dap_logger.rs

  1use crate::tests::{init_test, init_test_workspace, start_debug_session};
  2use dap::requests::{StackTrace, Threads};
  3use debugger_tools::LogStore;
  4use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
  5use project::Project;
  6use serde_json::json;
  7use std::cell::OnceCell;
  8
  9#[gpui::test]
 10async fn test_dap_logger_captures_all_session_rpc_messages(
 11    executor: BackgroundExecutor,
 12    cx: &mut TestAppContext,
 13) {
 14    let log_store_cell = std::rc::Rc::new(OnceCell::new());
 15
 16    cx.update(|cx| {
 17        let log_store_cell = log_store_cell.clone();
 18        cx.observe_new::<LogStore>(move |_, _, cx| {
 19            log_store_cell.set(cx.entity()).unwrap();
 20        })
 21        .detach();
 22        debugger_tools::init(cx);
 23    });
 24    init_test(cx);
 25
 26    let log_store = log_store_cell.get().unwrap().clone();
 27
 28    // Create a filesystem with a simple project
 29    let fs = project::FakeFs::new(executor.clone());
 30    fs.insert_tree(
 31        "/project",
 32        json!({
 33            "main.rs": "fn main() {\n    println!(\"Hello, world!\");\n}"
 34        }),
 35    )
 36    .await;
 37
 38    assert!(
 39        log_store.read_with(cx, |log_store, _| log_store
 40            .contained_session_ids()
 41            .is_empty()),
 42        "log_store shouldn't contain any session IDs before any sessions were created"
 43    );
 44
 45    let project = Project::test(fs, ["/project".as_ref()], cx).await;
 46
 47    let workspace = init_test_workspace(&project, cx).await;
 48    let cx = &mut VisualTestContext::from_window(*workspace, cx);
 49
 50    // Start a debug session
 51    let session = start_debug_session(&workspace, cx, |_| {}).unwrap();
 52    let session_id = session.read_with(cx, |session, _| session.session_id());
 53    let client = session.update(cx, |session, _| session.adapter_client().unwrap());
 54
 55    assert_eq!(
 56        log_store.read_with(cx, |log_store, _| log_store.contained_session_ids().len()),
 57        1,
 58    );
 59
 60    assert!(
 61        log_store.read_with(cx, |log_store, _| log_store
 62            .contained_session_ids()
 63            .contains(&session_id)),
 64        "log_store should contain the session IDs of the started session"
 65    );
 66
 67    assert!(
 68        !log_store.read_with(cx, |log_store, _| log_store
 69            .rpc_messages_for_session_id(session_id)
 70            .is_empty()),
 71        "We should have the initialization sequence in the log store"
 72    );
 73
 74    // Set up basic responses for common requests
 75    client.on_request::<Threads, _>(move |_, _| {
 76        Ok(dap::ThreadsResponse {
 77            threads: vec![dap::Thread {
 78                id: 1,
 79                name: "Thread 1".into(),
 80            }],
 81        })
 82    });
 83
 84    client.on_request::<StackTrace, _>(move |_, _| {
 85        Ok(dap::StackTraceResponse {
 86            stack_frames: Vec::default(),
 87            total_frames: None,
 88        })
 89    });
 90
 91    // Run until all pending tasks are executed
 92    cx.run_until_parked();
 93
 94    // Simulate a stopped event to generate more DAP messages
 95    client
 96        .fake_event(dap::messages::Events::Stopped(dap::StoppedEvent {
 97            reason: dap::StoppedEventReason::Pause,
 98            description: None,
 99            thread_id: Some(1),
100            preserve_focus_hint: None,
101            text: None,
102            all_threads_stopped: None,
103            hit_breakpoint_ids: None,
104        }))
105        .await;
106}