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:
685
crates/project/tests/integration/bookmark_store.rs
Normal file
685
crates/project/tests/integration/bookmark_store.rs
Normal file
@@ -0,0 +1,685 @@
|
||||
use std::{path::Path, sync::Arc};
|
||||
|
||||
use collections::BTreeMap;
|
||||
use gpui::{Entity, TestAppContext};
|
||||
use language::Buffer;
|
||||
use project::{Project, bookmark_store::SerializedBookmark};
|
||||
use serde_json::json;
|
||||
use util::path;
|
||||
|
||||
mod integration {
|
||||
use super::*;
|
||||
use fs::Fs as _;
|
||||
|
||||
fn init_test(cx: &mut TestAppContext) {
|
||||
cx.update(|cx| {
|
||||
let settings_store = settings::SettingsStore::test(cx);
|
||||
cx.set_global(settings_store);
|
||||
release_channel::init(semver::Version::new(0, 0, 0), cx);
|
||||
});
|
||||
}
|
||||
|
||||
fn project_path(path: &str) -> Arc<Path> {
|
||||
Arc::from(Path::new(path))
|
||||
}
|
||||
|
||||
async fn open_buffer(
|
||||
project: &Entity<Project>,
|
||||
path: &str,
|
||||
cx: &mut TestAppContext,
|
||||
) -> Entity<Buffer> {
|
||||
project
|
||||
.update(cx, |project, cx| {
|
||||
project.open_local_buffer(Path::new(path), cx)
|
||||
})
|
||||
.await
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
fn add_bookmarks(
|
||||
project: &Entity<Project>,
|
||||
buffer: &Entity<Buffer>,
|
||||
rows: &[u32],
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
let buffer = buffer.clone();
|
||||
project.update(cx, |project, cx| {
|
||||
let bookmark_store = project.bookmark_store();
|
||||
let snapshot = buffer.read(cx).snapshot();
|
||||
for &row in rows {
|
||||
let anchor = snapshot.anchor_after(text::Point::new(row, 0));
|
||||
bookmark_store.update(cx, |store, cx| {
|
||||
store.toggle_bookmark(buffer.clone(), anchor, cx);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn get_all_bookmarks(
|
||||
project: &Entity<Project>,
|
||||
cx: &mut TestAppContext,
|
||||
) -> BTreeMap<Arc<Path>, Vec<SerializedBookmark>> {
|
||||
project.read_with(cx, |project, cx| {
|
||||
project
|
||||
.bookmark_store()
|
||||
.read(cx)
|
||||
.all_serialized_bookmarks(cx)
|
||||
})
|
||||
}
|
||||
|
||||
fn build_serialized(
|
||||
entries: &[(&str, &[u32])],
|
||||
) -> BTreeMap<Arc<Path>, Vec<SerializedBookmark>> {
|
||||
let mut map = BTreeMap::new();
|
||||
for &(path_str, rows) in entries {
|
||||
let path = project_path(path_str);
|
||||
map.insert(
|
||||
path.clone(),
|
||||
rows.iter().map(|&row| SerializedBookmark(row)).collect(),
|
||||
);
|
||||
}
|
||||
map
|
||||
}
|
||||
|
||||
async fn restore_bookmarks(
|
||||
project: &Entity<Project>,
|
||||
serialized: BTreeMap<Arc<Path>, Vec<SerializedBookmark>>,
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
project
|
||||
.update(cx, |project, cx| {
|
||||
project.bookmark_store().update(cx, |store, cx| {
|
||||
store.load_serialized_bookmarks(serialized, cx)
|
||||
})
|
||||
})
|
||||
.await
|
||||
.expect("with_serialized_bookmarks should succeed");
|
||||
}
|
||||
|
||||
fn clear_bookmarks(project: &Entity<Project>, cx: &mut TestAppContext) {
|
||||
project.update(cx, |project, cx| {
|
||||
project.bookmark_store().update(cx, |store, cx| {
|
||||
store.clear_bookmarks(cx);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn assert_bookmark_rows(
|
||||
bookmarks: &BTreeMap<Arc<Path>, Vec<SerializedBookmark>>,
|
||||
path: &str,
|
||||
expected_rows: &[u32],
|
||||
) {
|
||||
let path = project_path(path);
|
||||
let file_bookmarks = bookmarks
|
||||
.get(&path)
|
||||
.unwrap_or_else(|| panic!("Expected bookmarks for {}", path.display()));
|
||||
let rows: Vec<u32> = file_bookmarks.iter().map(|b| b.0).collect();
|
||||
assert_eq!(rows, expected_rows, "Bookmark rows for {}", path.display());
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_all_serialized_bookmarks_empty(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(path!("/project"), json!({"file1.rs": "line1\nline2\n"}))
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
assert!(get_all_bookmarks(&project, cx).is_empty());
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_all_serialized_bookmarks_single_file(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({"file1.rs": "line1\nline2\nline3\nline4\nline5\n"}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let buffer = open_buffer(&project, path!("/project/file1.rs"), cx).await;
|
||||
|
||||
add_bookmarks(&project, &buffer, &[0, 2], cx);
|
||||
|
||||
let bookmarks = get_all_bookmarks(&project, cx);
|
||||
assert_eq!(bookmarks.len(), 1);
|
||||
assert_bookmark_rows(&bookmarks, path!("/project/file1.rs"), &[0, 2]);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_all_serialized_bookmarks_multiple_files(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"file1.rs": "line1\nline2\nline3\n",
|
||||
"file2.rs": "lineA\nlineB\nlineC\nlineD\n",
|
||||
"file3.rs": "single line"
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let buffer1 = open_buffer(&project, path!("/project/file1.rs"), cx).await;
|
||||
let buffer2 = open_buffer(&project, path!("/project/file2.rs"), cx).await;
|
||||
let _buffer3 = open_buffer(&project, path!("/project/file3.rs"), cx).await;
|
||||
|
||||
add_bookmarks(&project, &buffer1, &[1], cx);
|
||||
add_bookmarks(&project, &buffer2, &[0, 3], cx);
|
||||
|
||||
let bookmarks = get_all_bookmarks(&project, cx);
|
||||
assert_eq!(bookmarks.len(), 2);
|
||||
assert_bookmark_rows(&bookmarks, path!("/project/file1.rs"), &[1]);
|
||||
assert_bookmark_rows(&bookmarks, path!("/project/file2.rs"), &[0, 3]);
|
||||
assert!(
|
||||
!bookmarks.contains_key(&project_path(path!("/project/file3.rs"))),
|
||||
"file3.rs should have no bookmarks"
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_all_serialized_bookmarks_after_toggle_off(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({"file1.rs": "line1\nline2\nline3\n"}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let buffer = open_buffer(&project, path!("/project/file1.rs"), cx).await;
|
||||
|
||||
add_bookmarks(&project, &buffer, &[1], cx);
|
||||
assert_eq!(get_all_bookmarks(&project, cx).len(), 1);
|
||||
|
||||
// Toggle same row again to remove it
|
||||
add_bookmarks(&project, &buffer, &[1], cx);
|
||||
assert!(get_all_bookmarks(&project, cx).is_empty());
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_all_serialized_bookmarks_with_clear(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"file1.rs": "line1\nline2\nline3\n",
|
||||
"file2.rs": "lineA\nlineB\n"
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let buffer1 = open_buffer(&project, path!("/project/file1.rs"), cx).await;
|
||||
let buffer2 = open_buffer(&project, path!("/project/file2.rs"), cx).await;
|
||||
|
||||
add_bookmarks(&project, &buffer1, &[0], cx);
|
||||
add_bookmarks(&project, &buffer2, &[1], cx);
|
||||
assert_eq!(get_all_bookmarks(&project, cx).len(), 2);
|
||||
|
||||
clear_bookmarks(&project, cx);
|
||||
assert!(get_all_bookmarks(&project, cx).is_empty());
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_all_serialized_bookmarks_returns_sorted_by_path(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({"b.rs": "line1\n", "a.rs": "line1\n", "c.rs": "line1\n"}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let buffer_b = open_buffer(&project, path!("/project/b.rs"), cx).await;
|
||||
let buffer_a = open_buffer(&project, path!("/project/a.rs"), cx).await;
|
||||
let buffer_c = open_buffer(&project, path!("/project/c.rs"), cx).await;
|
||||
|
||||
add_bookmarks(&project, &buffer_b, &[0], cx);
|
||||
add_bookmarks(&project, &buffer_a, &[0], cx);
|
||||
add_bookmarks(&project, &buffer_c, &[0], cx);
|
||||
|
||||
let paths: Vec<_> = get_all_bookmarks(&project, cx).keys().cloned().collect();
|
||||
assert_eq!(
|
||||
paths,
|
||||
[
|
||||
project_path(path!("/project/a.rs")),
|
||||
project_path(path!("/project/b.rs")),
|
||||
project_path(path!("/project/c.rs")),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_all_serialized_bookmarks_deduplicates_same_row(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({"file1.rs": "line1\nline2\nline3\nline4\n"}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let buffer = open_buffer(&project, path!("/project/file1.rs"), cx).await;
|
||||
|
||||
add_bookmarks(&project, &buffer, &[1, 2], cx);
|
||||
|
||||
let bookmarks = get_all_bookmarks(&project, cx);
|
||||
assert_bookmark_rows(&bookmarks, path!("/project/file1.rs"), &[1, 2]);
|
||||
|
||||
// Verify no duplicates
|
||||
let rows: Vec<u32> = bookmarks
|
||||
.get(&project_path(path!("/project/file1.rs")))
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|b| b.0)
|
||||
.collect();
|
||||
let mut deduped = rows.clone();
|
||||
deduped.dedup();
|
||||
assert_eq!(rows, deduped);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_with_serialized_bookmarks_restores_bookmarks(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"file1.rs": "line1\nline2\nline3\nline4\nline5\n",
|
||||
"file2.rs": "aaa\nbbb\nccc\n"
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
|
||||
let serialized = build_serialized(&[
|
||||
(path!("/project/file1.rs"), &[0, 3]),
|
||||
(path!("/project/file2.rs"), &[1]),
|
||||
]);
|
||||
|
||||
restore_bookmarks(&project, serialized, cx).await;
|
||||
|
||||
let restored = get_all_bookmarks(&project, cx);
|
||||
assert_eq!(restored.len(), 2);
|
||||
assert_bookmark_rows(&restored, path!("/project/file1.rs"), &[0, 3]);
|
||||
assert_bookmark_rows(&restored, path!("/project/file2.rs"), &[1]);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_with_serialized_bookmarks_skips_out_of_range_rows(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
// 3 lines: rows 0, 1, 2
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({"file1.rs": "line1\nline2\nline3"}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
|
||||
let serialized = build_serialized(&[(path!("/project/file1.rs"), &[1, 100, 2])]);
|
||||
restore_bookmarks(&project, serialized, cx).await;
|
||||
|
||||
// Before resolution, unloaded bookmarks are stored as-is
|
||||
let unresolved = get_all_bookmarks(&project, cx);
|
||||
assert_bookmark_rows(&unresolved, path!("/project/file1.rs"), &[1, 2, 100]);
|
||||
|
||||
// Open the buffer to trigger lazy resolution
|
||||
let buffer = open_buffer(&project, path!("/project/file1.rs"), cx).await;
|
||||
project.update(cx, |project, cx| {
|
||||
let buffer_snapshot = buffer.read(cx).snapshot();
|
||||
project.bookmark_store().update(cx, |store, cx| {
|
||||
store.bookmarks_for_buffer(
|
||||
buffer.clone(),
|
||||
buffer_snapshot.anchor_before(0)
|
||||
..buffer_snapshot.anchor_after(buffer_snapshot.len()),
|
||||
&buffer_snapshot,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// After resolution, out-of-range rows are filtered
|
||||
let restored = get_all_bookmarks(&project, cx);
|
||||
assert_bookmark_rows(&restored, path!("/project/file1.rs"), &[1, 2]);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_with_serialized_bookmarks_skips_empty_entries(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({"file1.rs": "line1\nline2\n", "file2.rs": "aaa\nbbb\n"}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
|
||||
let mut serialized = build_serialized(&[(path!("/project/file1.rs"), &[0])]);
|
||||
serialized.insert(project_path(path!("/project/file2.rs")), vec![]);
|
||||
|
||||
restore_bookmarks(&project, serialized, cx).await;
|
||||
|
||||
let restored = get_all_bookmarks(&project, cx);
|
||||
assert_eq!(restored.len(), 1);
|
||||
assert!(restored.contains_key(&project_path(path!("/project/file1.rs"))));
|
||||
assert!(!restored.contains_key(&project_path(path!("/project/file2.rs"))));
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_with_serialized_bookmarks_all_out_of_range_produces_no_entry(
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(path!("/project"), json!({"tiny.rs": "x"}))
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
|
||||
let serialized = build_serialized(&[(path!("/project/tiny.rs"), &[5, 10])]);
|
||||
restore_bookmarks(&project, serialized, cx).await;
|
||||
|
||||
// Before resolution, unloaded bookmarks are stored as-is
|
||||
let unresolved = get_all_bookmarks(&project, cx);
|
||||
assert_eq!(unresolved.len(), 1);
|
||||
|
||||
// Open the buffer to trigger lazy resolution
|
||||
let buffer = open_buffer(&project, path!("/project/tiny.rs"), cx).await;
|
||||
project.update(cx, |project, cx| {
|
||||
let buffer_snapshot = buffer.read(cx).snapshot();
|
||||
project.bookmark_store().update(cx, |store, cx| {
|
||||
store.bookmarks_for_buffer(
|
||||
buffer.clone(),
|
||||
buffer_snapshot.anchor_before(0)
|
||||
..buffer_snapshot.anchor_after(buffer_snapshot.len()),
|
||||
&buffer_snapshot,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
// After resolution, all out-of-range rows are filtered away
|
||||
assert!(get_all_bookmarks(&project, cx).is_empty());
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_with_serialized_bookmarks_replaces_existing(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({"file1.rs": "aaa\nbbb\nccc\nddd\n"}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let buffer = open_buffer(&project, path!("/project/file1.rs"), cx).await;
|
||||
|
||||
add_bookmarks(&project, &buffer, &[0], cx);
|
||||
assert_bookmark_rows(
|
||||
&get_all_bookmarks(&project, cx),
|
||||
path!("/project/file1.rs"),
|
||||
&[0],
|
||||
);
|
||||
|
||||
// Restoring different bookmarks should replace, not merge
|
||||
let serialized = build_serialized(&[(path!("/project/file1.rs"), &[2, 3])]);
|
||||
restore_bookmarks(&project, serialized, cx).await;
|
||||
|
||||
let after = get_all_bookmarks(&project, cx);
|
||||
assert_eq!(after.len(), 1);
|
||||
assert_bookmark_rows(&after, path!("/project/file1.rs"), &[2, 3]);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_serialize_deserialize_round_trip(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"alpha.rs": "fn main() {\n println!(\"hello\");\n return;\n}\n",
|
||||
"beta.rs": "use std::io;\nfn read() {}\nfn write() {}\n"
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let buffer_alpha = open_buffer(&project, path!("/project/alpha.rs"), cx).await;
|
||||
let buffer_beta = open_buffer(&project, path!("/project/beta.rs"), cx).await;
|
||||
|
||||
add_bookmarks(&project, &buffer_alpha, &[0, 2, 3], cx);
|
||||
add_bookmarks(&project, &buffer_beta, &[1], cx);
|
||||
|
||||
// Serialize
|
||||
let serialized = get_all_bookmarks(&project, cx);
|
||||
assert_eq!(serialized.len(), 2);
|
||||
assert_bookmark_rows(&serialized, path!("/project/alpha.rs"), &[0, 2, 3]);
|
||||
assert_bookmark_rows(&serialized, path!("/project/beta.rs"), &[1]);
|
||||
|
||||
// Clear and restore
|
||||
clear_bookmarks(&project, cx);
|
||||
assert!(get_all_bookmarks(&project, cx).is_empty());
|
||||
|
||||
restore_bookmarks(&project, serialized, cx).await;
|
||||
|
||||
let restored = get_all_bookmarks(&project, cx);
|
||||
assert_eq!(restored.len(), 2);
|
||||
assert_bookmark_rows(&restored, path!("/project/alpha.rs"), &[0, 2, 3]);
|
||||
assert_bookmark_rows(&restored, path!("/project/beta.rs"), &[1]);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_round_trip_preserves_bookmarks_after_file_edit(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({"file.rs": "aaa\nbbb\nccc\nddd\neee\n"}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs, [path!("/project").as_ref()], cx).await;
|
||||
let buffer = open_buffer(&project, path!("/project/file.rs"), cx).await;
|
||||
|
||||
add_bookmarks(&project, &buffer, &[1, 3], cx);
|
||||
|
||||
// Insert a line at the beginning, shifting bookmarks down by 1
|
||||
buffer.update(cx, |buffer, cx| {
|
||||
buffer.edit([(0..0, "new_first_line\n")], None, cx);
|
||||
});
|
||||
|
||||
let serialized = get_all_bookmarks(&project, cx);
|
||||
assert_bookmark_rows(&serialized, path!("/project/file.rs"), &[2, 4]);
|
||||
|
||||
// Clear and restore
|
||||
clear_bookmarks(&project, cx);
|
||||
restore_bookmarks(&project, serialized, cx).await;
|
||||
|
||||
let restored = get_all_bookmarks(&project, cx);
|
||||
assert_bookmark_rows(&restored, path!("/project/file.rs"), &[2, 4]);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_file_deletion_removes_bookmarks(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"file1.rs": "aaa\nbbb\nccc\n",
|
||||
"file2.rs": "ddd\neee\nfff\n"
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
|
||||
let buffer1 = open_buffer(&project, path!("/project/file1.rs"), cx).await;
|
||||
let buffer2 = open_buffer(&project, path!("/project/file2.rs"), cx).await;
|
||||
|
||||
add_bookmarks(&project, &buffer1, &[0, 2], cx);
|
||||
add_bookmarks(&project, &buffer2, &[1], cx);
|
||||
assert_eq!(get_all_bookmarks(&project, cx).len(), 2);
|
||||
|
||||
// Delete file1.rs
|
||||
fs.remove_file(path!("/project/file1.rs").as_ref(), Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
// file1.rs bookmarks should be gone, file2.rs bookmarks preserved
|
||||
let bookmarks = get_all_bookmarks(&project, cx);
|
||||
assert_eq!(bookmarks.len(), 1);
|
||||
assert!(!bookmarks.contains_key(&project_path(path!("/project/file1.rs"))));
|
||||
assert_bookmark_rows(&bookmarks, path!("/project/file2.rs"), &[1]);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_deleting_all_bookmarked_files_clears_store(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"file1.rs": "aaa\nbbb\n",
|
||||
"file2.rs": "ccc\nddd\n"
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
|
||||
let buffer1 = open_buffer(&project, path!("/project/file1.rs"), cx).await;
|
||||
let buffer2 = open_buffer(&project, path!("/project/file2.rs"), cx).await;
|
||||
|
||||
add_bookmarks(&project, &buffer1, &[0], cx);
|
||||
add_bookmarks(&project, &buffer2, &[1], cx);
|
||||
assert_eq!(get_all_bookmarks(&project, cx).len(), 2);
|
||||
|
||||
// Delete both files
|
||||
fs.remove_file(path!("/project/file1.rs").as_ref(), Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
fs.remove_file(path!("/project/file2.rs").as_ref(), Default::default())
|
||||
.await
|
||||
.unwrap();
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
assert!(get_all_bookmarks(&project, cx).is_empty());
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_file_rename_re_keys_bookmarks(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(path!("/project"), json!({"old_name.rs": "aaa\nbbb\nccc\n"}))
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
|
||||
let buffer = open_buffer(&project, path!("/project/old_name.rs"), cx).await;
|
||||
|
||||
add_bookmarks(&project, &buffer, &[0, 2], cx);
|
||||
assert_bookmark_rows(
|
||||
&get_all_bookmarks(&project, cx),
|
||||
path!("/project/old_name.rs"),
|
||||
&[0, 2],
|
||||
);
|
||||
|
||||
// Rename the file
|
||||
fs.rename(
|
||||
path!("/project/old_name.rs").as_ref(),
|
||||
path!("/project/new_name.rs").as_ref(),
|
||||
Default::default(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
let bookmarks = get_all_bookmarks(&project, cx);
|
||||
assert_eq!(bookmarks.len(), 1);
|
||||
assert!(!bookmarks.contains_key(&project_path(path!("/project/old_name.rs"))));
|
||||
assert_bookmark_rows(&bookmarks, path!("/project/new_name.rs"), &[0, 2]);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_file_rename_preserves_other_bookmarks(cx: &mut TestAppContext) {
|
||||
init_test(cx);
|
||||
cx.executor().allow_parking();
|
||||
|
||||
let fs = fs::FakeFs::new(cx.executor());
|
||||
fs.insert_tree(
|
||||
path!("/project"),
|
||||
json!({
|
||||
"rename_me.rs": "aaa\nbbb\n",
|
||||
"untouched.rs": "ccc\nddd\neee\n"
|
||||
}),
|
||||
)
|
||||
.await;
|
||||
|
||||
let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
|
||||
let buffer_rename = open_buffer(&project, path!("/project/rename_me.rs"), cx).await;
|
||||
let buffer_other = open_buffer(&project, path!("/project/untouched.rs"), cx).await;
|
||||
|
||||
add_bookmarks(&project, &buffer_rename, &[1], cx);
|
||||
add_bookmarks(&project, &buffer_other, &[0, 2], cx);
|
||||
|
||||
fs.rename(
|
||||
path!("/project/rename_me.rs").as_ref(),
|
||||
path!("/project/renamed.rs").as_ref(),
|
||||
Default::default(),
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
let bookmarks = get_all_bookmarks(&project, cx);
|
||||
assert_eq!(bookmarks.len(), 2);
|
||||
assert_bookmark_rows(&bookmarks, path!("/project/renamed.rs"), &[1]);
|
||||
assert_bookmark_rows(&bookmarks, path!("/project/untouched.rs"), &[0, 2]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user