Files
oak-gpui/crates/debugger_ui/src/tests/inline_values.rs
T
Remco SmitsandAnthony Eid 48b376fdc9 debugger: Fix nits (#30632)
Release Notes:

- N/A

---------

Co-authored-by: Anthony Eid <hello@anthonyeid.me>
2025-05-13 23:13:02 +02:00

1852 lines
52 KiB
Rust

use std::{path::Path, sync::Arc};
use dap::{Scope, StackFrame, Variable, requests::Variables};
use editor::{Editor, EditorMode, MultiBuffer};
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
use language::{Language, LanguageConfig, LanguageMatcher, tree_sitter_python, tree_sitter_rust};
use project::{FakeFs, Project};
use serde_json::json;
use unindent::Unindent as _;
use util::path;
use crate::{
debugger_panel::DebugPanel,
tests::{active_debug_session_panel, init_test, init_test_workspace, start_debug_session},
};
#[gpui::test]
async fn test_rust_inline_values(executor: BackgroundExecutor, cx: &mut TestAppContext) {
init_test(cx);
fn stack_frame_for_line(line: u64) -> dap::StackFrame {
StackFrame {
id: 1,
name: "Stack Frame 1".into(),
source: Some(dap::Source {
name: Some("main.rs".into()),
path: Some(path!("/project/main.rs").into()),
source_reference: None,
presentation_hint: None,
origin: None,
sources: None,
adapter_data: None,
checksums: None,
}),
line,
column: 1,
end_line: None,
end_column: None,
can_restart: None,
instruction_pointer_reference: None,
module_id: None,
presentation_hint: None,
}
}
let fs = FakeFs::new(executor.clone());
let source_code = r#"
static mut GLOBAL: usize = 1;
fn main() {
let x = 10;
let value = 42;
let y = 4;
let tester = {
let y = 10;
let y = 5;
let b = 3;
vec![y, 20, 30]
};
let caller = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent();
fs.insert_tree(path!("/project"), json!({ "main.rs": source_code }))
.await;
let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
let workspace = init_test_workspace(&project, cx).await;
workspace
.update(cx, |workspace, window, cx| {
workspace.focus_panel::<DebugPanel>(window, cx);
})
.unwrap();
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let session = start_debug_session(&workspace, cx, |_| {}).unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(4)],
total_frames: None,
})
});
client.on_request::<dap::requests::Evaluate, _>(move |_, args| {
assert_eq!("GLOBAL", args.expression);
Ok(dap::EvaluateResponse {
result: "1".into(),
type_: None,
presentation_hint: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
value_location_reference: None,
})
});
let local_variables = vec![
Variable {
name: "x".into(),
value: "10".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "y".into(),
value: "4".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "value".into(),
value: "42".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
];
client.on_request::<Variables, _>({
let local_variables = Arc::new(local_variables.clone());
move |_, _| {
Ok(dap::VariablesResponse {
variables: (*local_variables).clone(),
})
}
});
client.on_request::<dap::requests::Scopes, _>(move |_, _| {
Ok(dap::ScopesResponse {
scopes: vec![Scope {
name: "Locale".into(),
presentation_hint: None,
variables_reference: 2,
named_variables: None,
indexed_variables: None,
expensive: false,
source: None,
line: None,
column: None,
end_line: None,
end_column: None,
}],
})
});
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();
let project_path = Path::new(path!("/project"));
let worktree = project
.update(cx, |project, cx| project.find_worktree(project_path, cx))
.expect("This worktree should exist in project")
.0;
let worktree_id = workspace
.update(cx, |_, _, cx| worktree.read(cx).id())
.unwrap();
let buffer = project
.update(cx, |project, cx| {
project.open_buffer((worktree_id, "main.rs"), cx)
})
.await
.unwrap();
buffer.update(cx, |buffer, cx| {
buffer.set_language(Some(Arc::new(rust_lang())), cx);
});
let (editor, cx) = cx.add_window_view(|window, cx| {
Editor::new(
EditorMode::full(),
MultiBuffer::build_from_buffer(buffer, cx),
Some(project),
window,
cx,
)
});
active_debug_session_panel(workspace, cx).update_in(cx, |_, window, cx| {
cx.focus_self(window);
});
cx.run_until_parked();
editor.update(cx, |editor, cx| editor.refresh_inline_values(cx));
cx.run_until_parked();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 1: usize = 1;
fn main() {
let x = 10;
let value = 42;
let y = 4;
let tester = {
let y = 10;
let y = 5;
let b = 3;
vec![y, 20, 30]
};
let caller = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(5)],
total_frames: None,
})
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 1: usize = 1;
fn main() {
let x: 10 = 10;
let value = 42;
let y = 4;
let tester = {
let y = 10;
let y = 5;
let b = 3;
vec![y, 20, 30]
};
let caller = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(6)],
total_frames: None,
})
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 1: usize = 1;
fn main() {
let x: 10 = 10;
let value: 42 = 42;
let y = 4;
let tester = {
let y = 10;
let y = 5;
let b = 3;
vec![y, 20, 30]
};
let caller = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(7)],
total_frames: None,
})
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 1: usize = 1;
fn main() {
let x: 10 = 10;
let value: 42 = 42;
let y: 4 = 4;
let tester = {
let y = 10;
let y = 5;
let b = 3;
vec![y, 20, 30]
};
let caller = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(8)],
total_frames: None,
})
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 1: usize = 1;
fn main() {
let x: 10 = 10;
let value: 42 = 42;
let y: 4 = 4;
let tester = {
let y = 10;
let y = 5;
let b = 3;
vec![y, 20, 30]
};
let caller = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
let local_variables = vec![
Variable {
name: "x".into(),
value: "10".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "y".into(),
value: "10".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "value".into(),
value: "42".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
];
client.on_request::<Variables, _>({
let local_variables = Arc::new(local_variables.clone());
move |_, _| {
Ok(dap::VariablesResponse {
variables: (*local_variables).clone(),
})
}
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(9)],
total_frames: None,
})
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 1: usize = 1;
fn main() {
let x: 10 = 10;
let value: 42 = 42;
let y = 4;
let tester = {
let y: 10 = 10;
let y = 5;
let b = 3;
vec![y, 20, 30]
};
let caller = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
let local_variables = vec![
Variable {
name: "x".into(),
value: "10".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "y".into(),
value: "5".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "value".into(),
value: "42".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
];
client.on_request::<Variables, _>({
let local_variables = Arc::new(local_variables.clone());
move |_, _| {
Ok(dap::VariablesResponse {
variables: (*local_variables).clone(),
})
}
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(10)],
total_frames: None,
})
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 1: usize = 1;
fn main() {
let x: 10 = 10;
let value: 42 = 42;
let y = 4;
let tester = {
let y = 10;
let y: 5 = 5;
let b = 3;
vec![y, 20, 30]
};
let caller = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
let local_variables = vec![
Variable {
name: "x".into(),
value: "10".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "y".into(),
value: "5".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "value".into(),
value: "42".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "b".into(),
value: "3".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
];
client.on_request::<Variables, _>({
let local_variables = Arc::new(local_variables.clone());
move |_, _| {
Ok(dap::VariablesResponse {
variables: (*local_variables).clone(),
})
}
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(11)],
total_frames: None,
})
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 1: usize = 1;
fn main() {
let x: 10 = 10;
let value: 42 = 42;
let y = 4;
let tester = {
let y = 10;
let y: 5 = 5;
let b: 3 = 3;
vec![y, 20, 30]
};
let caller = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
let local_variables = vec![
Variable {
name: "x".into(),
value: "10".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "y".into(),
value: "4".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "value".into(),
value: "42".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "tester".into(),
value: "size=3".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
];
client.on_request::<Variables, _>({
let local_variables = Arc::new(local_variables.clone());
move |_, _| {
Ok(dap::VariablesResponse {
variables: (*local_variables).clone(),
})
}
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(14)],
total_frames: None,
})
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 1: usize = 1;
fn main() {
let x: 10 = 10;
let value: 42 = 42;
let y: 4 = 4;
let tester: size=3 = {
let y = 10;
let y = 5;
let b = 3;
vec![y, 20, 30]
};
let caller = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
let local_variables = vec![
Variable {
name: "x".into(),
value: "10".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "y".into(),
value: "4".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "value".into(),
value: "42".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "tester".into(),
value: "size=3".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "caller".into(),
value: "<not available>".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
];
client.on_request::<Variables, _>({
let local_variables = Arc::new(local_variables.clone());
move |_, _| {
Ok(dap::VariablesResponse {
variables: (*local_variables).clone(),
})
}
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(19)],
total_frames: None,
})
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 1: usize = 1;
fn main() {
let x: 10 = 10;
let value: 42 = 42;
let y: 4 = 4;
let tester: size=3 = {
let y = 10;
let y = 5;
let b = 3;
vec![y, 20, 30]
};
let caller: <not available> = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(15)],
total_frames: None,
})
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 1: usize = 1;
fn main() {
let x = 10;
let value = 42;
let y = 4;
let tester = {
let y = 10;
let y = 5;
let b = 3;
vec![y, 20, 30]
};
let caller = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
let local_variables = vec![Variable {
name: "x".into(),
value: "3".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
}];
client.on_request::<Variables, _>({
let local_variables = Arc::new(local_variables.clone());
move |_, _| {
Ok(dap::VariablesResponse {
variables: (*local_variables).clone(),
})
}
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(16)],
total_frames: None,
})
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 1: usize = 1;
fn main() {
let x = 10;
let value = 42;
let y = 4;
let tester = {
let y = 10;
let y = 5;
let b = 3;
vec![y, 20, 30]
};
let caller = || {
let x: 3 = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
let local_variables = vec![
Variable {
name: "x".into(),
value: "10".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "y".into(),
value: "4".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "value".into(),
value: "42".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "tester".into(),
value: "size=3".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "caller".into(),
value: "<not available>".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
];
client.on_request::<Variables, _>({
let local_variables = Arc::new(local_variables.clone());
move |_, _| {
Ok(dap::VariablesResponse {
variables: (*local_variables).clone(),
})
}
});
client.on_request::<dap::requests::Evaluate, _>(move |_, args| {
assert_eq!("GLOBAL", args.expression);
Ok(dap::EvaluateResponse {
result: "2".into(),
type_: None,
presentation_hint: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
value_location_reference: None,
})
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(25)],
total_frames: None,
})
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 2: usize = 1;
fn main() {
let x: 10 = 10;
let value: 42 = 42;
let y: 4 = 4;
let tester: size=3 = {
let y = 10;
let y = 5;
let b = 3;
vec![y, 20, 30]
};
let caller: <not available> = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
let local_variables = vec![
Variable {
name: "x".into(),
value: "10".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "y".into(),
value: "4".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "value".into(),
value: "42".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "tester".into(),
value: "size=3".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "caller".into(),
value: "<not available>".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "result".into(),
value: "840".into(),
type_: None,
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
];
client.on_request::<Variables, _>({
let local_variables = Arc::new(local_variables.clone());
move |_, _| {
Ok(dap::VariablesResponse {
variables: (*local_variables).clone(),
})
}
});
client.on_request::<dap::requests::StackTrace, _>(move |_, _| {
Ok(dap::StackTraceResponse {
stack_frames: vec![stack_frame_for_line(26)],
total_frames: None,
})
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
static mut GLOBAL: 2: usize = 1;
fn main() {
let x: 10 = 10;
let value: 42 = 42;
let y: 4 = 4;
let tester: size=3 = {
let y = 10;
let y = 5;
let b = 3;
vec![y, 20, 30]
};
let caller: <not available> = || {
let x = 3;
println!("x={}", x);
};
caller();
unsafe {
GLOBAL = 2;
}
let result: 840 = value * 2 * x;
println!("Simple test executed: value={}, result={}", value, result);
assert!(true);
}
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
}
fn rust_lang() -> Language {
Language::new(
LanguageConfig {
name: "Rust".into(),
matcher: LanguageMatcher {
path_suffixes: vec!["rs".to_string()],
..Default::default()
},
..Default::default()
},
Some(tree_sitter_rust::LANGUAGE.into()),
)
}
#[gpui::test]
async fn test_python_inline_values(executor: BackgroundExecutor, cx: &mut TestAppContext) {
init_test(cx);
let fs = FakeFs::new(executor.clone());
let source_code = r#"
def process_data(untyped_param, typed_param: int, another_typed: str):
# Local variables
x = 10
result = typed_param * 2
text = "Hello, " + another_typed
# For loop with range
sum_value = 0
for i in range(5):
sum_value += i
# Final result
final_result = x + result + sum_value
return final_result
"#
.unindent();
fs.insert_tree(path!("/project"), json!({ "main.py": source_code }))
.await;
let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
let workspace = init_test_workspace(&project, cx).await;
workspace
.update(cx, |workspace, window, cx| {
workspace.focus_panel::<DebugPanel>(window, cx);
})
.unwrap();
let cx = &mut VisualTestContext::from_window(*workspace, cx);
let session = start_debug_session(&workspace, cx, |_| {}).unwrap();
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
let project_path = Path::new(path!("/project"));
let worktree = project
.update(cx, |project, cx| project.find_worktree(project_path, cx))
.expect("This worktree should exist in project")
.0;
let worktree_id = workspace
.update(cx, |_, _, cx| worktree.read(cx).id())
.unwrap();
let buffer = project
.update(cx, |project, cx| {
project.open_buffer((worktree_id, "main.py"), cx)
})
.await
.unwrap();
buffer.update(cx, |buffer, cx| {
buffer.set_language(Some(Arc::new(python_lang())), cx);
});
let (editor, cx) = cx.add_window_view(|window, cx| {
Editor::new(
EditorMode::full(),
MultiBuffer::build_from_buffer(buffer, cx),
Some(project),
window,
cx,
)
});
editor.update(cx, |editor, cx| editor.refresh_inline_values(cx));
client.on_request::<dap::requests::Threads, _>(move |_, _| {
Ok(dap::ThreadsResponse {
threads: vec![dap::Thread {
id: 1,
name: "Thread 1".into(),
}],
})
});
client.on_request::<dap::requests::StackTrace, _>(move |_, args| {
assert_eq!(args.thread_id, 1);
Ok(dap::StackTraceResponse {
stack_frames: vec![StackFrame {
id: 1,
name: "Stack Frame 1".into(),
source: Some(dap::Source {
name: Some("main.py".into()),
path: Some(path!("/project/main.py").into()),
source_reference: None,
presentation_hint: None,
origin: None,
sources: None,
adapter_data: None,
checksums: None,
}),
line: 12,
column: 1,
end_line: None,
end_column: None,
can_restart: None,
instruction_pointer_reference: None,
module_id: None,
presentation_hint: None,
}],
total_frames: None,
})
});
client.on_request::<dap::requests::Scopes, _>(move |_, _| {
Ok(dap::ScopesResponse {
scopes: vec![
Scope {
name: "Local".into(),
presentation_hint: None,
variables_reference: 1,
named_variables: None,
indexed_variables: None,
expensive: false,
source: None,
line: None,
column: None,
end_line: None,
end_column: None,
},
Scope {
name: "Global".into(),
presentation_hint: None,
variables_reference: 2,
named_variables: None,
indexed_variables: None,
expensive: false,
source: None,
line: None,
column: None,
end_line: None,
end_column: None,
},
],
})
});
client.on_request::<Variables, _>(move |_, args| match args.variables_reference {
1 => Ok(dap::VariablesResponse {
variables: vec![
Variable {
name: "untyped_param".into(),
value: "test_value".into(),
type_: Some("str".into()),
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "typed_param".into(),
value: "42".into(),
type_: Some("int".into()),
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "another_typed".into(),
value: "world".into(),
type_: Some("str".into()),
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "x".into(),
value: "10".into(),
type_: Some("int".into()),
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "result".into(),
value: "84".into(),
type_: Some("int".into()),
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "text".into(),
value: "Hello, world".into(),
type_: Some("str".into()),
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "sum_value".into(),
value: "10".into(),
type_: Some("int".into()),
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "i".into(),
value: "4".into(),
type_: Some("int".into()),
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
Variable {
name: "final_result".into(),
value: "104".into(),
type_: Some("int".into()),
presentation_hint: None,
evaluate_name: None,
variables_reference: 0,
named_variables: None,
indexed_variables: None,
memory_reference: None,
declaration_location_reference: None,
value_location_reference: None,
},
],
}),
_ => Ok(dap::VariablesResponse { variables: vec![] }),
});
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();
editor.update_in(cx, |editor, window, cx| {
pretty_assertions::assert_eq!(
r#"
def process_data(untyped_param: test_value, typed_param: 42: int, another_typed: world: str):
# Local variables
x: 10 = 10
result: 84 = typed_param * 2
text: Hello, world = "Hello, " + another_typed
# For loop with range
sum_value: 10 = 0
for i: 4 in range(5):
sum_value += i
# Final result
final_result = x + result + sum_value
return final_result
"#
.unindent(),
editor.snapshot(window, cx).text()
);
});
}
fn python_lang() -> Language {
Language::new(
LanguageConfig {
name: "Python".into(),
matcher: LanguageMatcher {
path_suffixes: vec!["py".to_string()],
..Default::default()
},
..Default::default()
},
Some(tree_sitter_python::LANGUAGE.into()),
)
}