351 lines · 11.1 KB · Rust
RawDownload
use dap::DapRegistry;use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};use project::{FakeFs, Project};use serde_json::json;use std::sync::Arc;use std::sync::atomic::{AtomicBool, Ordering};use task::{DebugRequest, DebugScenario, LaunchRequest, TaskContext, VariableName, ZedDebugConfig};use util::path; // use crate::new_process_modal::NewProcessMode;use crate::tests::{init_test, init_test_workspace}; #[gpui::test]async fn test_debug_session_substitutes_variables_and_relativizes_paths(    executor: BackgroundExecutor,    cx: &mut TestAppContext,) {    init_test(cx);     let fs = FakeFs::new(executor.clone());    fs.insert_tree(        path!("/project"),        json!({            "main.rs": "fn main() {}"        }),    )    .await;     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 test_variables = vec![(        VariableName::WorktreeRoot,        path!("/test/worktree/path").to_string(),    )]    .into_iter()    .collect();     let task_context = TaskContext {        cwd: None,        task_variables: test_variables,        project_env: Default::default(),    };     let home_dir = paths::home_dir();     let test_cases: Vec<(&'static str, &'static str)> = vec![        // Absolute path - should not be relativized        (            path!("/absolute/path/to/program"),            path!("/absolute/path/to/program"),        ),        // Relative path - should be prefixed with worktree root        (            format!(".{0}src{0}program", std::path::MAIN_SEPARATOR).leak(),            path!("/test/worktree/path/src/program"),        ),        // Home directory path - should be expanded to full home directory path        (            format!("~{0}src{0}program", std::path::MAIN_SEPARATOR).leak(),            home_dir                .join("src")                .join("program")                .to_string_lossy()                .to_string()                .leak(),        ),        // Path with $ZED_WORKTREE_ROOT - should be substituted without double appending        (            format!(                "$ZED_WORKTREE_ROOT{0}src{0}program",                std::path::MAIN_SEPARATOR            )            .leak(),            path!("/test/worktree/path/src/program"),        ),    ];     let called_launch = Arc::new(AtomicBool::new(false));     for (input_path, expected_path) in test_cases {        let _subscription = project::debugger::test::intercept_debug_sessions(cx, {            let called_launch = called_launch.clone();            move |client| {                client.on_request::<dap::requests::Launch, _>({                    let called_launch = called_launch.clone();                     move |_, args| {                        let config = args.raw.as_object().unwrap();                         assert_eq!(                            config["program"].as_str().unwrap(),                            expected_path,                            "Program path was not correctly substituted for input: {}",                            input_path                        );                         assert_eq!(                            config["cwd"].as_str().unwrap(),                            expected_path,                            "CWD path was not correctly substituted for input: {}",                            input_path                        );                         let expected_other_field = if input_path.contains("$ZED_WORKTREE_ROOT") {                            input_path                                .replace("$ZED_WORKTREE_ROOT", &path!("/test/worktree/path"))                                .to_owned()                        } else {                            input_path.to_string()                        };                         assert_eq!(                            config["otherField"].as_str().unwrap(),                            &expected_other_field,                            "Other field was incorrectly modified for input: {}",                            input_path                        );                         called_launch.store(true, Ordering::SeqCst);                         Ok(())                    }                });            }        });         let scenario = DebugScenario {            adapter: "fake-adapter".into(),            label: "test-debug-session".into(),            build: None,            config: json!({                "request": "launch",                "program": input_path,                "cwd": input_path,                "otherField": input_path            }),            tcp_connection: None,        };         workspace            .update(cx, |workspace, window, cx| {                workspace.start_debug_session(scenario, task_context.clone(), None, window, cx)            })            .unwrap();         cx.run_until_parked();         assert!(called_launch.load(Ordering::SeqCst));        called_launch.store(false, Ordering::SeqCst);    }} // #[gpui::test]// async fn test_save_debug_scenario_to_file(executor: BackgroundExecutor, cx: &mut TestAppContext) {//     init_test(cx); //     let fs = FakeFs::new(executor.clone());//     fs.insert_tree(//         path!("/project"),//         json!({//             "main.rs": "fn main() {}"//         }),//     )//     .await; //     let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;//     let workspace = init_test_workspace(&project, cx).await;//     let cx = &mut VisualTestContext::from_window(*workspace, cx); //     workspace//         .update(cx, |workspace, window, cx| {//             crate::new_process_modal::NewProcessModal::show(//                 workspace,//                 window,//                 NewProcessMode::Debug,//                 None,//                 cx,//             );//         })//         .unwrap(); //     cx.run_until_parked(); //     let modal = workspace//         .update(cx, |workspace, _, cx| {//             workspace.active_modal::<crate::new_process_modal::NewProcessModal>(cx)//         })//         .unwrap()//         .expect("Modal should be active"); //     modal.update_in(cx, |modal, window, cx| {//         modal.set_configure("/project/main", "/project", false, window, cx);//         modal.save_scenario(window, cx);//     }); //     cx.executor().run_until_parked(); //     let debug_json_content = fs//         .load(path!("/project/.zed/debug.json").as_ref())//         .await//         .expect("debug.json should exist"); //     let expected_content = vec![//         "[",//         "  {",//         r#"    "adapter": "fake-adapter","#,//         r#"    "label": "main (fake-adapter)","#,//         r#"    "request": "launch","#,//         r#"    "program": "/project/main","#,//         r#"    "cwd": "/project","#,//         r#"    "args": [],"#,//         r#"    "env": {}"#,//         "  }",//         "]",//     ]; //     let actual_lines: Vec<&str> = debug_json_content.lines().collect();//     pretty_assertions::assert_eq!(expected_content, actual_lines); //     modal.update_in(cx, |modal, window, cx| {//         modal.set_configure("/project/other", "/project", true, window, cx);//         modal.save_scenario(window, cx);//     }); //     cx.executor().run_until_parked(); //     let debug_json_content = fs//         .load(path!("/project/.zed/debug.json").as_ref())//         .await//         .expect("debug.json should exist after second save"); //     let expected_content = vec![//         "[",//         "  {",//         r#"    "adapter": "fake-adapter","#,//         r#"    "label": "main (fake-adapter)","#,//         r#"    "request": "launch","#,//         r#"    "program": "/project/main","#,//         r#"    "cwd": "/project","#,//         r#"    "args": [],"#,//         r#"    "env": {}"#,//         "  },",//         "  {",//         r#"    "adapter": "fake-adapter","#,//         r#"    "label": "other (fake-adapter)","#,//         r#"    "request": "launch","#,//         r#"    "program": "/project/other","#,//         r#"    "cwd": "/project","#,//         r#"    "args": [],"#,//         r#"    "env": {}"#,//         "  }",//         "]",//     ]; //     let actual_lines: Vec<&str> = debug_json_content.lines().collect();//     pretty_assertions::assert_eq!(expected_content, actual_lines);// } #[gpui::test]async fn test_dap_adapter_config_conversion_and_validation(cx: &mut TestAppContext) {    init_test(cx);     let mut expected_adapters = vec![        "CodeLLDB",        "Debugpy",        "PHP",        "JavaScript",        "Ruby",        "Delve",        "GDB",        "fake-adapter",    ];     let adapter_names = cx.update(|cx| {        let registry = DapRegistry::global(cx);        registry.enumerate_adapters()    });     let zed_config = ZedDebugConfig {        label: "test_debug_session".into(),        adapter: "test_adapter".into(),        request: DebugRequest::Launch(LaunchRequest {            program: "test_program".into(),            cwd: None,            args: vec![],            env: Default::default(),        }),        stop_on_entry: Some(true),    };     for adapter_name in adapter_names {        let adapter_str = adapter_name.to_string();        if let Some(pos) = expected_adapters.iter().position(|&x| x == adapter_str) {            expected_adapters.remove(pos);        }         let adapter = cx            .update(|cx| {                let registry = DapRegistry::global(cx);                registry.adapter(adapter_name.as_ref())            })            .unwrap_or_else(|| panic!("Adapter {} should exist", adapter_name));         let mut adapter_specific_config = zed_config.clone();        adapter_specific_config.adapter = adapter_name.to_string().into();         let debug_scenario = adapter            .config_from_zed_format(adapter_specific_config)            .await            .unwrap_or_else(|_| {                panic!(                    "Adapter {} should successfully convert from Zed format",                    adapter_name                )            });         assert!(            debug_scenario.config.is_object(),            "Adapter {} should produce a JSON object for config",            adapter_name        );         let request_type = adapter            .request_kind(&debug_scenario.config)            .await            .unwrap_or_else(|_| {                panic!(                    "Adapter {} should validate the config successfully",                    adapter_name                )            });         match request_type {            dap::StartDebuggingRequestArgumentsRequest::Launch => {}            dap::StartDebuggingRequestArgumentsRequest::Attach => {                panic!(                    "Expected Launch request but got Attach for adapter {}",                    adapter_name                );            }        }    }     assert!(        expected_adapters.is_empty(),        "The following expected adapters were not found in the registry: {:?}",        expected_adapters    );}