logiguard fork: GPUI xdg-activation keyboard-focus serial fix
Some checks failed
Update All Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Triage Project Sync (#84) / Sync triage project (push) Has been cancelled
release_nightly / notify_on_failure (push) Has been cancelled
release_nightly / check_style (push) Has been cancelled
release_nightly / run_tests_windows (push) Has been cancelled
release_nightly / clippy_windows (push) Has been cancelled
release_nightly / bundle_linux_aarch64 (push) Has been cancelled
release_nightly / bundle_linux_x86_64 (push) Has been cancelled
release_nightly / bundle_mac_aarch64 (push) Has been cancelled
release_nightly / bundle_mac_x86_64 (push) Has been cancelled
release_nightly / bundle_windows_aarch64 (push) Has been cancelled
release_nightly / bundle_windows_x86_64 (push) Has been cancelled
release_nightly / build_nix_linux_x86_64 (push) Has been cancelled
release_nightly / build_nix_mac_aarch64 (push) Has been cancelled
release_nightly / update_nightly_tag (push) Has been cancelled
Hotfix Review Monitor / check-hotfix-reviews (push) Has been cancelled
Stale PR Review Reminder / check-stale-prs (push) Has been cancelled
Update Weekly Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Bump collab-staging Tag / update-collab-staging-tag (push) Has been cancelled
compliance_check / scheduled_compliance_check (push) Has been cancelled
Some checks failed
Update All Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Triage Project Sync (#84) / Sync triage project (push) Has been cancelled
release_nightly / notify_on_failure (push) Has been cancelled
release_nightly / check_style (push) Has been cancelled
release_nightly / run_tests_windows (push) Has been cancelled
release_nightly / clippy_windows (push) Has been cancelled
release_nightly / bundle_linux_aarch64 (push) Has been cancelled
release_nightly / bundle_linux_x86_64 (push) Has been cancelled
release_nightly / bundle_mac_aarch64 (push) Has been cancelled
release_nightly / bundle_mac_x86_64 (push) Has been cancelled
release_nightly / bundle_windows_aarch64 (push) Has been cancelled
release_nightly / bundle_windows_x86_64 (push) Has been cancelled
release_nightly / build_nix_linux_x86_64 (push) Has been cancelled
release_nightly / build_nix_mac_aarch64 (push) Has been cancelled
release_nightly / update_nightly_tag (push) Has been cancelled
Hotfix Review Monitor / check-hotfix-reviews (push) Has been cancelled
Stale PR Review Reminder / check-stale-prs (push) Has been cancelled
Update Weekly Top Ranking Issues / update_top_ranking_issues (push) Has been cancelled
Bump collab-staging Tag / update-collab-staging-tag (push) Has been cancelled
compliance_check / scheduled_compliance_check (push) Has been cancelled
Single-commit orphan branch: full zed-industries/zed @ 8c74db0 source tree with a 3-file patch applied (no upstream history). Patch (crates/gpui_linux/src/linux/wayland/): - serial.rs: add SerialKind::KeyboardEnter - client.rs: store wl_keyboard.enter serial; add latest_serial_of() - window.rs: activate() uses keyboard-enter serial (Mutter focus gate) Mutter honors window activation only when the token carries the keyboard- focus serial from wl_keyboard.enter; GPUI used a stale mouse-press serial. See docs/tray-window-focus-wayland.md in logiguard. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
320
crates/debugger_ui/src/tests/attach_modal.rs
Normal file
320
crates/debugger_ui/src/tests/attach_modal.rs
Normal file
@@ -0,0 +1,320 @@
|
||||
#![expect(clippy::result_large_err)]
|
||||
use crate::{
|
||||
attach_modal::{Candidate, ModalIntent},
|
||||
tests::start_debug_session_with,
|
||||
*,
|
||||
};
|
||||
use attach_modal::AttachModal;
|
||||
use dap::{FakeAdapter, adapters::DebugTaskDefinition};
|
||||
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
|
||||
use menu::Confirm;
|
||||
use project::{FakeFs, Project};
|
||||
use serde_json::json;
|
||||
use task::{AttachRequest, SharedTaskContext};
|
||||
use tests::{init_test, init_test_workspace};
|
||||
use util::path;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_direct_attach_to_process(executor: BackgroundExecutor, cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(executor.clone());
|
||||
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"main.rs": "First line\nSecond line\nThird line\nFourth line",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let _session = start_debug_session_with(
|
||||
&workspace,
|
||||
cx,
|
||||
DebugTaskDefinition {
|
||||
adapter: "fake-adapter".into(),
|
||||
label: "label".into(),
|
||||
config: json!({
|
||||
"request": "attach",
|
||||
"process_id": 10,
|
||||
}),
|
||||
tcp_connection: None,
|
||||
},
|
||||
|client| {
|
||||
client.on_request::<dap::requests::Attach, _>(move |_, args| {
|
||||
let raw = &args.raw;
|
||||
assert_eq!(raw["request"], "attach");
|
||||
assert_eq!(raw["process_id"], 10);
|
||||
|
||||
Ok(())
|
||||
});
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
// assert we didn't show the attach modal
|
||||
workspace
|
||||
.update(cx, |workspace, _window, cx| {
|
||||
assert!(
|
||||
workspace
|
||||
.workspace()
|
||||
.read(cx)
|
||||
.active_modal::<AttachModal>(cx)
|
||||
.is_none()
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_show_attach_modal_and_select_process(
|
||||
executor: BackgroundExecutor,
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(executor.clone());
|
||||
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"main.rs": "First line\nSecond line\nThird line\nFourth line",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
// Set up handlers for sessions spawned via modal.
|
||||
let _initialize_subscription =
|
||||
project::debugger::test::intercept_debug_sessions(cx, |client| {
|
||||
client.on_request::<dap::requests::Attach, _>(move |_, args| {
|
||||
let raw = &args.raw;
|
||||
assert_eq!(raw["request"], "attach");
|
||||
assert_eq!(raw["process_id"], 1);
|
||||
|
||||
Ok(())
|
||||
});
|
||||
});
|
||||
let attach_modal = workspace
|
||||
.update(cx, |multi, window, cx| {
|
||||
let workspace_handle = multi.workspace().downgrade();
|
||||
multi.toggle_modal(window, cx, |window, cx| {
|
||||
AttachModal::with_processes(
|
||||
workspace_handle,
|
||||
vec![
|
||||
Candidate {
|
||||
pid: 0,
|
||||
name: "fake-binary-1".into(),
|
||||
command: vec![],
|
||||
},
|
||||
Candidate {
|
||||
pid: 3,
|
||||
name: "real-binary-1".into(),
|
||||
command: vec![],
|
||||
},
|
||||
Candidate {
|
||||
pid: 1,
|
||||
name: "fake-binary-2".into(),
|
||||
command: vec![],
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
true,
|
||||
ModalIntent::AttachToProcess(task::ZedDebugConfig {
|
||||
adapter: FakeAdapter::ADAPTER_NAME.into(),
|
||||
request: dap::DebugRequest::Attach(AttachRequest::default()),
|
||||
label: "attach example".into(),
|
||||
stop_on_entry: None,
|
||||
}),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
});
|
||||
|
||||
multi.active_modal::<AttachModal>(cx).unwrap()
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
// assert we got the expected processes
|
||||
workspace
|
||||
.update(cx, |_, window, cx| {
|
||||
let names = attach_modal.update(cx, |modal, cx| attach_modal::process_names(modal, cx));
|
||||
// Initially all processes are visible.
|
||||
assert_eq!(3, names.len());
|
||||
attach_modal.update(cx, |this, cx| {
|
||||
this.picker.update(cx, |this, cx| {
|
||||
this.set_query("fakb", window, cx);
|
||||
})
|
||||
})
|
||||
})
|
||||
.unwrap();
|
||||
cx.run_until_parked();
|
||||
// assert we got the expected processes
|
||||
workspace
|
||||
.update(cx, |_, _, cx| {
|
||||
let names = attach_modal.update(cx, |modal, cx| attach_modal::process_names(modal, cx));
|
||||
// Initially all processes are visible.
|
||||
assert_eq!(2, names.len());
|
||||
})
|
||||
.unwrap();
|
||||
// select the only existing process
|
||||
cx.dispatch_action(Confirm);
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
// assert attach modal was dismissed
|
||||
workspace
|
||||
.update(cx, |workspace, _window, cx| {
|
||||
assert!(workspace.active_modal::<AttachModal>(cx).is_none());
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_attach_with_pick_pid_variable(executor: BackgroundExecutor, cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(executor.clone());
|
||||
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"main.rs": "First line\nSecond line\nThird line\nFourth line",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let _initialize_subscription =
|
||||
project::debugger::test::intercept_debug_sessions(cx, |client| {
|
||||
client.on_request::<dap::requests::Attach, _>(move |_, args| {
|
||||
let raw = &args.raw;
|
||||
assert_eq!(raw["request"], "attach");
|
||||
assert_eq!(
|
||||
raw["process_id"], "42",
|
||||
"verify process id has been replaced"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
});
|
||||
});
|
||||
|
||||
let pick_pid_placeholder = task::VariableName::PickProcessId.template_value();
|
||||
workspace
|
||||
.update(cx, |multi, window, cx| {
|
||||
multi.workspace().update(cx, |workspace, cx| {
|
||||
workspace.start_debug_session(
|
||||
DebugTaskDefinition {
|
||||
adapter: FakeAdapter::ADAPTER_NAME.into(),
|
||||
label: "attach with picker".into(),
|
||||
config: json!({
|
||||
"request": "attach",
|
||||
"process_id": pick_pid_placeholder,
|
||||
}),
|
||||
tcp_connection: None,
|
||||
}
|
||||
.to_scenario(),
|
||||
SharedTaskContext::default(),
|
||||
None,
|
||||
None,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
})
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
let attach_modal = workspace
|
||||
.update(cx, |workspace, _window, cx| {
|
||||
workspace.active_modal::<AttachModal>(cx)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
attach_modal.is_some(),
|
||||
"Attach modal should open when config contains ZED_PICK_PID"
|
||||
);
|
||||
|
||||
let attach_modal = attach_modal.unwrap();
|
||||
|
||||
workspace
|
||||
.update(cx, |_, window, cx| {
|
||||
attach_modal.update(cx, |modal, cx| {
|
||||
attach_modal::set_candidates(
|
||||
modal,
|
||||
vec![
|
||||
Candidate {
|
||||
pid: 10,
|
||||
name: "process-1".into(),
|
||||
command: vec![],
|
||||
},
|
||||
Candidate {
|
||||
pid: 42,
|
||||
name: "target-process".into(),
|
||||
command: vec![],
|
||||
},
|
||||
Candidate {
|
||||
pid: 99,
|
||||
name: "process-3".into(),
|
||||
command: vec![],
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
window,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
workspace
|
||||
.update(cx, |_, window, cx| {
|
||||
attach_modal.update(cx, |modal, cx| {
|
||||
modal.picker.update(cx, |picker, cx| {
|
||||
picker.set_query("target", window, cx);
|
||||
})
|
||||
})
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
workspace
|
||||
.update(cx, |_, _, cx| {
|
||||
let names = attach_modal.update(cx, |modal, cx| attach_modal::process_names(modal, cx));
|
||||
assert_eq!(names.len(), 1);
|
||||
assert_eq!(names[0], " 42 target-process");
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
cx.dispatch_action(Confirm);
|
||||
cx.run_until_parked();
|
||||
|
||||
workspace
|
||||
.update(cx, |workspace, _window, cx| {
|
||||
assert!(
|
||||
workspace.active_modal::<AttachModal>(cx).is_none(),
|
||||
"Attach modal should be dismissed after selection"
|
||||
);
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
1095
crates/debugger_ui/src/tests/console.rs
Normal file
1095
crates/debugger_ui/src/tests/console.rs
Normal file
File diff suppressed because it is too large
Load Diff
118
crates/debugger_ui/src/tests/dap_logger.rs
Normal file
118
crates/debugger_ui/src/tests/dap_logger.rs
Normal file
@@ -0,0 +1,118 @@
|
||||
#![expect(clippy::result_large_err)]
|
||||
use crate::tests::{init_test, init_test_workspace, start_debug_session};
|
||||
use dap::requests::{StackTrace, Threads};
|
||||
use debugger_tools::LogStore;
|
||||
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
|
||||
use project::Project;
|
||||
use serde_json::json;
|
||||
use std::cell::OnceCell;
|
||||
use util::path;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_dap_logger_captures_all_session_rpc_messages(
|
||||
executor: BackgroundExecutor,
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
let log_store_cell = std::rc::Rc::new(OnceCell::new());
|
||||
|
||||
cx.update(|cx| {
|
||||
let log_store_cell = log_store_cell.clone();
|
||||
cx.observe_new::<LogStore>(move |_, _, cx| {
|
||||
log_store_cell.set(cx.entity()).unwrap();
|
||||
})
|
||||
.detach();
|
||||
debugger_tools::init(cx);
|
||||
});
|
||||
init_test(cx);
|
||||
|
||||
let log_store = log_store_cell.get().unwrap().clone();
|
||||
|
||||
// Create a filesystem with a simple project
|
||||
let fs = project::FakeFs::new(executor.clone());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"main.rs": "fn main() {\n println!(\"Hello, world!\");\n}"
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
assert!(
|
||||
log_store.read_with(cx, |log_store, _| !log_store.has_projects()),
|
||||
"log_store shouldn't contain any projects before any projects were created"
|
||||
);
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
assert!(
|
||||
log_store.read_with(cx, |log_store, _| log_store.has_projects()),
|
||||
"log_store shouldn't contain any projects before any projects were created"
|
||||
);
|
||||
assert!(
|
||||
log_store.read_with(cx, |log_store, _| log_store
|
||||
.contained_session_ids(&project.downgrade())
|
||||
.is_empty()),
|
||||
"log_store shouldn't contain any projects before any projects were created"
|
||||
);
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
// Start a debug session
|
||||
let session = start_debug_session(&workspace, cx, |_| {}).unwrap();
|
||||
let session_id = session.read_with(cx, |session, _| session.session_id());
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
assert_eq!(
|
||||
log_store.read_with(cx, |log_store, _| log_store
|
||||
.contained_session_ids(&project.downgrade())
|
||||
.len()),
|
||||
1,
|
||||
);
|
||||
|
||||
assert!(
|
||||
log_store.read_with(cx, |log_store, _| log_store
|
||||
.contained_session_ids(&project.downgrade())
|
||||
.contains(&session_id)),
|
||||
"log_store should contain the session IDs of the started session"
|
||||
);
|
||||
|
||||
assert!(
|
||||
!log_store.read_with(cx, |log_store, _| log_store
|
||||
.rpc_messages_for_session_id(&project.downgrade(), session_id)
|
||||
.is_empty()),
|
||||
"We should have the initialization sequence in the log store"
|
||||
);
|
||||
|
||||
// Set up basic responses for common requests
|
||||
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,
|
||||
})
|
||||
});
|
||||
|
||||
// Run until all pending tasks are executed
|
||||
cx.run_until_parked();
|
||||
|
||||
// Simulate a stopped event to generate more DAP messages
|
||||
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;
|
||||
}
|
||||
2557
crates/debugger_ui/src/tests/debugger_panel.rs
Normal file
2557
crates/debugger_ui/src/tests/debugger_panel.rs
Normal file
File diff suppressed because it is too large
Load Diff
2523
crates/debugger_ui/src/tests/inline_values.rs
Normal file
2523
crates/debugger_ui/src/tests/inline_values.rs
Normal file
File diff suppressed because it is too large
Load Diff
217
crates/debugger_ui/src/tests/module_list.rs
Normal file
217
crates/debugger_ui/src/tests/module_list.rs
Normal file
@@ -0,0 +1,217 @@
|
||||
#![expect(clippy::result_large_err)]
|
||||
use crate::{
|
||||
debugger_panel::DebugPanel,
|
||||
persistence::DebuggerPaneItem,
|
||||
tests::{active_debug_session_panel, init_test, init_test_workspace, start_debug_session},
|
||||
};
|
||||
use dap::{
|
||||
StoppedEvent,
|
||||
requests::{Initialize, Modules},
|
||||
};
|
||||
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
|
||||
use project::{FakeFs, Project};
|
||||
use std::sync::{
|
||||
Arc,
|
||||
atomic::{AtomicBool, AtomicI32, Ordering},
|
||||
};
|
||||
use util::path;
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_module_list(executor: BackgroundExecutor, cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(executor.clone());
|
||||
|
||||
let project = Project::test(fs, [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, |client| {
|
||||
client.on_request::<Initialize, _>(move |_, _| {
|
||||
Ok(dap::Capabilities {
|
||||
supports_modules_request: Some(true),
|
||||
..Default::default()
|
||||
})
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
let called_modules = Arc::new(AtomicBool::new(false));
|
||||
let modules = vec![
|
||||
dap::Module {
|
||||
id: dap::ModuleId::Number(1),
|
||||
name: "First Module".into(),
|
||||
address_range: None,
|
||||
date_time_stamp: None,
|
||||
path: None,
|
||||
symbol_file_path: None,
|
||||
symbol_status: None,
|
||||
version: None,
|
||||
is_optimized: None,
|
||||
is_user_code: None,
|
||||
},
|
||||
dap::Module {
|
||||
id: dap::ModuleId::Number(2),
|
||||
name: "Second Module".into(),
|
||||
address_range: None,
|
||||
date_time_stamp: None,
|
||||
path: None,
|
||||
symbol_file_path: None,
|
||||
symbol_status: None,
|
||||
version: None,
|
||||
is_optimized: None,
|
||||
is_user_code: None,
|
||||
},
|
||||
];
|
||||
|
||||
client.on_request::<Modules, _>({
|
||||
let called_modules = called_modules.clone();
|
||||
let modules_request_count = AtomicI32::new(0);
|
||||
let modules = modules.clone();
|
||||
move |_, _| {
|
||||
modules_request_count.fetch_add(1, Ordering::SeqCst);
|
||||
assert_eq!(
|
||||
1,
|
||||
modules_request_count.load(Ordering::SeqCst),
|
||||
"This request should only be called once from the host"
|
||||
);
|
||||
called_modules.store(true, Ordering::SeqCst);
|
||||
|
||||
Ok(dap::ModulesResponse {
|
||||
modules: modules.clone(),
|
||||
total_modules: Some(2u64),
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Stopped(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 running_state =
|
||||
active_debug_session_panel(workspace, cx).update_in(cx, |item, window, cx| {
|
||||
cx.focus_self(window);
|
||||
item.running_state().clone()
|
||||
});
|
||||
|
||||
running_state.update_in(cx, |this, window, cx| {
|
||||
this.activate_item(DebuggerPaneItem::Modules, window, cx);
|
||||
cx.refresh_windows();
|
||||
});
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
assert!(
|
||||
called_modules.load(std::sync::atomic::Ordering::SeqCst),
|
||||
"Request Modules should be called because a user clicked on the module list"
|
||||
);
|
||||
|
||||
active_debug_session_panel(workspace, cx).update(cx, |_, cx| {
|
||||
let actual_modules = running_state.update(cx, |state, cx| {
|
||||
state.module_list().update(cx, |list, cx| list.modules(cx))
|
||||
});
|
||||
|
||||
assert_eq!(modules, actual_modules);
|
||||
});
|
||||
|
||||
// Test all module events now
|
||||
// New Module
|
||||
// Changed
|
||||
// Removed
|
||||
|
||||
let new_module = dap::Module {
|
||||
id: dap::ModuleId::Number(3),
|
||||
name: "Third Module".into(),
|
||||
address_range: None,
|
||||
date_time_stamp: None,
|
||||
path: None,
|
||||
symbol_file_path: None,
|
||||
symbol_status: None,
|
||||
version: None,
|
||||
is_optimized: None,
|
||||
is_user_code: None,
|
||||
};
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Module(dap::ModuleEvent {
|
||||
reason: dap::ModuleEventReason::New,
|
||||
module: new_module.clone(),
|
||||
}))
|
||||
.await;
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
active_debug_session_panel(workspace, cx).update(cx, |_, cx| {
|
||||
let actual_modules = running_state.update(cx, |state, cx| {
|
||||
state.module_list().update(cx, |list, cx| list.modules(cx))
|
||||
});
|
||||
assert_eq!(actual_modules.len(), 3);
|
||||
assert!(actual_modules.contains(&new_module));
|
||||
});
|
||||
|
||||
let changed_module = dap::Module {
|
||||
id: dap::ModuleId::Number(2),
|
||||
name: "Modified Second Module".into(),
|
||||
address_range: None,
|
||||
date_time_stamp: None,
|
||||
path: None,
|
||||
symbol_file_path: None,
|
||||
symbol_status: None,
|
||||
version: None,
|
||||
is_optimized: None,
|
||||
is_user_code: None,
|
||||
};
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Module(dap::ModuleEvent {
|
||||
reason: dap::ModuleEventReason::Changed,
|
||||
module: changed_module.clone(),
|
||||
}))
|
||||
.await;
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
active_debug_session_panel(workspace, cx).update(cx, |_, cx| {
|
||||
let actual_modules = running_state.update(cx, |state, cx| {
|
||||
state.module_list().update(cx, |list, cx| list.modules(cx))
|
||||
});
|
||||
|
||||
assert_eq!(actual_modules.len(), 3);
|
||||
assert!(actual_modules.contains(&changed_module));
|
||||
});
|
||||
|
||||
client
|
||||
.fake_event(dap::messages::Events::Module(dap::ModuleEvent {
|
||||
reason: dap::ModuleEventReason::Removed,
|
||||
module: changed_module.clone(),
|
||||
}))
|
||||
.await;
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
active_debug_session_panel(workspace, cx).update(cx, |_, cx| {
|
||||
let actual_modules = running_state.update(cx, |state, cx| {
|
||||
state.module_list().update(cx, |list, cx| list.modules(cx))
|
||||
});
|
||||
|
||||
assert_eq!(actual_modules.len(), 2);
|
||||
assert!(!actual_modules.contains(&changed_module));
|
||||
});
|
||||
}
|
||||
448
crates/debugger_ui/src/tests/new_process_modal.rs
Normal file
448
crates/debugger_ui/src/tests/new_process_modal.rs
Normal file
@@ -0,0 +1,448 @@
|
||||
#![expect(clippy::result_large_err)]
|
||||
use dap::DapRegistry;
|
||||
use editor::Editor;
|
||||
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
|
||||
use project::{FakeFs, Fs as _, Project};
|
||||
use serde_json::json;
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use task::{
|
||||
DebugRequest, DebugScenario, LaunchRequest, SharedTaskContext, TaskContext, VariableName,
|
||||
ZedDebugConfig,
|
||||
};
|
||||
use text::Point;
|
||||
use util::path;
|
||||
|
||||
use crate::NewProcessMode;
|
||||
use crate::new_process_modal::NewProcessModal;
|
||||
use crate::tests::{init_test, init_test_workspace};
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_debug_session_substitutes_variables_and_relativizes_paths(
|
||||
executor: BackgroundExecutor,
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(executor.clone());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"main.rs": "fn main() {}"
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
let test_variables = vec![(
|
||||
VariableName::WorktreeRoot,
|
||||
path!("/test/worktree/path").to_string(),
|
||||
)]
|
||||
.into_iter()
|
||||
.collect();
|
||||
|
||||
let task_context: SharedTaskContext = TaskContext {
|
||||
cwd: None,
|
||||
task_variables: test_variables,
|
||||
project_env: Default::default(),
|
||||
}
|
||||
.into();
|
||||
|
||||
let home_dir = paths::home_dir();
|
||||
|
||||
let test_cases: Vec<(&'static str, &'static str)> = vec![
|
||||
// Absolute path - should not be relativized
|
||||
(
|
||||
path!("/absolute/path/to/program"),
|
||||
path!("/absolute/path/to/program"),
|
||||
),
|
||||
// Relative path - should be prefixed with worktree root
|
||||
(
|
||||
format!(".{0}src{0}program", std::path::MAIN_SEPARATOR).leak(),
|
||||
path!("/test/worktree/path/src/program"),
|
||||
),
|
||||
// Home directory path - should be expanded to full home directory path
|
||||
(
|
||||
format!("~{0}src{0}program", std::path::MAIN_SEPARATOR).leak(),
|
||||
home_dir
|
||||
.join("src")
|
||||
.join("program")
|
||||
.to_string_lossy()
|
||||
.to_string()
|
||||
.leak(),
|
||||
),
|
||||
// Path with $ZED_WORKTREE_ROOT - should be substituted without double appending
|
||||
(
|
||||
format!(
|
||||
"$ZED_WORKTREE_ROOT{0}src{0}program",
|
||||
std::path::MAIN_SEPARATOR
|
||||
)
|
||||
.leak(),
|
||||
path!("/test/worktree/path/src/program"),
|
||||
),
|
||||
];
|
||||
|
||||
let called_launch = Arc::new(AtomicBool::new(false));
|
||||
|
||||
for (input_path, expected_path) in test_cases {
|
||||
let _subscription = project::debugger::test::intercept_debug_sessions(cx, {
|
||||
let called_launch = called_launch.clone();
|
||||
move |client| {
|
||||
client.on_request::<dap::requests::Launch, _>({
|
||||
let called_launch = called_launch.clone();
|
||||
|
||||
move |_, args| {
|
||||
let config = args.raw.as_object().unwrap();
|
||||
|
||||
assert_eq!(
|
||||
config["program"].as_str().unwrap(),
|
||||
expected_path,
|
||||
"Program path was not correctly substituted for input: {}",
|
||||
input_path
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
config["cwd"].as_str().unwrap(),
|
||||
expected_path,
|
||||
"CWD path was not correctly substituted for input: {}",
|
||||
input_path
|
||||
);
|
||||
|
||||
let expected_other_field = if input_path.contains("$ZED_WORKTREE_ROOT") {
|
||||
input_path.replace("$ZED_WORKTREE_ROOT", path!("/test/worktree/path"))
|
||||
} else {
|
||||
input_path.to_string()
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
config["otherField"].as_str().unwrap(),
|
||||
&expected_other_field,
|
||||
"Other field was incorrectly modified for input: {}",
|
||||
input_path
|
||||
);
|
||||
|
||||
called_launch.store(true, Ordering::SeqCst);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
let scenario = DebugScenario {
|
||||
adapter: "fake-adapter".into(),
|
||||
label: "test-debug-session".into(),
|
||||
build: None,
|
||||
config: json!({
|
||||
"request": "launch",
|
||||
"program": input_path,
|
||||
"cwd": input_path,
|
||||
"otherField": input_path
|
||||
}),
|
||||
tcp_connection: None,
|
||||
};
|
||||
|
||||
workspace
|
||||
.update(cx, |multi, window, cx| {
|
||||
multi.workspace().update(cx, |workspace, cx| {
|
||||
workspace.start_debug_session(
|
||||
scenario,
|
||||
task_context.clone(),
|
||||
None,
|
||||
None,
|
||||
window,
|
||||
cx,
|
||||
);
|
||||
})
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
assert!(called_launch.load(Ordering::SeqCst));
|
||||
called_launch.store(false, Ordering::SeqCst);
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_save_debug_scenario_to_file(executor: BackgroundExecutor, cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(executor.clone());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"main.rs": "fn main() {}"
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
workspace
|
||||
.update(cx, |multi, window, cx| {
|
||||
multi.workspace().update(cx, |workspace, cx| {
|
||||
NewProcessModal::show(workspace, window, NewProcessMode::Debug, None, cx);
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
let modal = workspace
|
||||
.update(cx, |workspace, _, cx| {
|
||||
workspace.active_modal::<NewProcessModal>(cx)
|
||||
})
|
||||
.unwrap()
|
||||
.expect("Modal should be active");
|
||||
|
||||
modal.update_in(cx, |modal, window, cx| {
|
||||
modal.set_configure("/project/main", "/project", false, window, cx);
|
||||
modal.save_debug_scenario(window, cx);
|
||||
});
|
||||
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
let editor = workspace
|
||||
.update(cx, |workspace, _window, cx| {
|
||||
workspace.active_item_as::<Editor>(cx).unwrap()
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let debug_json_content = fs
|
||||
.load(path!("/project/.zed/debug.json").as_ref())
|
||||
.await
|
||||
.expect("debug.json should exist")
|
||||
.lines()
|
||||
.filter(|line| !line.starts_with("//"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
|
||||
let expected_content = indoc::indoc! {r#"
|
||||
[
|
||||
{
|
||||
"adapter": "fake-adapter",
|
||||
"label": "main (fake-adapter)",
|
||||
"request": "launch",
|
||||
"program": "/project/main",
|
||||
"cwd": "/project",
|
||||
"args": [],
|
||||
"env": {}
|
||||
}
|
||||
]"#};
|
||||
|
||||
pretty_assertions::assert_eq!(expected_content, debug_json_content);
|
||||
|
||||
editor.update(cx, |editor, cx| {
|
||||
assert_eq!(
|
||||
editor
|
||||
.selections
|
||||
.newest::<Point>(&editor.display_snapshot(cx))
|
||||
.head(),
|
||||
Point::new(5, 2)
|
||||
)
|
||||
});
|
||||
|
||||
modal.update_in(cx, |modal, window, cx| {
|
||||
modal.set_configure("/project/other", "/project", true, window, cx);
|
||||
modal.save_debug_scenario(window, cx);
|
||||
});
|
||||
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
let expected_content = indoc::indoc! {r#"
|
||||
[
|
||||
{
|
||||
"adapter": "fake-adapter",
|
||||
"label": "main (fake-adapter)",
|
||||
"request": "launch",
|
||||
"program": "/project/main",
|
||||
"cwd": "/project",
|
||||
"args": [],
|
||||
"env": {}
|
||||
},
|
||||
{
|
||||
"adapter": "fake-adapter",
|
||||
"label": "other (fake-adapter)",
|
||||
"request": "launch",
|
||||
"program": "/project/other",
|
||||
"cwd": "/project",
|
||||
"args": [],
|
||||
"env": {}
|
||||
}
|
||||
]"#};
|
||||
|
||||
let debug_json_content = fs
|
||||
.load(path!("/project/.zed/debug.json").as_ref())
|
||||
.await
|
||||
.expect("debug.json should exist")
|
||||
.lines()
|
||||
.filter(|line| !line.starts_with("//"))
|
||||
.collect::<Vec<_>>()
|
||||
.join("\n");
|
||||
pretty_assertions::assert_eq!(expected_content, debug_json_content);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_debug_modal_subtitles_with_multiple_worktrees(
|
||||
executor: BackgroundExecutor,
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(executor.clone());
|
||||
|
||||
fs.insert_tree(
|
||||
path!("/workspace1"),
|
||||
json!({
|
||||
".zed": {
|
||||
"debug.json": r#"[
|
||||
{
|
||||
"adapter": "fake-adapter",
|
||||
"label": "Debug App 1",
|
||||
"request": "launch",
|
||||
"program": "./app1",
|
||||
"cwd": "."
|
||||
},
|
||||
{
|
||||
"adapter": "fake-adapter",
|
||||
"label": "Debug Tests 1",
|
||||
"request": "launch",
|
||||
"program": "./test1",
|
||||
"cwd": "."
|
||||
}
|
||||
]"#
|
||||
},
|
||||
"main.rs": "fn main() {}"
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs.clone(), [path!("/workspace1").as_ref()], cx).await;
|
||||
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
workspace
|
||||
.update(cx, |multi, window, cx| {
|
||||
multi.workspace().update(cx, |workspace, cx| {
|
||||
NewProcessModal::show(workspace, window, NewProcessMode::Debug, None, cx);
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
let modal = workspace
|
||||
.update(cx, |workspace, _, cx| {
|
||||
workspace.active_modal::<NewProcessModal>(cx)
|
||||
})
|
||||
.unwrap()
|
||||
.expect("Modal should be active");
|
||||
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
let subtitles = modal.update_in(cx, |modal, _, cx| {
|
||||
modal.debug_picker_candidate_subtitles(cx)
|
||||
});
|
||||
|
||||
assert_eq!(
|
||||
subtitles.as_slice(),
|
||||
[path!(".zed/debug.json"), path!(".zed/debug.json")]
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_dap_adapter_config_conversion_and_validation(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
|
||||
let mut expected_adapters = vec![
|
||||
"CodeLLDB",
|
||||
"Debugpy",
|
||||
"JavaScript",
|
||||
"Delve",
|
||||
"GDB",
|
||||
"fake-adapter",
|
||||
];
|
||||
|
||||
let adapter_names = cx.update(|cx| {
|
||||
let registry = DapRegistry::global(cx);
|
||||
registry.enumerate_adapters::<Vec<_>>()
|
||||
});
|
||||
|
||||
let zed_config = ZedDebugConfig {
|
||||
label: "test_debug_session".into(),
|
||||
adapter: "test_adapter".into(),
|
||||
request: DebugRequest::Launch(LaunchRequest {
|
||||
program: "test_program".into(),
|
||||
cwd: None,
|
||||
args: vec![],
|
||||
env: Default::default(),
|
||||
}),
|
||||
stop_on_entry: Some(true),
|
||||
};
|
||||
|
||||
for adapter_name in adapter_names {
|
||||
let adapter_str = adapter_name.to_string();
|
||||
if let Some(pos) = expected_adapters.iter().position(|&x| x == adapter_str) {
|
||||
expected_adapters.remove(pos);
|
||||
}
|
||||
|
||||
let adapter = cx
|
||||
.update(|cx| {
|
||||
let registry = DapRegistry::global(cx);
|
||||
registry.adapter(adapter_name.as_ref())
|
||||
})
|
||||
.unwrap_or_else(|| panic!("Adapter {} should exist", adapter_name));
|
||||
|
||||
let mut adapter_specific_config = zed_config.clone();
|
||||
adapter_specific_config.adapter = adapter_name.to_string().into();
|
||||
|
||||
let debug_scenario = adapter
|
||||
.config_from_zed_format(adapter_specific_config)
|
||||
.await
|
||||
.unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"Adapter {} should successfully convert from Zed format",
|
||||
adapter_name
|
||||
)
|
||||
});
|
||||
|
||||
assert!(
|
||||
debug_scenario.config.is_object(),
|
||||
"Adapter {} should produce a JSON object for config",
|
||||
adapter_name
|
||||
);
|
||||
|
||||
let request_type = adapter
|
||||
.request_kind(&debug_scenario.config)
|
||||
.await
|
||||
.unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"Adapter {} should validate the config successfully",
|
||||
adapter_name
|
||||
)
|
||||
});
|
||||
|
||||
match request_type {
|
||||
dap::StartDebuggingRequestArgumentsRequest::Launch => {}
|
||||
dap::StartDebuggingRequestArgumentsRequest::Attach => {
|
||||
panic!(
|
||||
"Expected Launch request but got Attach for adapter {}",
|
||||
adapter_name
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert!(
|
||||
expected_adapters.is_empty(),
|
||||
"The following expected adapters were not found in the registry: {:?}",
|
||||
expected_adapters
|
||||
);
|
||||
}
|
||||
132
crates/debugger_ui/src/tests/persistence.rs
Normal file
132
crates/debugger_ui/src/tests/persistence.rs
Normal file
@@ -0,0 +1,132 @@
|
||||
#![expect(clippy::result_large_err)]
|
||||
use std::iter::zip;
|
||||
|
||||
use crate::{
|
||||
debugger_panel::DebugPanel,
|
||||
persistence::SerializedPaneLayout,
|
||||
tests::{init_test, init_test_workspace, start_debug_session},
|
||||
};
|
||||
use dap::{StoppedEvent, StoppedEventReason, messages::Events};
|
||||
use gpui::{BackgroundExecutor, TestAppContext, VisualTestContext};
|
||||
use project::{FakeFs, Project};
|
||||
use serde_json::json;
|
||||
use util::path;
|
||||
use workspace::{Panel, dock::DockPosition};
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_invert_axis_on_panel_position_change(
|
||||
executor: BackgroundExecutor,
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
init_test(cx);
|
||||
|
||||
let fs = FakeFs::new(executor.clone());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"main.rs": "fn main() {\n println!(\"Hello, world!\");\n}",
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let workspace = init_test_workspace(&project, cx).await;
|
||||
let cx = &mut VisualTestContext::from_window(*workspace, cx);
|
||||
|
||||
// Start a debug session
|
||||
let session = start_debug_session(&workspace, cx, |_| {}).unwrap();
|
||||
let client = session.update(cx, |session, _| session.adapter_client().unwrap());
|
||||
|
||||
// Setup thread response
|
||||
client.on_request::<dap::requests::Threads, _>(move |_, _| {
|
||||
Ok(dap::ThreadsResponse { threads: vec![] })
|
||||
});
|
||||
|
||||
cx.run_until_parked();
|
||||
|
||||
client
|
||||
.fake_event(Events::Stopped(StoppedEvent {
|
||||
reason: 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 (debug_panel, dock_position) = workspace
|
||||
.update(cx, |workspace, window, cx| {
|
||||
let debug_panel = workspace.panel::<DebugPanel>(cx).unwrap();
|
||||
let dock_position = debug_panel.read(cx).position(window, cx);
|
||||
(debug_panel, dock_position)
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
dock_position,
|
||||
DockPosition::Bottom,
|
||||
"Default dock position should be bottom for debug panel"
|
||||
);
|
||||
|
||||
let pre_serialized_layout = debug_panel
|
||||
.read_with(cx, |panel, cx| {
|
||||
panel
|
||||
.active_session()
|
||||
.unwrap()
|
||||
.read(cx)
|
||||
.running_state()
|
||||
.read(cx)
|
||||
.serialized_layout(cx)
|
||||
})
|
||||
.panes;
|
||||
|
||||
let post_serialized_layout = debug_panel
|
||||
.update_in(cx, |panel, window, cx| {
|
||||
panel.set_position(DockPosition::Right, window, cx);
|
||||
|
||||
panel
|
||||
.active_session()
|
||||
.unwrap()
|
||||
.read(cx)
|
||||
.running_state()
|
||||
.read(cx)
|
||||
.serialized_layout(cx)
|
||||
})
|
||||
.panes;
|
||||
|
||||
let pre_panes = pre_serialized_layout.in_order();
|
||||
let post_panes = post_serialized_layout.in_order();
|
||||
|
||||
assert_eq!(pre_panes.len(), post_panes.len());
|
||||
|
||||
for (pre, post) in zip(pre_panes, post_panes) {
|
||||
match (pre, post) {
|
||||
(
|
||||
SerializedPaneLayout::Group {
|
||||
axis: pre_axis,
|
||||
flexes: pre_flexes,
|
||||
children: _,
|
||||
},
|
||||
SerializedPaneLayout::Group {
|
||||
axis: post_axis,
|
||||
flexes: post_flexes,
|
||||
children: _,
|
||||
},
|
||||
) => {
|
||||
assert_ne!(pre_axis, post_axis);
|
||||
assert_eq!(pre_flexes, post_flexes);
|
||||
}
|
||||
(SerializedPaneLayout::Pane(pre_pane), SerializedPaneLayout::Pane(post_pane)) => {
|
||||
assert_eq!(pre_pane.children, post_pane.children);
|
||||
assert_eq!(pre_pane.active_item, post_pane.active_item);
|
||||
}
|
||||
_ => {
|
||||
panic!("Variants don't match")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1272
crates/debugger_ui/src/tests/stack_frame_list.rs
Normal file
1272
crates/debugger_ui/src/tests/stack_frame_list.rs
Normal file
File diff suppressed because it is too large
Load Diff
2343
crates/debugger_ui/src/tests/variable_list.rs
Normal file
2343
crates/debugger_ui/src/tests/variable_list.rs
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user