use crate::*;use dap::{ ErrorResponse, Message, RunInTerminalRequestArguments, SourceBreakpoint, StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest, client::SessionId, requests::{ Continue, Disconnect, Launch, Next, RunInTerminal, SetBreakpoints, StackTrace, StartDebugging, StepBack, StepIn, StepOut, Threads, },};use editor::{ Editor, EditorMode, MultiBuffer, actions::{self},};use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};use project::{ FakeFs, Project, debugger::session::{ThreadId, ThreadStatus},};use serde_json::json;use std::{ path::Path, sync::{ Arc, atomic::{AtomicBool, Ordering}, },};use terminal_view::{TerminalView, terminal_panel::TerminalPanel};use tests::{active_debug_session_panel, init_test, init_test_workspace};use util::path;use workspace::{Item, dock::Panel}; #[gpui::test]async fn test_basic_show_debug_panel(executor: BackgroundExecutor, cx: &mut TestAppContext) { init_test(cx); let fs = FakeFs::new(executor.clone()); fs.insert_tree( "/project", json!({ "main.rs": "First line\nSecond line\nThird line\nFourth line", }), ) .await; let project = Project::test(fs, ["/project".as_ref()], cx).await; let workspace = init_test_workspace(&project, cx).await; let cx = &mut VisualTestContext::from_window(*workspace, cx); let session = debugger::test::start_debug_session(&project, cx, |_| {}) .await .unwrap(); let client = session.update(cx, |session, _| session.adapter_client().unwrap()); client.on_request::<Threads, _>(move |_, _| { Ok(dap::ThreadsResponse { threads: vec![dap::Thread { id: 1, name: "Thread 1".into(), }], }) }); client.on_request::<StackTrace, _>(move |_, _| { Ok(dap::StackTraceResponse { stack_frames: Vec::default(), total_frames: None, }) }); cx.run_until_parked(); // assert we have a debug panel item before the session has stopped workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let active_session = debug_panel.update(cx, |debug_panel, _| debug_panel.active_session().unwrap()); let running_state = active_session.update(cx, |active_session, _| { active_session .mode() .as_running() .expect("Session should be running by this point") .clone() }); debug_panel.update(cx, |this, cx| { assert!(this.active_session().is_some()); assert!(running_state.read(cx).selected_thread_id().is_none()); }); }) .unwrap(); client .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { reason: dap::StoppedEventReason::Pause, description: None, thread_id: Some(1), preserve_focus_hint: None, text: None, all_threads_stopped: None, hit_breakpoint_ids: None, })) .await; cx.run_until_parked(); workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let active_session = debug_panel .update(cx, |this, _| this.active_session()) .unwrap(); let running_state = active_session.update(cx, |active_session, _| { active_session .mode() .as_running() .expect("Session should be running by this point") .clone() }); assert_eq!(client.id(), running_state.read(cx).session_id()); assert_eq!( ThreadId(1), running_state.read(cx).selected_thread_id().unwrap() ); }) .unwrap(); let shutdown_session = project.update(cx, |project, cx| { project.dap_store().update(cx, |dap_store, cx| { dap_store.shutdown_session(session.read(cx).session_id(), cx) }) }); shutdown_session.await.unwrap(); // assert we still have a debug panel item after the client shutdown workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let active_session = debug_panel .update(cx, |this, _| this.active_session()) .unwrap(); let running_state = active_session.update(cx, |active_session, _| { active_session .mode() .as_running() .expect("Session should be running by this point") .clone() }); debug_panel.update(cx, |this, cx| { assert!(this.active_session().is_some()); assert_eq!( ThreadId(1), running_state.read(cx).selected_thread_id().unwrap() ); }); }) .unwrap();} #[gpui::test]async fn test_we_can_only_have_one_panel_per_debug_session( executor: BackgroundExecutor, cx: &mut TestAppContext,) { init_test(cx); let fs = FakeFs::new(executor.clone()); fs.insert_tree( "/project", json!({ "main.rs": "First line\nSecond line\nThird line\nFourth line", }), ) .await; let project = Project::test(fs, ["/project".as_ref()], cx).await; let workspace = init_test_workspace(&project, cx).await; let cx = &mut VisualTestContext::from_window(*workspace, cx); let session = debugger::test::start_debug_session(&project, cx, |_| {}) .await .unwrap(); let client = session.update(cx, |session, _| session.adapter_client().unwrap()); client.on_request::<Threads, _>(move |_, _| { Ok(dap::ThreadsResponse { threads: vec![dap::Thread { id: 1, name: "Thread 1".into(), }], }) }); client.on_request::<StackTrace, _>(move |_, _| { Ok(dap::StackTraceResponse { stack_frames: Vec::default(), total_frames: None, }) }); cx.run_until_parked(); // assert we have a debug panel item before the session has stopped workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); debug_panel.update(cx, |this, _| { assert!(this.active_session().is_some()); }); }) .unwrap(); client .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { reason: dap::StoppedEventReason::Pause, description: None, thread_id: Some(1), preserve_focus_hint: None, text: None, all_threads_stopped: None, hit_breakpoint_ids: None, })) .await; cx.run_until_parked(); // assert we added a debug panel item workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let active_session = debug_panel .update(cx, |this, _| this.active_session()) .unwrap(); let running_state = active_session.update(cx, |active_session, _| { active_session .mode() .as_running() .expect("Session should be running by this point") .clone() }); assert_eq!(client.id(), active_session.read(cx).session_id(cx)); assert_eq!( ThreadId(1), running_state.read(cx).selected_thread_id().unwrap() ); }) .unwrap(); client .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { reason: dap::StoppedEventReason::Pause, description: None, thread_id: Some(2), preserve_focus_hint: None, text: None, all_threads_stopped: None, hit_breakpoint_ids: None, })) .await; cx.run_until_parked(); workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let active_session = debug_panel .update(cx, |this, _| this.active_session()) .unwrap(); let running_state = active_session.update(cx, |active_session, _| { active_session .mode() .as_running() .expect("Session should be running by this point") .clone() }); assert_eq!(client.id(), active_session.read(cx).session_id(cx)); assert_eq!( ThreadId(1), running_state.read(cx).selected_thread_id().unwrap() ); }) .unwrap(); let shutdown_session = project.update(cx, |project, cx| { project.dap_store().update(cx, |dap_store, cx| { dap_store.shutdown_session(session.read(cx).session_id(), cx) }) }); shutdown_session.await.unwrap(); // assert we still have a debug panel item after the client shutdown workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let active_session = debug_panel .update(cx, |this, _| this.active_session()) .unwrap(); let running_state = active_session.update(cx, |active_session, _| { active_session .mode() .as_running() .expect("Session should be running by this point") .clone() }); debug_panel.update(cx, |this, cx| { assert!(this.active_session().is_some()); assert_eq!( ThreadId(1), running_state.read(cx).selected_thread_id().unwrap() ); }); }) .unwrap();} #[gpui::test]async fn test_handle_successful_run_in_terminal_reverse_request( executor: BackgroundExecutor, cx: &mut TestAppContext,) { init_test(cx); let send_response = Arc::new(AtomicBool::new(false)); let fs = FakeFs::new(executor.clone()); fs.insert_tree( "/project", json!({ "main.rs": "First line\nSecond line\nThird line\nFourth line", }), ) .await; let project = Project::test(fs, ["/project".as_ref()], cx).await; let workspace = init_test_workspace(&project, cx).await; let cx = &mut VisualTestContext::from_window(*workspace, cx); let session = debugger::test::start_debug_session(&project, cx, |_| {}) .await .unwrap(); let client = session.update(cx, |session, _| session.adapter_client().unwrap()); client .on_response::<RunInTerminal, _>({ let send_response = send_response.clone(); move |response| { send_response.store(true, Ordering::SeqCst); assert!(response.success); assert!(response.body.is_some()); } }) .await; client .fake_reverse_request::<RunInTerminal>(RunInTerminalRequestArguments { kind: None, title: None, cwd: std::env::temp_dir().to_string_lossy().to_string(), args: vec![], env: None, args_can_be_interpreted_by_shell: None, }) .await; cx.run_until_parked(); assert!( send_response.load(std::sync::atomic::Ordering::SeqCst), "Expected to receive response from reverse request" ); workspace .update(cx, |workspace, _window, cx| { let terminal_panel = workspace.panel::<TerminalPanel>(cx).unwrap(); let panel = terminal_panel.read(cx).pane().unwrap().read(cx); assert_eq!(1, panel.items_len()); assert!( panel .active_item() .unwrap() .downcast::<TerminalView>() .unwrap() .read(cx) .terminal() .read(cx) .debug_terminal() ); }) .unwrap(); let shutdown_session = project.update(cx, |project, cx| { project.dap_store().update(cx, |dap_store, cx| { dap_store.shutdown_session(session.read(cx).session_id(), cx) }) }); shutdown_session.await.unwrap();} // // covers that we always send a response back, if something when wrong,// // while spawning the terminal#[gpui::test]async fn test_handle_error_run_in_terminal_reverse_request( executor: BackgroundExecutor, cx: &mut TestAppContext,) { init_test(cx); let send_response = Arc::new(AtomicBool::new(false)); let fs = FakeFs::new(executor.clone()); fs.insert_tree( "/project", json!({ "main.rs": "First line\nSecond line\nThird line\nFourth line", }), ) .await; let project = Project::test(fs, ["/project".as_ref()], cx).await; let workspace = init_test_workspace(&project, cx).await; let cx = &mut VisualTestContext::from_window(*workspace, cx); let session = debugger::test::start_debug_session(&project, cx, |_| {}) .await .unwrap(); let client = session.update(cx, |session, _| session.adapter_client().unwrap()); client .on_response::<RunInTerminal, _>({ let send_response = send_response.clone(); move |response| { send_response.store(true, Ordering::SeqCst); assert!(!response.success); assert!(response.body.is_some()); } }) .await; client .fake_reverse_request::<RunInTerminal>(RunInTerminalRequestArguments { kind: None, title: None, cwd: "/non-existing/path".into(), // invalid/non-existing path will cause the terminal spawn to fail args: vec![], env: None, args_can_be_interpreted_by_shell: None, }) .await; cx.run_until_parked(); assert!( send_response.load(std::sync::atomic::Ordering::SeqCst), "Expected to receive response from reverse request" ); workspace .update(cx, |workspace, _window, cx| { let terminal_panel = workspace.panel::<TerminalPanel>(cx).unwrap(); assert_eq!( 0, terminal_panel.read(cx).pane().unwrap().read(cx).items_len() ); }) .unwrap(); let shutdown_session = project.update(cx, |project, cx| { project.dap_store().update(cx, |dap_store, cx| { dap_store.shutdown_session(session.read(cx).session_id(), cx) }) }); shutdown_session.await.unwrap();}Lines 1–500 of 1390. Load more
use crate::*; use dap::{ ErrorResponse, Message, RunInTerminalRequestArguments, SourceBreakpoint, StartDebuggingRequestArguments, StartDebuggingRequestArgumentsRequest, client::SessionId, requests::{ Continue, Disconnect, Launch, Next, RunInTerminal, SetBreakpoints, StackTrace, StartDebugging, StepBack, StepIn, StepOut, Threads, }, }; use editor::{ Editor, EditorMode, MultiBuffer, actions::{self}, }; use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext}; use project::{ FakeFs, Project, debugger::session::{ThreadId, ThreadStatus}, }; use serde_json::json; use std::{ path::Path, sync::{ Arc, atomic::{AtomicBool, Ordering}, }, }; use terminal_view::{TerminalView, terminal_panel::TerminalPanel}; use tests::{active_debug_session_panel, init_test, init_test_workspace}; use util::path; use workspace::{Item, dock::Panel}; #[gpui::test] async fn test_basic_show_debug_panel(executor: BackgroundExecutor, cx: &mut TestAppContext) { init_test(cx); let fs = FakeFs::new(executor.clone()); fs.insert_tree( "/project", json!({ "main.rs": "First line\nSecond line\nThird line\nFourth line", }), ) .await; let project = Project::test(fs, ["/project".as_ref()], cx).await; let workspace = init_test_workspace(&project, cx).await; let cx = &mut VisualTestContext::from_window(*workspace, cx); let session = debugger::test::start_debug_session(&project, cx, |_| {}) .await .unwrap(); let client = session.update(cx, |session, _| session.adapter_client().unwrap()); client.on_request::<Threads, _>(move |_, _| { Ok(dap::ThreadsResponse { threads: vec![dap::Thread { id: 1, name: "Thread 1".into(), }], }) }); client.on_request::<StackTrace, _>(move |_, _| { Ok(dap::StackTraceResponse { stack_frames: Vec::default(), total_frames: None, }) }); cx.run_until_parked(); // assert we have a debug panel item before the session has stopped workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let active_session = debug_panel.update(cx, |debug_panel, _| debug_panel.active_session().unwrap()); let running_state = active_session.update(cx, |active_session, _| { active_session .mode() .as_running() .expect("Session should be running by this point") .clone() }); debug_panel.update(cx, |this, cx| { assert!(this.active_session().is_some()); assert!(running_state.read(cx).selected_thread_id().is_none()); }); }) .unwrap(); client .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { reason: dap::StoppedEventReason::Pause, description: None, thread_id: Some(1), preserve_focus_hint: None, text: None, all_threads_stopped: None, hit_breakpoint_ids: None, })) .await; cx.run_until_parked(); workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let active_session = debug_panel .update(cx, |this, _| this.active_session()) .unwrap(); let running_state = active_session.update(cx, |active_session, _| { active_session .mode() .as_running() .expect("Session should be running by this point") .clone() }); assert_eq!(client.id(), running_state.read(cx).session_id()); assert_eq!( ThreadId(1), running_state.read(cx).selected_thread_id().unwrap() ); }) .unwrap(); let shutdown_session = project.update(cx, |project, cx| { project.dap_store().update(cx, |dap_store, cx| { dap_store.shutdown_session(session.read(cx).session_id(), cx) }) }); shutdown_session.await.unwrap(); // assert we still have a debug panel item after the client shutdown workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let active_session = debug_panel .update(cx, |this, _| this.active_session()) .unwrap(); let running_state = active_session.update(cx, |active_session, _| { active_session .mode() .as_running() .expect("Session should be running by this point") .clone() }); debug_panel.update(cx, |this, cx| { assert!(this.active_session().is_some()); assert_eq!( ThreadId(1), running_state.read(cx).selected_thread_id().unwrap() ); }); }) .unwrap(); } #[gpui::test] async fn test_we_can_only_have_one_panel_per_debug_session( executor: BackgroundExecutor, cx: &mut TestAppContext, ) { init_test(cx); let fs = FakeFs::new(executor.clone()); fs.insert_tree( "/project", json!({ "main.rs": "First line\nSecond line\nThird line\nFourth line", }), ) .await; let project = Project::test(fs, ["/project".as_ref()], cx).await; let workspace = init_test_workspace(&project, cx).await; let cx = &mut VisualTestContext::from_window(*workspace, cx); let session = debugger::test::start_debug_session(&project, cx, |_| {}) .await .unwrap(); let client = session.update(cx, |session, _| session.adapter_client().unwrap()); client.on_request::<Threads, _>(move |_, _| { Ok(dap::ThreadsResponse { threads: vec![dap::Thread { id: 1, name: "Thread 1".into(), }], }) }); client.on_request::<StackTrace, _>(move |_, _| { Ok(dap::StackTraceResponse { stack_frames: Vec::default(), total_frames: None, }) }); cx.run_until_parked(); // assert we have a debug panel item before the session has stopped workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); debug_panel.update(cx, |this, _| { assert!(this.active_session().is_some()); }); }) .unwrap(); client .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { reason: dap::StoppedEventReason::Pause, description: None, thread_id: Some(1), preserve_focus_hint: None, text: None, all_threads_stopped: None, hit_breakpoint_ids: None, })) .await; cx.run_until_parked(); // assert we added a debug panel item workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let active_session = debug_panel .update(cx, |this, _| this.active_session()) .unwrap(); let running_state = active_session.update(cx, |active_session, _| { active_session .mode() .as_running() .expect("Session should be running by this point") .clone() }); assert_eq!(client.id(), active_session.read(cx).session_id(cx)); assert_eq!( ThreadId(1), running_state.read(cx).selected_thread_id().unwrap() ); }) .unwrap(); client .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent { reason: dap::StoppedEventReason::Pause, description: None, thread_id: Some(2), preserve_focus_hint: None, text: None, all_threads_stopped: None, hit_breakpoint_ids: None, })) .await; cx.run_until_parked(); workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let active_session = debug_panel .update(cx, |this, _| this.active_session()) .unwrap(); let running_state = active_session.update(cx, |active_session, _| { active_session .mode() .as_running() .expect("Session should be running by this point") .clone() }); assert_eq!(client.id(), active_session.read(cx).session_id(cx)); assert_eq!( ThreadId(1), running_state.read(cx).selected_thread_id().unwrap() ); }) .unwrap(); let shutdown_session = project.update(cx, |project, cx| { project.dap_store().update(cx, |dap_store, cx| { dap_store.shutdown_session(session.read(cx).session_id(), cx) }) }); shutdown_session.await.unwrap(); // assert we still have a debug panel item after the client shutdown workspace .update(cx, |workspace, _window, cx| { let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap(); let active_session = debug_panel .update(cx, |this, _| this.active_session()) .unwrap(); let running_state = active_session.update(cx, |active_session, _| { active_session .mode() .as_running() .expect("Session should be running by this point") .clone() }); debug_panel.update(cx, |this, cx| { assert!(this.active_session().is_some()); assert_eq!( ThreadId(1), running_state.read(cx).selected_thread_id().unwrap() ); }); }) .unwrap(); } #[gpui::test] async fn test_handle_successful_run_in_terminal_reverse_request( executor: BackgroundExecutor, cx: &mut TestAppContext, ) { init_test(cx); let send_response = Arc::new(AtomicBool::new(false)); let fs = FakeFs::new(executor.clone()); fs.insert_tree( "/project", json!({ "main.rs": "First line\nSecond line\nThird line\nFourth line", }), ) .await; let project = Project::test(fs, ["/project".as_ref()], cx).await; let workspace = init_test_workspace(&project, cx).await; let cx = &mut VisualTestContext::from_window(*workspace, cx); let session = debugger::test::start_debug_session(&project, cx, |_| {}) .await .unwrap(); let client = session.update(cx, |session, _| session.adapter_client().unwrap()); client .on_response::<RunInTerminal, _>({ let send_response = send_response.clone(); move |response| { send_response.store(true, Ordering::SeqCst); assert!(response.success); assert!(response.body.is_some()); } }) .await; client .fake_reverse_request::<RunInTerminal>(RunInTerminalRequestArguments { kind: None, title: None, cwd: std::env::temp_dir().to_string_lossy().to_string(), args: vec![], env: None, args_can_be_interpreted_by_shell: None, }) .await; cx.run_until_parked(); assert!( send_response.load(std::sync::atomic::Ordering::SeqCst), "Expected to receive response from reverse request" ); workspace .update(cx, |workspace, _window, cx| { let terminal_panel = workspace.panel::<TerminalPanel>(cx).unwrap(); let panel = terminal_panel.read(cx).pane().unwrap().read(cx); assert_eq!(1, panel.items_len()); assert!( panel .active_item() .unwrap() .downcast::<TerminalView>() .unwrap() .read(cx) .terminal() .read(cx) .debug_terminal() ); }) .unwrap(); let shutdown_session = project.update(cx, |project, cx| { project.dap_store().update(cx, |dap_store, cx| { dap_store.shutdown_session(session.read(cx).session_id(), cx) }) }); shutdown_session.await.unwrap(); } // // covers that we always send a response back, if something when wrong, // // while spawning the terminal #[gpui::test] async fn test_handle_error_run_in_terminal_reverse_request( executor: BackgroundExecutor, cx: &mut TestAppContext, ) { init_test(cx); let send_response = Arc::new(AtomicBool::new(false)); let fs = FakeFs::new(executor.clone()); fs.insert_tree( "/project", json!({ "main.rs": "First line\nSecond line\nThird line\nFourth line", }), ) .await; let project = Project::test(fs, ["/project".as_ref()], cx).await; let workspace = init_test_workspace(&project, cx).await; let cx = &mut VisualTestContext::from_window(*workspace, cx); let session = debugger::test::start_debug_session(&project, cx, |_| {}) .await .unwrap(); let client = session.update(cx, |session, _| session.adapter_client().unwrap()); client .on_response::<RunInTerminal, _>({ let send_response = send_response.clone(); move |response| { send_response.store(true, Ordering::SeqCst); assert!(!response.success); assert!(response.body.is_some()); } }) .await; client .fake_reverse_request::<RunInTerminal>(RunInTerminalRequestArguments { kind: None, title: None, cwd: "/non-existing/path".into(), // invalid/non-existing path will cause the terminal spawn to fail args: vec![], env: None, args_can_be_interpreted_by_shell: None, }) .await; cx.run_until_parked(); assert!( send_response.load(std::sync::atomic::Ordering::SeqCst), "Expected to receive response from reverse request" ); workspace .update(cx, |workspace, _window, cx| { let terminal_panel = workspace.panel::<TerminalPanel>(cx).unwrap(); assert_eq!( 0, terminal_panel.read(cx).pane().unwrap().read(cx).items_len() ); }) .unwrap(); let shutdown_session = project.update(cx, |project, cx| { project.dap_store().update(cx, |dap_store, cx| { dap_store.shutdown_session(session.read(cx).session_id(), cx) }) }); shutdown_session.await.unwrap(); }