Tidy up DAP initialization (#28730)

To make DAP work over SSH we want to create the binary
at the project level (so we can wrap it in an `ssh` invocation
transparently).

This means not pushing the adapter down into the session, and resolving
more information ahead-of-time.

Co-authored-by: Anthony Eid <hello@anthonyeid.me>
Co-authored-by: Piotr <piotr@zed.dev>

Release Notes:

- N/A

---------

Co-authored-by: Anthony Eid <hello@anthonyeid.me>
Co-authored-by: Piotr <piotr@zed.dev>
Co-authored-by: Piotr Osiewicz <24362066+osiewicz@users.noreply.github.com>
Co-authored-by: Anthony <anthony@zed.dev>
This commit is contained in:
Conrad Irwin 2025-04-15 09:11:29 -06:00 committed by GitHub
parent 6f0951ff77
commit aef78dcffd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 1319 additions and 1738 deletions

View file

@ -228,10 +228,7 @@ impl PickerDelegate for AttachModalDelegate {
let config = self.debug_config.clone();
self.project
.update(cx, |project, cx| {
#[cfg(any(test, feature = "test-support"))]
let ret = project.fake_debug_session(config.request, None, false, cx);
#[cfg(not(any(test, feature = "test-support")))]
let ret = project.start_debug_session(config.into(), cx);
let ret = project.start_debug_session(config, cx);
ret
})
.detach_and_log_err(cx);

View file

@ -146,7 +146,7 @@ impl NewSessionModal {
{
this.start_debug_session(debug_config, cx)
} else {
this.start_debug_session(config.into(), cx)
this.start_debug_session(config, cx)
}
})?;
let spawn_result = task.await;

View file

@ -26,18 +26,30 @@ async fn test_direct_attach_to_process(executor: BackgroundExecutor, cx: &mut Te
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Attach(AttachConfig {
let session = debugger::test::start_debug_session_with(
&project,
cx,
DebugTaskDefinition {
adapter: "fake-adapter".to_string(),
request: dap::DebugRequestType::Attach(AttachConfig {
process_id: Some(10),
}),
None,
false,
cx,
)
});
label: "label".to_string(),
initialize_args: None,
tcp_connection: None,
locator: None,
stop_on_entry: None,
},
|client| {
client.on_request::<dap::requests::Attach, _>(move |_, args| {
assert_eq!(json!({"request": "attach", "process_id": 10}), args.raw);
let session = task.await.unwrap();
Ok(())
});
},
)
.await
.unwrap();
cx.run_until_parked();
@ -77,7 +89,15 @@ async fn test_show_attach_modal_and_select_process(
let project = Project::test(fs, ["/project".as_ref()], cx).await;
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
// Set up handlers for sessions spawned via modal.
let _initialize_subscription =
project::debugger::test::intercept_debug_sessions(cx, |client| {
client.on_request::<dap::requests::Attach, _>(move |_, args| {
assert_eq!(json!({"request": "attach", "process_id": 1}), args.raw);
Ok(())
});
});
let attach_modal = workspace
.update(cx, |workspace, window, cx| {
workspace.toggle_modal(window, cx, |window, cx| {

View file

@ -3,7 +3,6 @@ use dap::requests::StackTrace;
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
use project::{FakeFs, Project};
use serde_json::json;
use task::LaunchConfig;
use tests::{init_test, init_test_workspace};
#[gpui::test]
@ -29,26 +28,17 @@ async fn test_handle_output_event(executor: BackgroundExecutor, cx: &mut TestApp
})
.unwrap();
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: Vec::default(),
total_frames: None,
})
client.on_request::<StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: Vec::default(),
total_frames: None,
})
.await;
});
client
.fake_event(dap::messages::Events::Output(dap::OutputEvent {

View file

@ -1,7 +1,7 @@
use crate::*;
use dap::{
ErrorResponse, RunInTerminalRequestArguments, SourceBreakpoint, StartDebuggingRequestArguments,
StartDebuggingRequestArgumentsRequest,
ErrorResponse, Message, RunInTerminalRequestArguments, SourceBreakpoint,
StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest,
client::SessionId,
requests::{
Continue, Disconnect, Launch, Next, RunInTerminal, SetBreakpoints, StackTrace,
@ -25,7 +25,6 @@ use std::{
atomic::{AtomicBool, Ordering},
},
};
use task::LaunchConfig;
use terminal_view::{TerminalView, terminal_panel::TerminalPanel};
use tests::{active_debug_session_panel, init_test, init_test_workspace};
use util::path;
@ -49,37 +48,26 @@ async fn test_basic_show_debug_panel(executor: BackgroundExecutor, cx: &mut Test
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client
.on_request::<StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: Vec::default(),
total_frames: None,
})
client.on_request::<StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: Vec::default(),
total_frames: None,
})
.await;
});
cx.run_until_parked();
@ -199,37 +187,26 @@ async fn test_we_can_only_have_one_panel_per_debug_session(
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client
.on_request::<StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: Vec::default(),
total_frames: None,
})
client.on_request::<StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: Vec::default(),
total_frames: None,
})
.await;
});
cx.run_until_parked();
@ -377,16 +354,9 @@ async fn test_handle_successful_run_in_terminal_reverse_request(
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
@ -474,16 +444,9 @@ async fn test_handle_error_run_in_terminal_reverse_request(
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
@ -559,28 +522,19 @@ async fn test_handle_start_debugging_reverse_request(
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client
.on_response::<StartDebugging, _>({
@ -593,7 +547,9 @@ async fn test_handle_start_debugging_reverse_request(
}
})
.await;
// Set up handlers for sessions spawned with reverse request too.
let _reverse_request_subscription =
project::debugger::test::intercept_debug_sessions(cx, |_| {});
client
.fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments {
configuration: json!({}),
@ -612,20 +568,16 @@ async fn test_handle_start_debugging_reverse_request(
});
let child_client = child_session.update(cx, |session, _| session.adapter_client().unwrap());
child_client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
child_client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
child_client
.on_request::<Disconnect, _>(move |_, _| Ok(()))
.await;
child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
child_client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@ -677,31 +629,24 @@ async fn test_shutdown_children_when_parent_session_shutdown(
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let parent_session = task.await.unwrap();
let parent_session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = parent_session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client.on_response::<StartDebugging, _>(move |_| {}).await;
// Set up handlers for sessions spawned with reverse request too.
let _reverse_request_subscription =
project::debugger::test::intercept_debug_sessions(cx, |_| {});
// start first child session
client
.fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments {
@ -729,9 +674,7 @@ async fn test_shutdown_children_when_parent_session_shutdown(
let first_child_client =
first_child_session.update(cx, |session, _| session.adapter_client().unwrap());
first_child_client
.on_request::<Disconnect, _>(move |_, _| Ok(()))
.await;
first_child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
// configure second child session
let second_child_session = dap_store.read_with(cx, |dap_store, _| {
@ -740,9 +683,7 @@ async fn test_shutdown_children_when_parent_session_shutdown(
let second_child_client =
second_child_session.update(cx, |session, _| session.adapter_client().unwrap());
second_child_client
.on_request::<Disconnect, _>(move |_, _| Ok(()))
.await;
second_child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
cx.run_until_parked();
@ -796,20 +737,15 @@ async fn test_shutdown_parent_session_if_all_children_are_shutdown(
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let parent_session = task.await.unwrap();
let parent_session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = parent_session.update(cx, |session, _| session.adapter_client().unwrap());
client.on_response::<StartDebugging, _>(move |_| {}).await;
// Set up handlers for sessions spawned with reverse request too.
let _reverse_request_subscription =
project::debugger::test::intercept_debug_sessions(cx, |_| {});
// start first child session
client
.fake_reverse_request::<StartDebugging>(StartDebuggingRequestArguments {
@ -837,9 +773,7 @@ async fn test_shutdown_parent_session_if_all_children_are_shutdown(
let first_child_client =
first_child_session.update(cx, |session, _| session.adapter_client().unwrap());
first_child_client
.on_request::<Disconnect, _>(move |_, _| Ok(()))
.await;
first_child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
// configure second child session
let second_child_session = dap_store.read_with(cx, |dap_store, _| {
@ -848,9 +782,7 @@ async fn test_shutdown_parent_session_if_all_children_are_shutdown(
let second_child_client =
second_child_session.update(cx, |session, _| session.adapter_client().unwrap());
second_child_client
.on_request::<Disconnect, _>(move |_, _| Ok(()))
.await;
second_child_client.on_request::<Disconnect, _>(move |_, _| Ok(()));
cx.run_until_parked();
@ -926,123 +858,107 @@ async fn test_debug_panel_item_thread_status_reset_on_failure(
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
Some(dap::Capabilities {
let session = debugger::test::start_debug_session(&project, cx, |client| {
client.on_request::<dap::requests::Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(true),
..Default::default()
}),
false,
cx,
)
});
})
});
})
.await
.unwrap();
let session = task.await.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
const THREAD_ID_NUM: u64 = 1;
client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: THREAD_ID_NUM,
name: "Thread 1".into(),
}],
})
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: THREAD_ID_NUM,
name: "Thread 1".into(),
}],
})
.await;
});
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
client.on_request::<Launch, _>(move |_, _| Ok(()));
client
.on_request::<StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: Vec::default(),
total_frames: None,
})
client.on_request::<StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: Vec::default(),
total_frames: None,
})
.await;
});
client
.on_request::<Next, _>(move |_, _| {
Err(ErrorResponse {
error: Some(dap::Message {
id: 1,
format: "error".into(),
variables: None,
send_telemetry: None,
show_user: None,
url: None,
url_label: None,
}),
})
client.on_request::<Next, _>(move |_, _| {
Err(ErrorResponse {
error: Some(dap::Message {
id: 1,
format: "error".into(),
variables: None,
send_telemetry: None,
show_user: None,
url: None,
url_label: None,
}),
})
.await;
});
client
.on_request::<StepOut, _>(move |_, _| {
Err(ErrorResponse {
error: Some(dap::Message {
id: 1,
format: "error".into(),
variables: None,
send_telemetry: None,
show_user: None,
url: None,
url_label: None,
}),
})
client.on_request::<StepOut, _>(move |_, _| {
Err(ErrorResponse {
error: Some(dap::Message {
id: 1,
format: "error".into(),
variables: None,
send_telemetry: None,
show_user: None,
url: None,
url_label: None,
}),
})
.await;
});
client
.on_request::<StepIn, _>(move |_, _| {
Err(ErrorResponse {
error: Some(dap::Message {
id: 1,
format: "error".into(),
variables: None,
send_telemetry: None,
show_user: None,
url: None,
url_label: None,
}),
})
client.on_request::<StepIn, _>(move |_, _| {
Err(ErrorResponse {
error: Some(dap::Message {
id: 1,
format: "error".into(),
variables: None,
send_telemetry: None,
show_user: None,
url: None,
url_label: None,
}),
})
.await;
});
client
.on_request::<StepBack, _>(move |_, _| {
Err(ErrorResponse {
error: Some(dap::Message {
id: 1,
format: "error".into(),
variables: None,
send_telemetry: None,
show_user: None,
url: None,
url_label: None,
}),
})
client.on_request::<StepBack, _>(move |_, _| {
Err(ErrorResponse {
error: Some(dap::Message {
id: 1,
format: "error".into(),
variables: None,
send_telemetry: None,
show_user: None,
url: None,
url_label: None,
}),
})
.await;
});
client
.on_request::<Continue, _>(move |_, _| {
Err(ErrorResponse {
error: Some(dap::Message {
id: 1,
format: "error".into(),
variables: None,
send_telemetry: None,
show_user: None,
url: None,
url_label: None,
}),
})
client.on_request::<Continue, _>(move |_, _| {
Err(ErrorResponse {
error: Some(dap::Message {
id: 1,
format: "error".into(),
variables: None,
send_telemetry: None,
show_user: None,
url: None,
url_label: None,
}),
})
.await;
});
client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@ -1157,16 +1073,9 @@ async fn test_send_breakpoints_when_editor_has_been_saved(
.update(cx, |_, _, cx| worktree.read(cx).id())
.unwrap();
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
let buffer = project
@ -1186,16 +1095,14 @@ async fn test_send_breakpoints_when_editor_has_been_saved(
)
});
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
client.on_request::<Launch, _>(move |_, _| Ok(()));
client
.on_request::<StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: Vec::default(),
total_frames: None,
})
client.on_request::<StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: Vec::default(),
total_frames: None,
})
.await;
});
client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@ -1210,32 +1117,30 @@ async fn test_send_breakpoints_when_editor_has_been_saved(
.await;
let called_set_breakpoints = Arc::new(AtomicBool::new(false));
client
.on_request::<SetBreakpoints, _>({
let called_set_breakpoints = called_set_breakpoints.clone();
move |_, args| {
assert_eq!(path!("/project/main.rs"), args.source.path.unwrap());
assert_eq!(
vec![SourceBreakpoint {
line: 2,
column: None,
condition: None,
hit_condition: None,
log_message: None,
mode: None
}],
args.breakpoints.unwrap()
);
assert!(!args.source_modified.unwrap());
client.on_request::<SetBreakpoints, _>({
let called_set_breakpoints = called_set_breakpoints.clone();
move |_, args| {
assert_eq!(path!("/project/main.rs"), args.source.path.unwrap());
assert_eq!(
vec![SourceBreakpoint {
line: 2,
column: None,
condition: None,
hit_condition: None,
log_message: None,
mode: None
}],
args.breakpoints.unwrap()
);
assert!(!args.source_modified.unwrap());
called_set_breakpoints.store(true, Ordering::SeqCst);
called_set_breakpoints.store(true, Ordering::SeqCst);
Ok(dap::SetBreakpointsResponse {
breakpoints: Vec::default(),
})
}
})
.await;
Ok(dap::SetBreakpointsResponse {
breakpoints: Vec::default(),
})
}
});
editor.update_in(cx, |editor, window, cx| {
editor.move_down(&actions::MoveDown, window, cx);
@ -1250,32 +1155,30 @@ async fn test_send_breakpoints_when_editor_has_been_saved(
);
let called_set_breakpoints = Arc::new(AtomicBool::new(false));
client
.on_request::<SetBreakpoints, _>({
let called_set_breakpoints = called_set_breakpoints.clone();
move |_, args| {
assert_eq!(path!("/project/main.rs"), args.source.path.unwrap());
assert_eq!(
vec![SourceBreakpoint {
line: 3,
column: None,
condition: None,
hit_condition: None,
log_message: None,
mode: None
}],
args.breakpoints.unwrap()
);
assert!(args.source_modified.unwrap());
client.on_request::<SetBreakpoints, _>({
let called_set_breakpoints = called_set_breakpoints.clone();
move |_, args| {
assert_eq!(path!("/project/main.rs"), args.source.path.unwrap());
assert_eq!(
vec![SourceBreakpoint {
line: 3,
column: None,
condition: None,
hit_condition: None,
log_message: None,
mode: None
}],
args.breakpoints.unwrap()
);
assert!(args.source_modified.unwrap());
called_set_breakpoints.store(true, Ordering::SeqCst);
called_set_breakpoints.store(true, Ordering::SeqCst);
Ok(dap::SetBreakpointsResponse {
breakpoints: Vec::default(),
})
}
})
.await;
Ok(dap::SetBreakpointsResponse {
breakpoints: Vec::default(),
})
}
});
editor.update_in(cx, |editor, window, cx| {
editor.move_up(&actions::MoveUp, window, cx);
@ -1387,49 +1290,40 @@ async fn test_unsetting_breakpoints_on_clear_breakpoint_action(
editor.toggle_breakpoint(&actions::ToggleBreakpoint, window, cx);
});
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
let called_set_breakpoints = Arc::new(AtomicBool::new(false));
client
.on_request::<SetBreakpoints, _>({
let called_set_breakpoints = called_set_breakpoints.clone();
move |_, args| {
assert!(
args.breakpoints.is_none_or(|bps| bps.is_empty()),
"Send empty breakpoint sets to clear them from DAP servers"
);
client.on_request::<SetBreakpoints, _>({
let called_set_breakpoints = called_set_breakpoints.clone();
move |_, args| {
assert!(
args.breakpoints.is_none_or(|bps| bps.is_empty()),
"Send empty breakpoint sets to clear them from DAP servers"
);
match args
.source
.path
.expect("We should always send a breakpoint's path")
.as_str()
{
"/project/main.rs" | "/project/second.rs" => {}
_ => {
panic!("Unset breakpoints for path that doesn't have any")
}
match args
.source
.path
.expect("We should always send a breakpoint's path")
.as_str()
{
"/project/main.rs" | "/project/second.rs" => {}
_ => {
panic!("Unset breakpoints for path that doesn't have any")
}
called_set_breakpoints.store(true, Ordering::SeqCst);
Ok(dap::SetBreakpointsResponse {
breakpoints: Vec::default(),
})
}
})
.await;
called_set_breakpoints.store(true, Ordering::SeqCst);
Ok(dap::SetBreakpointsResponse {
breakpoints: Vec::default(),
})
}
});
cx.dispatch_action(crate::ClearAllBreakpoints);
cx.run_until_parked();
@ -1464,13 +1358,20 @@ async fn test_debug_session_is_shutdown_when_attach_and_launch_request_fails(
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
true,
cx,
)
let task = project::debugger::test::start_debug_session(&project, cx, |client| {
client.on_request::<dap::requests::Initialize, _>(|_, _| {
Err(ErrorResponse {
error: Some(Message {
format: "failed to launch".to_string(),
id: 1,
variables: None,
send_telemetry: None,
show_user: None,
url: None,
url_label: None,
}),
})
});
});
assert!(

View file

@ -4,15 +4,17 @@ use crate::{
};
use dap::{
StoppedEvent,
requests::{Modules, StackTrace, Threads},
requests::{Initialize, Modules},
};
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
use project::{FakeFs, Project};
use project::{
FakeFs, Project,
debugger::{self},
};
use std::sync::{
Arc,
atomic::{AtomicBool, AtomicI32, Ordering},
};
use task::LaunchConfig;
#[gpui::test]
async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext) {
@ -29,30 +31,18 @@ async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext)
.unwrap();
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
Some(dap::Capabilities {
let session = debugger::test::start_debug_session(&project, cx, |client| {
client.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_modules_request: Some(true),
..Default::default()
}),
false,
cx,
)
});
let session = task.await.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<StackTrace, _>(move |_, args| {
assert!(args.thread_id == 1);
Ok(dap::StackTraceResponse {
stack_frames: Vec::default(),
total_frames: None,
})
})
.await;
});
})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
let called_modules = Arc::new(AtomicBool::new(false));
let modules = vec![
@ -82,38 +72,25 @@ async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext)
},
];
client
.on_request::<Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
client.on_request::<Modules, _>({
let called_modules = called_modules.clone();
let modules_request_count = AtomicI32::new(0);
let modules = modules.clone();
move |_, _| {
modules_request_count.fetch_add(1, Ordering::SeqCst);
assert_eq!(
1,
modules_request_count.load(Ordering::SeqCst),
"This request should only be called once from the host"
);
called_modules.store(true, Ordering::SeqCst);
Ok(dap::ModulesResponse {
modules: modules.clone(),
total_modules: Some(2u64),
})
})
.await;
client
.on_request::<Modules, _>({
let called_modules = called_modules.clone();
let modules_request_count = AtomicI32::new(0);
let modules = modules.clone();
move |_, _| {
modules_request_count.fetch_add(1, Ordering::SeqCst);
assert_eq!(
1,
modules_request_count.load(Ordering::SeqCst),
"This request should only be called once from the host"
);
called_modules.store(true, Ordering::SeqCst);
Ok(dap::ModulesResponse {
modules: modules.clone(),
total_modules: Some(2u64),
})
}
})
.await;
}
});
client
.fake_event(dap::messages::Events::Stopped(StoppedEvent {

View file

@ -5,14 +5,13 @@ use crate::{
};
use dap::{
StackFrame,
requests::{StackTrace, Threads},
requests::{Scopes, StackTrace, Threads},
};
use editor::{Editor, ToPoint as _};
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
use project::{FakeFs, Project};
use project::{FakeFs, Project, debugger};
use serde_json::json;
use std::sync::Arc;
use task::LaunchConfig;
use unindent::Unindent as _;
use util::path;
@ -51,29 +50,20 @@ async fn test_fetch_initial_stack_frames_and_go_to_stack_frame(
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client.on_request::<Scopes, _>(move |_, _| Ok(dap::ScopesResponse { scopes: vec![] }));
client
.on_request::<Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
let stack_frames = vec![
StackFrame {
@ -122,19 +112,17 @@ async fn test_fetch_initial_stack_frames_and_go_to_stack_frame(
},
];
client
.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
client.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
})
.await;
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
});
client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@ -241,29 +229,21 @@ async fn test_select_stack_frame(executor: BackgroundExecutor, cx: &mut TestAppC
});
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client.on_request::<Scopes, _>(move |_, _| Ok(dap::ScopesResponse { scopes: vec![] }));
let stack_frames = vec![
StackFrame {
@ -312,19 +292,17 @@ async fn test_select_stack_frame(executor: BackgroundExecutor, cx: &mut TestAppC
},
];
client
.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
client.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
})
.await;
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
});
client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@ -517,28 +495,21 @@ async fn test_collapsed_entries(executor: BackgroundExecutor, cx: &mut TestAppCo
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client.on_request::<Scopes, _>(move |_, _| Ok(dap::ScopesResponse { scopes: vec![] }));
let stack_frames = vec![
StackFrame {
@ -697,19 +668,17 @@ async fn test_collapsed_entries(executor: BackgroundExecutor, cx: &mut TestAppCo
},
];
client
.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
client.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
})
.await;
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
});
client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {

View file

@ -15,9 +15,8 @@ use dap::{
};
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
use menu::{SelectFirst, SelectNext, SelectPrevious};
use project::{FakeFs, Project};
use project::{FakeFs, Project, debugger};
use serde_json::json;
use task::LaunchConfig;
use unindent::Unindent as _;
use util::path;
@ -55,29 +54,19 @@ async fn test_basic_fetch_initial_scope_and_variables(
})
.unwrap();
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
let stack_frames = vec![StackFrame {
id: 1,
@ -102,19 +91,17 @@ async fn test_basic_fetch_initial_scope_and_variables(
presentation_hint: None,
}];
client
.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
client.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
})
.await;
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
});
let scopes = vec![Scope {
name: "Scope 1".into(),
@ -130,18 +117,16 @@ async fn test_basic_fetch_initial_scope_and_variables(
end_column: None,
}];
client
.on_request::<Scopes, _>({
let scopes = Arc::new(scopes.clone());
move |_, args| {
assert_eq!(1, args.frame_id);
client.on_request::<Scopes, _>({
let scopes = Arc::new(scopes.clone());
move |_, args| {
assert_eq!(1, args.frame_id);
Ok(dap::ScopesResponse {
scopes: (*scopes).clone(),
})
}
})
.await;
Ok(dap::ScopesResponse {
scopes: (*scopes).clone(),
})
}
});
let variables = vec![
Variable {
@ -172,18 +157,16 @@ async fn test_basic_fetch_initial_scope_and_variables(
},
];
client
.on_request::<Variables, _>({
let variables = Arc::new(variables.clone());
move |_, args| {
assert_eq!(2, args.variables_reference);
client.on_request::<Variables, _>({
let variables = Arc::new(variables.clone());
move |_, args| {
assert_eq!(2, args.variables_reference);
Ok(dap::VariablesResponse {
variables: (*variables).clone(),
})
}
})
.await;
Ok(dap::VariablesResponse {
variables: (*variables).clone(),
})
}
});
client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@ -283,39 +266,28 @@ async fn test_fetch_variables_for_multiple_scopes(
.unwrap();
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client
.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
client.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
.await;
});
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
client.on_request::<Launch, _>(move |_, _| Ok(()));
let stack_frames = vec![StackFrame {
id: 1,
@ -340,19 +312,17 @@ async fn test_fetch_variables_for_multiple_scopes(
presentation_hint: None,
}];
client
.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
client.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
})
.await;
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
});
let scopes = vec![
Scope {
@ -383,18 +353,16 @@ async fn test_fetch_variables_for_multiple_scopes(
},
];
client
.on_request::<Scopes, _>({
let scopes = Arc::new(scopes.clone());
move |_, args| {
assert_eq!(1, args.frame_id);
client.on_request::<Scopes, _>({
let scopes = Arc::new(scopes.clone());
move |_, args| {
assert_eq!(1, args.frame_id);
Ok(dap::ScopesResponse {
scopes: (*scopes).clone(),
})
}
})
.await;
Ok(dap::ScopesResponse {
scopes: (*scopes).clone(),
})
}
});
let mut variables = HashMap::default();
variables.insert(
@ -445,16 +413,14 @@ async fn test_fetch_variables_for_multiple_scopes(
}],
);
client
.on_request::<Variables, _>({
let variables = Arc::new(variables.clone());
move |_, args| {
Ok(dap::VariablesResponse {
variables: variables.get(&args.variables_reference).unwrap().clone(),
})
}
})
.await;
client.on_request::<Variables, _>({
let variables = Arc::new(variables.clone());
move |_, args| {
Ok(dap::VariablesResponse {
variables: variables.get(&args.variables_reference).unwrap().clone(),
})
}
});
client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@ -562,40 +528,28 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
})
.unwrap();
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client
.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
client.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
.await;
});
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
client.on_request::<Launch, _>(move |_, _| Ok(()));
let stack_frames = vec![StackFrame {
id: 1,
@ -620,19 +574,17 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
presentation_hint: None,
}];
client
.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
client.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
})
.await;
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
});
let scopes = vec![
Scope {
@ -663,18 +615,16 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
},
];
client
.on_request::<Scopes, _>({
let scopes = Arc::new(scopes.clone());
move |_, args| {
assert_eq!(1, args.frame_id);
client.on_request::<Scopes, _>({
let scopes = Arc::new(scopes.clone());
move |_, args| {
assert_eq!(1, args.frame_id);
Ok(dap::ScopesResponse {
scopes: (*scopes).clone(),
})
}
})
.await;
Ok(dap::ScopesResponse {
scopes: (*scopes).clone(),
})
}
});
let scope1_variables = vec![
Variable {
@ -748,25 +698,23 @@ async fn test_keyboard_navigation(executor: BackgroundExecutor, cx: &mut TestApp
value_location_reference: None,
}];
client
.on_request::<Variables, _>({
let scope1_variables = Arc::new(scope1_variables.clone());
let nested_variables = Arc::new(nested_variables.clone());
let scope2_variables = Arc::new(scope2_variables.clone());
move |_, args| match args.variables_reference {
4 => Ok(dap::VariablesResponse {
variables: (*scope2_variables).clone(),
}),
3 => Ok(dap::VariablesResponse {
variables: (*nested_variables).clone(),
}),
2 => Ok(dap::VariablesResponse {
variables: (*scope1_variables).clone(),
}),
id => unreachable!("unexpected variables reference {id}"),
}
})
.await;
client.on_request::<Variables, _>({
let scope1_variables = Arc::new(scope1_variables.clone());
let nested_variables = Arc::new(nested_variables.clone());
let scope2_variables = Arc::new(scope2_variables.clone());
move |_, args| match args.variables_reference {
4 => Ok(dap::VariablesResponse {
variables: (*scope2_variables).clone(),
}),
3 => Ok(dap::VariablesResponse {
variables: (*nested_variables).clone(),
}),
2 => Ok(dap::VariablesResponse {
variables: (*scope1_variables).clone(),
}),
id => unreachable!("unexpected variables reference {id}"),
}
});
client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@ -1365,39 +1313,28 @@ async fn test_variable_list_only_sends_requests_when_rendering(
let workspace = init_test_workspace(&project, cx).await;
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client
.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
client.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
.await;
});
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
client.on_request::<Launch, _>(move |_, _| Ok(()));
let stack_frames = vec![
StackFrame {
@ -1446,19 +1383,17 @@ async fn test_variable_list_only_sends_requests_when_rendering(
},
];
client
.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
client.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
})
.await;
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
});
let frame_1_scopes = vec![Scope {
name: "Frame 1 Scope 1".into(),
@ -1476,25 +1411,23 @@ async fn test_variable_list_only_sends_requests_when_rendering(
let made_scopes_request = Arc::new(AtomicBool::new(false));
client
.on_request::<Scopes, _>({
let frame_1_scopes = Arc::new(frame_1_scopes.clone());
let made_scopes_request = made_scopes_request.clone();
move |_, args| {
assert_eq!(1, args.frame_id);
assert!(
!made_scopes_request.load(Ordering::SeqCst),
"We should be caching the scope request"
);
client.on_request::<Scopes, _>({
let frame_1_scopes = Arc::new(frame_1_scopes.clone());
let made_scopes_request = made_scopes_request.clone();
move |_, args| {
assert_eq!(1, args.frame_id);
assert!(
!made_scopes_request.load(Ordering::SeqCst),
"We should be caching the scope request"
);
made_scopes_request.store(true, Ordering::SeqCst);
made_scopes_request.store(true, Ordering::SeqCst);
Ok(dap::ScopesResponse {
scopes: (*frame_1_scopes).clone(),
})
}
})
.await;
Ok(dap::ScopesResponse {
scopes: (*frame_1_scopes).clone(),
})
}
});
let frame_1_variables = vec![
Variable {
@ -1525,18 +1458,16 @@ async fn test_variable_list_only_sends_requests_when_rendering(
},
];
client
.on_request::<Variables, _>({
let frame_1_variables = Arc::new(frame_1_variables.clone());
move |_, args| {
assert_eq!(2, args.variables_reference);
client.on_request::<Variables, _>({
let frame_1_variables = Arc::new(frame_1_variables.clone());
move |_, args| {
assert_eq!(2, args.variables_reference);
Ok(dap::VariablesResponse {
variables: (*frame_1_variables).clone(),
})
}
})
.await;
Ok(dap::VariablesResponse {
variables: (*frame_1_variables).clone(),
})
}
});
cx.run_until_parked();
@ -1629,39 +1560,28 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
.unwrap();
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let task = project.update(cx, |project, cx| {
project.fake_debug_session(
dap::DebugRequestType::Launch(LaunchConfig::default()),
None,
false,
cx,
)
});
let session = task.await.unwrap();
let session = debugger::test::start_debug_session(&project, cx, |_| {})
.await
.unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client
.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
.await;
});
client
.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
client.on_request::<Initialize, _>(move |_, _| {
Ok(dap::Capabilities {
supports_step_back: Some(false),
..Default::default()
})
.await;
});
client.on_request::<Launch, _>(move |_, _| Ok(())).await;
client.on_request::<Launch, _>(move |_, _| Ok(()));
let stack_frames = vec![
StackFrame {
@ -1710,19 +1630,17 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
},
];
client
.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
client.on_request::<StackTrace, _>({
let stack_frames = Arc::new(stack_frames.clone());
move |_, args| {
assert_eq!(1, args.thread_id);
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
})
.await;
Ok(dap::StackTraceResponse {
stack_frames: (*stack_frames).clone(),
total_frames: None,
})
}
});
let frame_1_scopes = vec![Scope {
name: "Frame 1 Scope 1".into(),
@ -1757,30 +1675,28 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
let called_second_stack_frame = Arc::new(AtomicBool::new(false));
let called_first_stack_frame = Arc::new(AtomicBool::new(false));
client
.on_request::<Scopes, _>({
let frame_1_scopes = Arc::new(frame_1_scopes.clone());
let frame_2_scopes = Arc::new(frame_2_scopes.clone());
let called_first_stack_frame = called_first_stack_frame.clone();
let called_second_stack_frame = called_second_stack_frame.clone();
move |_, args| match args.frame_id {
1 => {
called_first_stack_frame.store(true, Ordering::SeqCst);
Ok(dap::ScopesResponse {
scopes: (*frame_1_scopes).clone(),
})
}
2 => {
called_second_stack_frame.store(true, Ordering::SeqCst);
Ok(dap::ScopesResponse {
scopes: (*frame_2_scopes).clone(),
})
}
_ => panic!("Made a scopes request with an invalid frame id"),
client.on_request::<Scopes, _>({
let frame_1_scopes = Arc::new(frame_1_scopes.clone());
let frame_2_scopes = Arc::new(frame_2_scopes.clone());
let called_first_stack_frame = called_first_stack_frame.clone();
let called_second_stack_frame = called_second_stack_frame.clone();
move |_, args| match args.frame_id {
1 => {
called_first_stack_frame.store(true, Ordering::SeqCst);
Ok(dap::ScopesResponse {
scopes: (*frame_1_scopes).clone(),
})
}
})
.await;
2 => {
called_second_stack_frame.store(true, Ordering::SeqCst);
Ok(dap::ScopesResponse {
scopes: (*frame_2_scopes).clone(),
})
}
_ => panic!("Made a scopes request with an invalid frame id"),
}
});
let frame_1_variables = vec![
Variable {
@ -1840,18 +1756,16 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
},
];
client
.on_request::<Variables, _>({
let frame_1_variables = Arc::new(frame_1_variables.clone());
move |_, args| {
assert_eq!(2, args.variables_reference);
client.on_request::<Variables, _>({
let frame_1_variables = Arc::new(frame_1_variables.clone());
move |_, args| {
assert_eq!(2, args.variables_reference);
Ok(dap::VariablesResponse {
variables: (*frame_1_variables).clone(),
})
}
})
.await;
Ok(dap::VariablesResponse {
variables: (*frame_1_variables).clone(),
})
}
});
client
.fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
@ -1907,18 +1821,16 @@ async fn test_it_fetches_scopes_variables_when_you_select_a_stack_frame(
assert_eq!(frame_1_variables, variables);
});
client
.on_request::<Variables, _>({
let frame_2_variables = Arc::new(frame_2_variables.clone());
move |_, args| {
assert_eq!(3, args.variables_reference);
client.on_request::<Variables, _>({
let frame_2_variables = Arc::new(frame_2_variables.clone());
move |_, args| {
assert_eq!(3, args.variables_reference);
Ok(dap::VariablesResponse {
variables: (*frame_2_variables).clone(),
})
}
})
.await;
Ok(dap::VariablesResponse {
variables: (*frame_2_variables).clone(),
})
}
});
running_state
.update_in(cx, |running_state, window, cx| {