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