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