mirror of
https://github.com/zed-industries/zed.git
synced 2026-08-26 17:42:21 +00:00
The `go-subtest` task template wrapped the `-run` arg in single quotes for shell safety. This works for Run Test (terminal strips quotes), but Debug Test sends the arg through Delve’s DAP protocol with no shell involved, so the literal quote characters ended up in the regex and prevented any match. All other Go task templates (`go-test`, `go-testify-suite`, `go-table-test-case`) use the backslash-escaped format which `GoLocator` already knows how to handle. Align the `go-subtest` template to the same format. Self-Review Checklist: - [x] I've reviewed my own diff for quality, security, and reliability - [ ] Unsafe blocks (if any) have justifying comments - [ ] The content is consistent with the [UI/UX checklist](https://github.com/zed-industries/zed/blob/main/CONTRIBUTING.md#uiux-checklist) - [x] Tests cover the new/changed behavior - [x] Performance impact has been considered and is acceptable Closes #53230. Release Notes: - Fixed Debug Test for Go subtests --------- Co-authored-by: Smit Barmase <heysmitbarmase@gmail.com>
339 lines
11 KiB
Rust
339 lines
11 KiB
Rust
mod go_locator {
|
|
use collections::HashMap;
|
|
use dap::{DapLocator, adapters::DebugAdapterName};
|
|
use gpui::TestAppContext;
|
|
use project::debugger::locators::go::{DelveLaunchRequest, GoLocator};
|
|
use task::{HideStrategy, RevealStrategy, RevealTarget, SaveStrategy, Shell, TaskTemplate};
|
|
#[gpui::test]
|
|
async fn test_create_scenario_for_go_build(_: &mut TestAppContext) {
|
|
let locator = GoLocator;
|
|
let task = TaskTemplate {
|
|
label: "go build".into(),
|
|
command: "go".into(),
|
|
args: vec!["build".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,
|
|
save: SaveStrategy::default(),
|
|
hooks: Default::default(),
|
|
};
|
|
|
|
let scenario = locator
|
|
.create_scenario(&task, "test label", &DebugAdapterName("Delve".into()))
|
|
.await;
|
|
|
|
assert!(scenario.is_none());
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_skip_non_go_commands_with_non_delve_adapter(_: &mut TestAppContext) {
|
|
let locator = GoLocator;
|
|
let task = TaskTemplate {
|
|
label: "cargo build".into(),
|
|
command: "cargo".into(),
|
|
args: vec!["build".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,
|
|
save: SaveStrategy::default(),
|
|
hooks: Default::default(),
|
|
};
|
|
|
|
let scenario = locator
|
|
.create_scenario(
|
|
&task,
|
|
"test label",
|
|
&DebugAdapterName("SomeOtherAdapter".into()),
|
|
)
|
|
.await;
|
|
assert!(scenario.is_none());
|
|
|
|
let scenario = locator
|
|
.create_scenario(&task, "test label", &DebugAdapterName("Delve".into()))
|
|
.await;
|
|
assert!(scenario.is_none());
|
|
}
|
|
#[gpui::test]
|
|
async fn test_go_locator_run(_: &mut TestAppContext) {
|
|
let locator = GoLocator;
|
|
let delve = DebugAdapterName("Delve".into());
|
|
|
|
let task = TaskTemplate {
|
|
label: "go run with flags".into(),
|
|
command: "go".into(),
|
|
args: vec![
|
|
"run".to_string(),
|
|
"-race".to_string(),
|
|
"-ldflags".to_string(),
|
|
"-X main.version=1.0".to_string(),
|
|
"./cmd/myapp".to_string(),
|
|
"--config".to_string(),
|
|
"production.yaml".to_string(),
|
|
"--verbose".to_string(),
|
|
],
|
|
env: {
|
|
let mut env = HashMap::default();
|
|
env.insert("GO_ENV".to_string(), "production".to_string());
|
|
env
|
|
},
|
|
cwd: Some("/project/root".into()),
|
|
..Default::default()
|
|
};
|
|
|
|
let scenario = locator
|
|
.create_scenario(&task, "test run label", &delve)
|
|
.await
|
|
.unwrap();
|
|
|
|
let config: DelveLaunchRequest = serde_json::from_value(scenario.config).unwrap();
|
|
|
|
assert_eq!(
|
|
config,
|
|
DelveLaunchRequest {
|
|
request: "launch".to_string(),
|
|
mode: "debug".to_string(),
|
|
program: "./cmd/myapp".to_string(),
|
|
build_flags: vec![
|
|
"-race".to_string(),
|
|
"-ldflags".to_string(),
|
|
"-X main.version=1.0".to_string()
|
|
],
|
|
args: vec![
|
|
"--config".to_string(),
|
|
"production.yaml".to_string(),
|
|
"--verbose".to_string(),
|
|
],
|
|
env: {
|
|
let mut env = HashMap::default();
|
|
env.insert("GO_ENV".to_string(), "production".to_string());
|
|
env
|
|
},
|
|
cwd: Some("/project/root".to_string()),
|
|
}
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_go_locator_test(_: &mut TestAppContext) {
|
|
let locator = GoLocator;
|
|
let delve = DebugAdapterName("Delve".into());
|
|
|
|
// Test with tags and run flag
|
|
let task_with_tags = TaskTemplate {
|
|
label: "test".into(),
|
|
command: "go".into(),
|
|
args: vec![
|
|
"test".to_string(),
|
|
"-tags".to_string(),
|
|
"integration,unit".to_string(),
|
|
"-run".to_string(),
|
|
"Foo".to_string(),
|
|
".".to_string(),
|
|
],
|
|
..Default::default()
|
|
};
|
|
let result = locator
|
|
.create_scenario(&task_with_tags, "", &delve)
|
|
.await
|
|
.unwrap();
|
|
|
|
let config: DelveLaunchRequest = serde_json::from_value(result.config).unwrap();
|
|
|
|
assert_eq!(
|
|
config,
|
|
DelveLaunchRequest {
|
|
request: "launch".to_string(),
|
|
mode: "test".to_string(),
|
|
program: ".".to_string(),
|
|
build_flags: vec!["-tags".to_string(), "integration,unit".to_string(),],
|
|
args: vec![
|
|
"-test.run".to_string(),
|
|
"Foo".to_string(),
|
|
"-test.v".to_string()
|
|
],
|
|
env: Default::default(),
|
|
cwd: None,
|
|
}
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_go_locator_unescapes_nested_subtest_regex(_: &mut TestAppContext) {
|
|
let locator = GoLocator;
|
|
let delve = DebugAdapterName("Delve".into());
|
|
|
|
// Delve receives the `-run` regex with no shell, so GoLocator must strip
|
|
// the escaping itself.
|
|
let task = TaskTemplate {
|
|
label: "test subtest".into(),
|
|
command: "go".into(),
|
|
args: vec![
|
|
"test".to_string(),
|
|
"-v".to_string(),
|
|
"-run".to_string(),
|
|
"\\^TestFoo\\$/\\^simple_subtest\\$".to_string(),
|
|
],
|
|
..Default::default()
|
|
};
|
|
let result = locator.create_scenario(&task, "", &delve).await.unwrap();
|
|
let config: DelveLaunchRequest = serde_json::from_value(result.config).unwrap();
|
|
assert_eq!(
|
|
config,
|
|
DelveLaunchRequest {
|
|
request: "launch".to_string(),
|
|
mode: "test".to_string(),
|
|
program: ".".to_string(),
|
|
build_flags: vec![],
|
|
args: vec![
|
|
"-test.v".to_string(),
|
|
"-test.run".to_string(),
|
|
"^TestFoo$/^simple_subtest$".to_string(),
|
|
],
|
|
env: Default::default(),
|
|
cwd: None,
|
|
}
|
|
);
|
|
}
|
|
|
|
#[gpui::test]
|
|
async fn test_skip_unsupported_go_commands(_: &mut TestAppContext) {
|
|
let locator = GoLocator;
|
|
let task = TaskTemplate {
|
|
label: "go clean".into(),
|
|
command: "go".into(),
|
|
args: vec!["clean".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,
|
|
save: SaveStrategy::default(),
|
|
hooks: Default::default(),
|
|
};
|
|
|
|
let scenario = locator
|
|
.create_scenario(&task, "test label", &DebugAdapterName("Delve".into()))
|
|
.await;
|
|
assert!(scenario.is_none());
|
|
}
|
|
}
|
|
|
|
mod python_locator {
|
|
use dap::{DapLocator, adapters::DebugAdapterName};
|
|
use serde_json::json;
|
|
|
|
use project::debugger::locators::python::*;
|
|
use task::{DebugScenario, TaskTemplate};
|
|
|
|
#[gpui::test]
|
|
async fn test_python_locator() {
|
|
let adapter = DebugAdapterName("Debugpy".into());
|
|
let build_task = TaskTemplate {
|
|
label: "run module '$ZED_FILE'".into(),
|
|
command: "$ZED_CUSTOM_PYTHON_ACTIVE_ZED_TOOLCHAIN".into(),
|
|
args: vec!["-m".into(), "$ZED_CUSTOM_PYTHON_MODULE_NAME".into()],
|
|
env: Default::default(),
|
|
cwd: Some("$ZED_WORKTREE_ROOT".into()),
|
|
use_new_terminal: false,
|
|
allow_concurrent_runs: false,
|
|
reveal: task::RevealStrategy::Always,
|
|
reveal_target: task::RevealTarget::Dock,
|
|
hide: task::HideStrategy::Never,
|
|
tags: vec!["python-module-main-method".into()],
|
|
shell: task::Shell::System,
|
|
show_summary: false,
|
|
show_command: false,
|
|
save: task::SaveStrategy::default(),
|
|
hooks: Default::default(),
|
|
};
|
|
|
|
let expected_scenario = DebugScenario {
|
|
adapter: "Debugpy".into(),
|
|
label: "run module 'main.py'".into(),
|
|
build: None,
|
|
config: json!({
|
|
"request": "launch",
|
|
"python": "$ZED_CUSTOM_PYTHON_ACTIVE_ZED_TOOLCHAIN",
|
|
"args": [],
|
|
"cwd": "$ZED_WORKTREE_ROOT",
|
|
"module": "$ZED_CUSTOM_PYTHON_MODULE_NAME",
|
|
}),
|
|
tcp_connection: None,
|
|
};
|
|
|
|
assert_eq!(
|
|
PythonLocator
|
|
.create_scenario(&build_task, "run module 'main.py'", &adapter)
|
|
.await
|
|
.expect("Failed to create a scenario"),
|
|
expected_scenario
|
|
);
|
|
}
|
|
}
|
|
|
|
mod memory {
|
|
use project::debugger::{
|
|
MemoryCell,
|
|
memory::{MemoryIterator, PageAddress, PageContents},
|
|
};
|
|
|
|
#[test]
|
|
fn iterate_over_unmapped_memory() {
|
|
let empty_iterator = MemoryIterator::new(0..=127, Default::default());
|
|
let actual = empty_iterator.collect::<Vec<_>>();
|
|
let expected = vec![MemoryCell(None); 128];
|
|
assert_eq!(actual.len(), expected.len());
|
|
assert_eq!(actual, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn iterate_over_partially_mapped_memory() {
|
|
let it = MemoryIterator::new(
|
|
0..=127,
|
|
vec![(PageAddress(5), PageContents::mapped(vec![1]))].into_iter(),
|
|
);
|
|
let actual = it.collect::<Vec<_>>();
|
|
let expected = std::iter::repeat_n(MemoryCell(None), 5)
|
|
.chain(std::iter::once(MemoryCell(Some(1))))
|
|
.chain(std::iter::repeat_n(MemoryCell(None), 122))
|
|
.collect::<Vec<_>>();
|
|
assert_eq!(actual.len(), expected.len());
|
|
assert_eq!(actual, expected);
|
|
}
|
|
|
|
#[test]
|
|
fn reads_from_the_middle_of_a_page() {
|
|
let partial_iter = MemoryIterator::new(
|
|
20..=30,
|
|
vec![(PageAddress(0), PageContents::mapped((0..255).collect()))].into_iter(),
|
|
);
|
|
let actual = partial_iter.collect::<Vec<_>>();
|
|
let expected = (20..=30)
|
|
.map(|val| MemoryCell(Some(val)))
|
|
.collect::<Vec<_>>();
|
|
assert_eq!(actual.len(), expected.len());
|
|
assert_eq!(actual, expected);
|
|
}
|
|
}
|