debugger: Fix bug where args from debug config weren't sent to adapters (#29445)

Anthony Eid created

I added some tests to ensure that this regression doesn't happen again.
This also fixes the cargo test locators, debugging all tests in a module
instead of just the singular test a user selects.

Release Notes:

- N/A

Change summary

crates/dap/src/adapters.rs                     |  5 +
crates/debugger_ui/src/tests/attach_modal.rs   |  8 +
crates/debugger_ui/src/tests/debugger_panel.rs | 78 +++++++++++++++++++
3 files changed, 88 insertions(+), 3 deletions(-)

Detailed changes

crates/dap/src/adapters.rs 🔗

@@ -121,6 +121,10 @@ impl TcpArguments {
 /// an optional build step is completed, we turn it's result into a DebugTaskDefinition by running a locator (or using a user-provided task) and resolving task variables.
 /// Finally, a [DebugTaskDefinition] has to be turned into a concrete debugger invocation ([DebugAdapterBinary]).
 #[derive(Clone, Debug, PartialEq)]
+#[cfg_attr(
+    any(feature = "test-support", test),
+    derive(serde::Deserialize, serde::Serialize)
+)]
 pub struct DebugTaskDefinition {
     pub label: SharedString,
     pub adapter: SharedString,
@@ -524,6 +528,7 @@ impl FakeAdapter {
             } else {
                 None
             },
+            "raw_request": serde_json::to_value(config).unwrap()
         });
         let request = match config.request {
             DebugRequest::Launch(_) => dap_types::StartDebuggingRequestArgumentsRequest::Launch,

crates/debugger_ui/src/tests/attach_modal.rs 🔗

@@ -41,7 +41,9 @@ async fn test_direct_attach_to_process(executor: BackgroundExecutor, cx: &mut Te
         },
         |client| {
             client.on_request::<dap::requests::Attach, _>(move |_, args| {
-                assert_eq!(json!({"request": "attach", "process_id": 10}), args.raw);
+                let raw = &args.raw;
+                assert_eq!(raw["request"], "attach");
+                assert_eq!(raw["process_id"], 10);
 
                 Ok(())
             });
@@ -91,7 +93,9 @@ async fn test_show_attach_modal_and_select_process(
     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);
+                let raw = &args.raw;
+                assert_eq!(raw["request"], "attach");
+                assert_eq!(raw["process_id"], 1);
 
                 Ok(())
             });

crates/debugger_ui/src/tests/debugger_panel.rs 🔗

@@ -1,7 +1,12 @@
-use crate::{persistence::DebuggerPaneItem, tests::start_debug_session, *};
+use crate::{
+    persistence::DebuggerPaneItem,
+    tests::{start_debug_session, start_debug_session_with},
+    *,
+};
 use dap::{
     ErrorResponse, Message, RunInTerminalRequestArguments, SourceBreakpoint,
     StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest,
+    adapters::DebugTaskDefinition,
     client::SessionId,
     requests::{
         Continue, Disconnect, Launch, Next, RunInTerminal, SetBreakpoints, StackTrace,
@@ -19,12 +24,14 @@ use project::{
 };
 use serde_json::json;
 use std::{
+    collections::HashMap,
     path::Path,
     sync::{
         Arc,
         atomic::{AtomicBool, Ordering},
     },
 };
+use task::LaunchRequest;
 use terminal_view::terminal_panel::TerminalPanel;
 use tests::{active_debug_session_panel, init_test, init_test_workspace};
 use util::path;
@@ -1384,3 +1391,72 @@ async fn test_debug_session_is_shutdown_when_attach_and_launch_request_fails(
         );
     });
 }
+
+#[gpui::test]
+async fn test_we_send_arguments_from_user_config(
+    executor: BackgroundExecutor,
+    cx: &mut TestAppContext,
+) {
+    init_test(cx);
+
+    let fs = FakeFs::new(executor.clone());
+
+    fs.insert_tree(
+        "/project",
+        json!({
+            "main.rs": "First line\nSecond line\nThird line\nFourth line",
+        }),
+    )
+    .await;
+
+    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);
+    let debug_definition = DebugTaskDefinition {
+        adapter: "fake-adapter".into(),
+        request: dap::DebugRequest::Launch(LaunchRequest {
+            program: "main.rs".to_owned(),
+            args: vec!["arg1".to_owned(), "arg2".to_owned()],
+            cwd: Some("/Random_path".into()),
+            env: HashMap::from_iter(vec![("KEY".to_owned(), "VALUE".to_owned())]),
+        }),
+        label: "test".into(),
+        initialize_args: None,
+        tcp_connection: None,
+        stop_on_entry: None,
+    };
+
+    let launch_handler_called = Arc::new(AtomicBool::new(false));
+
+    start_debug_session_with(&workspace, cx, debug_definition.clone(), {
+        let debug_definition = debug_definition.clone();
+        let launch_handler_called = launch_handler_called.clone();
+
+        move |client| {
+            let debug_definition = debug_definition.clone();
+            let launch_handler_called = launch_handler_called.clone();
+
+            client.on_request::<dap::requests::Launch, _>(move |_, args| {
+                launch_handler_called.store(true, Ordering::SeqCst);
+
+                let obj = args.raw.as_object().unwrap();
+                let sent_definition = serde_json::from_value::<DebugTaskDefinition>(
+                    obj.get(&"raw_request".to_owned()).unwrap().clone(),
+                )
+                .unwrap();
+
+                assert_eq!(sent_definition, debug_definition);
+
+                Ok(())
+            });
+        }
+    })
+    .ok();
+
+    cx.run_until_parked();
+
+    assert!(
+        launch_handler_called.load(Ordering::SeqCst),
+        "Launch request handler was not called"
+    );
+}