1use crate::{attach_modal::Candidate, tests::start_debug_session_with, *};
2use attach_modal::AttachModal;
3use dap::{FakeAdapter, adapters::DebugTaskDefinition};
4use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
5use menu::Confirm;
6use project::{FakeFs, Project};
7use serde_json::json;
8use task::{AttachRequest, TcpArgumentsTemplate};
9use tests::{init_test, init_test_workspace};
10use util::path;
11
12#[gpui::test]
13async fn test_direct_attach_to_process(executor: BackgroundExecutor, cx: &mut TestAppContext) {
14 init_test(cx);
15
16 let fs = FakeFs::new(executor.clone());
17
18 fs.insert_tree(
19 path!("/project"),
20 json!({
21 "main.rs": "First line\nSecond line\nThird line\nFourth line",
22 }),
23 )
24 .await;
25
26 let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
27 let workspace = init_test_workspace(&project, cx).await;
28 let cx = &mut VisualTestContext::from_window(*workspace, cx);
29
30 let session = start_debug_session_with(
31 &workspace,
32 cx,
33 DebugTaskDefinition {
34 adapter: "fake-adapter".into(),
35 request: dap::DebugRequest::Attach(AttachRequest {
36 process_id: Some(10),
37 }),
38 label: "label".into(),
39 initialize_args: None,
40 tcp_connection: None,
41 stop_on_entry: None,
42 },
43 |client| {
44 client.on_request::<dap::requests::Attach, _>(move |_, args| {
45 let raw = &args.raw;
46 assert_eq!(raw["request"], "attach");
47 assert_eq!(raw["process_id"], 10);
48
49 Ok(())
50 });
51 },
52 )
53 .unwrap();
54
55 cx.run_until_parked();
56
57 // assert we didn't show the attach modal
58 workspace
59 .update(cx, |workspace, _window, cx| {
60 assert!(workspace.active_modal::<AttachModal>(cx).is_none());
61 })
62 .unwrap();
63
64 let shutdown_session = project.update(cx, |project, cx| {
65 project.dap_store().update(cx, |dap_store, cx| {
66 dap_store.shutdown_session(session.read(cx).session_id(), cx)
67 })
68 });
69
70 shutdown_session.await.unwrap();
71}
72
73#[gpui::test]
74async fn test_show_attach_modal_and_select_process(
75 executor: BackgroundExecutor,
76 cx: &mut TestAppContext,
77) {
78 init_test(cx);
79
80 let fs = FakeFs::new(executor.clone());
81
82 fs.insert_tree(
83 path!("/project"),
84 json!({
85 "main.rs": "First line\nSecond line\nThird line\nFourth line",
86 }),
87 )
88 .await;
89
90 let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
91 let workspace = init_test_workspace(&project, cx).await;
92 let cx = &mut VisualTestContext::from_window(*workspace, cx);
93 // Set up handlers for sessions spawned via modal.
94 let _initialize_subscription =
95 project::debugger::test::intercept_debug_sessions(cx, |client| {
96 client.on_request::<dap::requests::Attach, _>(move |_, args| {
97 let raw = &args.raw;
98 assert_eq!(raw["request"], "attach");
99 assert_eq!(raw["process_id"], 1);
100
101 Ok(())
102 });
103 });
104 let attach_modal = workspace
105 .update(cx, |workspace, window, cx| {
106 let workspace_handle = cx.weak_entity();
107 workspace.toggle_modal(window, cx, |window, cx| {
108 AttachModal::with_processes(
109 workspace_handle,
110 DebugTaskDefinition {
111 adapter: FakeAdapter::ADAPTER_NAME.into(),
112
113 request: dap::DebugRequest::Attach(AttachRequest::default()),
114 label: "attach example".into(),
115 initialize_args: None,
116 tcp_connection: Some(TcpArgumentsTemplate::default()),
117 stop_on_entry: None,
118 },
119 vec![
120 Candidate {
121 pid: 0,
122 name: "fake-binary-1".into(),
123 command: vec![],
124 },
125 Candidate {
126 pid: 3,
127 name: "real-binary-1".into(),
128 command: vec![],
129 },
130 Candidate {
131 pid: 1,
132 name: "fake-binary-2".into(),
133 command: vec![],
134 },
135 ]
136 .into_iter()
137 .collect(),
138 true,
139 window,
140 cx,
141 )
142 });
143
144 workspace.active_modal::<AttachModal>(cx).unwrap()
145 })
146 .unwrap();
147
148 cx.run_until_parked();
149
150 // assert we got the expected processes
151 workspace
152 .update(cx, |_, window, cx| {
153 let names =
154 attach_modal.update(cx, |modal, cx| attach_modal::_process_names(&modal, cx));
155 // Initially all processes are visible.
156 assert_eq!(3, names.len());
157 attach_modal.update(cx, |this, cx| {
158 this.picker.update(cx, |this, cx| {
159 this.set_query("fakb", window, cx);
160 })
161 })
162 })
163 .unwrap();
164 cx.run_until_parked();
165 // assert we got the expected processes
166 workspace
167 .update(cx, |_, _, cx| {
168 let names =
169 attach_modal.update(cx, |modal, cx| attach_modal::_process_names(&modal, cx));
170 // Initially all processes are visible.
171 assert_eq!(2, names.len());
172 })
173 .unwrap();
174 // select the only existing process
175 cx.dispatch_action(Confirm);
176
177 cx.run_until_parked();
178
179 // assert attach modal was dismissed
180 workspace
181 .update(cx, |workspace, _window, cx| {
182 assert!(workspace.active_modal::<AttachModal>(cx).is_none());
183 })
184 .unwrap();
185}