diff --git a/crates/project/src/debugger/locators/go.rs b/crates/project/src/debugger/locators/go.rs index fe7b306e3bdd377b1a13c4597d3739ee72059888..6ed4649706c95c243c8eea45f52a888c16eafb0c 100644 --- a/crates/project/src/debugger/locators/go.rs +++ b/crates/project/src/debugger/locators/go.rs @@ -30,6 +30,47 @@ impl DapLocator for GoLocator { let go_action = build_config.args.first()?; match go_action.as_str() { + "test" => { + let binary_path = if build_config.env.contains_key("OUT_DIR") { + "${OUT_DIR}/__debug".to_string() + } else { + "__debug".to_string() + }; + + let build_task = TaskTemplate { + label: "go test debug".into(), + command: "go".into(), + args: vec![ + "test".into(), + "-c".into(), + "-gcflags \"all=-N -l\"".into(), + "-o".into(), + binary_path, + ], + env: build_config.env.clone(), + cwd: build_config.cwd.clone(), + use_new_terminal: false, + allow_concurrent_runs: false, + reveal: RevealStrategy::Always, + reveal_target: RevealTarget::Dock, + hide: task::HideStrategy::Never, + shell: Shell::System, + tags: vec![], + show_summary: true, + show_command: true, + }; + + Some(DebugScenario { + label: resolved_label.to_string().into(), + adapter: adapter.0, + build: Some(BuildTaskDefinition::Template { + task_template: build_task, + locator_name: Some(self.name()), + }), + config: serde_json::Value::Null, + tcp_connection: None, + }) + } "run" => { let program = build_config .args @@ -91,6 +132,23 @@ impl DapLocator for GoLocator { } match go_action.as_str() { + "test" => { + let program = if let Some(out_dir) = build_config.env.get("OUT_DIR") { + format!("{}/__debug", out_dir) + } else { + PathBuf::from(&cwd) + .join("__debug") + .to_string_lossy() + .to_string() + }; + + Ok(DebugRequest::Launch(task::LaunchRequest { + program, + cwd: Some(PathBuf::from(&cwd)), + args: vec!["-test.v".into(), "-test.run=${ZED_SYMBOL}".into()], + env, + })) + } "build" => { let package = build_config .args @@ -221,6 +279,92 @@ mod tests { assert!(scenario.is_none()); } + #[test] + fn test_create_scenario_for_go_test() { + let locator = GoLocator; + let task = TaskTemplate { + label: "go test".into(), + command: "go".into(), + args: vec!["test".into(), ".".into()], + env: Default::default(), + cwd: Some("${ZED_WORKTREE_ROOT}".into()), + use_new_terminal: false, + allow_concurrent_runs: false, + reveal: RevealStrategy::Always, + reveal_target: RevealTarget::Dock, + hide: HideStrategy::Never, + shell: Shell::System, + tags: vec![], + show_summary: true, + show_command: true, + }; + + let scenario = + locator.create_scenario(&task, "test label", DebugAdapterName("Delve".into())); + + assert!(scenario.is_some()); + let scenario = scenario.unwrap(); + assert_eq!(scenario.adapter, "Delve"); + assert_eq!(scenario.label, "test label"); + assert!(scenario.build.is_some()); + + if let Some(BuildTaskDefinition::Template { task_template, .. }) = &scenario.build { + assert_eq!(task_template.command, "go"); + assert!(task_template.args.contains(&"test".into())); + assert!(task_template.args.contains(&"-c".into())); + assert!( + task_template + .args + .contains(&"-gcflags \"all=-N -l\"".into()) + ); + assert!(task_template.args.contains(&"-o".into())); + assert!(task_template.args.contains(&"__debug".into())); + } else { + panic!("Expected BuildTaskDefinition::Template"); + } + + assert!( + scenario.config.is_null(), + "Initial config should be null to ensure it's invalid" + ); + } + + #[test] + fn test_create_scenario_for_go_test_with_out_dir() { + let locator = GoLocator; + let mut env = FxHashMap::default(); + env.insert("OUT_DIR".to_string(), "/tmp/build".to_string()); + + let task = TaskTemplate { + label: "go test".into(), + command: "go".into(), + args: vec!["test".into(), ".".into()], + env, + cwd: Some("${ZED_WORKTREE_ROOT}".into()), + use_new_terminal: false, + allow_concurrent_runs: false, + reveal: RevealStrategy::Always, + reveal_target: RevealTarget::Dock, + hide: HideStrategy::Never, + shell: Shell::System, + tags: vec![], + show_summary: true, + show_command: true, + }; + + let scenario = + locator.create_scenario(&task, "test label", DebugAdapterName("Delve".into())); + + assert!(scenario.is_some()); + let scenario = scenario.unwrap(); + + if let Some(BuildTaskDefinition::Template { task_template, .. }) = &scenario.build { + assert!(task_template.args.contains(&"${OUT_DIR}/__debug".into())); + } else { + panic!("Expected BuildTaskDefinition::Template"); + } + } + #[test] fn test_skip_unsupported_go_commands() { let locator = GoLocator;