new_session_modal.rs

  1use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
  2use project::{FakeFs, Project};
  3use serde_json::json;
  4use std::sync::Arc;
  5use std::sync::atomic::{AtomicBool, Ordering};
  6use task::{DebugScenario, TaskContext, VariableName};
  7use util::path;
  8
  9use crate::tests::{init_test, init_test_workspace};
 10
 11// todo(tasks) figure out why task replacement is broken on windows
 12#[gpui::test]
 13async fn test_debug_session_substitutes_variables_and_relativizes_paths(
 14    executor: BackgroundExecutor,
 15    cx: &mut TestAppContext,
 16) {
 17    init_test(cx);
 18
 19    let fs = FakeFs::new(executor.clone());
 20    fs.insert_tree(
 21        path!("/project"),
 22        json!({
 23            "main.rs": "fn main() {}"
 24        }),
 25    )
 26    .await;
 27
 28    let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
 29    let workspace = init_test_workspace(&project, cx).await;
 30    let cx = &mut VisualTestContext::from_window(*workspace, cx);
 31
 32    // Set up task variables to simulate a real environment
 33    let test_variables = vec![(
 34        VariableName::WorktreeRoot,
 35        "/test/worktree/path".to_string(),
 36    )]
 37    .into_iter()
 38    .collect();
 39
 40    let task_context = TaskContext {
 41        cwd: None,
 42        task_variables: test_variables,
 43        project_env: Default::default(),
 44    };
 45
 46    let home_dir = paths::home_dir();
 47
 48    let sep = std::path::MAIN_SEPARATOR;
 49
 50    // Test cases for different path formats
 51    let test_cases: Vec<(Arc<String>, Arc<String>)> = vec![
 52        // Absolute path - should not be relativized
 53        (
 54            Arc::from(format!("{0}absolute{0}path{0}to{0}program", sep)),
 55            Arc::from(format!("{0}absolute{0}path{0}to{0}program", sep)),
 56        ),
 57        // Relative path - should be prefixed with worktree root
 58        (
 59            Arc::from(format!(".{0}src{0}program", sep)),
 60            Arc::from(format!("{0}test{0}worktree{0}path{0}src{0}program", sep)),
 61        ),
 62        // Home directory path - should be prefixed with worktree root
 63        (
 64            Arc::from(format!("~{0}src{0}program", sep)),
 65            Arc::from(format!(
 66                "{1}{0}src{0}program",
 67                sep,
 68                home_dir.to_string_lossy()
 69            )),
 70        ),
 71        // Path with $ZED_WORKTREE_ROOT - should be substituted without double appending
 72        (
 73            Arc::from(format!("$ZED_WORKTREE_ROOT{0}src{0}program", sep)),
 74            Arc::from(format!("{0}test{0}worktree{0}path{0}src{0}program", sep)),
 75        ),
 76    ];
 77
 78    let called_launch = Arc::new(AtomicBool::new(false));
 79
 80    for (input_path, expected_path) in test_cases {
 81        let _subscription = project::debugger::test::intercept_debug_sessions(cx, {
 82            let called_launch = called_launch.clone();
 83            let input_path = input_path.clone();
 84            let expected_path = expected_path.clone();
 85            move |client| {
 86                client.on_request::<dap::requests::Launch, _>({
 87                    let called_launch = called_launch.clone();
 88                    let input_path = input_path.clone();
 89                    let expected_path = expected_path.clone();
 90
 91                    move |_, args| {
 92                        let config = args.raw.as_object().unwrap();
 93
 94                        // Verify the program path was substituted correctly
 95                        assert_eq!(
 96                            config["program"].as_str().unwrap(),
 97                            expected_path.as_str(),
 98                            "Program path was not correctly substituted for input: {}",
 99                            input_path.as_str()
100                        );
101
102                        // Verify the cwd path was substituted correctly
103                        assert_eq!(
104                            config["cwd"].as_str().unwrap(),
105                            expected_path.as_str(),
106                            "CWD path was not correctly substituted for input: {}",
107                            input_path.as_str()
108                        );
109
110                        // Verify that otherField was substituted but not relativized
111                        // It should still have $ZED_WORKTREE_ROOT substituted if present
112                        let expected_other_field = if input_path.contains("$ZED_WORKTREE_ROOT") {
113                            input_path.replace("$ZED_WORKTREE_ROOT", "/test/worktree/path")
114                        } else {
115                            input_path.to_string()
116                        };
117
118                        assert_eq!(
119                            config["otherField"].as_str().unwrap(),
120                            expected_other_field,
121                            "Other field was incorrectly modified for input: {}",
122                            input_path
123                        );
124
125                        called_launch.store(true, Ordering::SeqCst);
126
127                        Ok(())
128                    }
129                });
130            }
131        });
132
133        let scenario = DebugScenario {
134            adapter: "fake-adapter".into(),
135            label: "test-debug-session".into(),
136            build: None,
137            config: json!({
138                "request": "launch",
139                "program": input_path,
140                "cwd": input_path,
141                "otherField": input_path
142            }),
143            tcp_connection: None,
144        };
145
146        workspace
147            .update(cx, |workspace, window, cx| {
148                workspace.start_debug_session(scenario, task_context.clone(), None, window, cx)
149            })
150            .unwrap();
151
152        cx.run_until_parked();
153
154        assert!(called_launch.load(Ordering::SeqCst));
155        called_launch.store(false, Ordering::SeqCst);
156    }
157}