Add a test

co-authored-by: Mikayla <mikayla@zed.dev>
This commit is contained in:
Kirill Bulatov 2023-05-27 00:06:09 +03:00
parent cf2bbfc85a
commit 3a3c1c5a5b
4 changed files with 235 additions and 55 deletions

View file

@ -32,6 +32,7 @@ pub struct FileFinderDelegate {
history_items: Vec<FoundPath>, history_items: Vec<FoundPath>,
} }
#[derive(Debug)]
enum Matches { enum Matches {
History(Vec<FoundPath>), History(Vec<FoundPath>),
Search(Vec<PathMatch>), Search(Vec<PathMatch>),
@ -114,6 +115,12 @@ fn toggle_file_finder(workspace: &mut Workspace, _: &Toggle, cx: &mut ViewContex
.as_ref() .as_ref()
.map(|found_path| &found_path.project) .map(|found_path| &found_path.project)
}) })
.filter(|(_, history_abs_path)| {
history_abs_path.as_ref()
!= currently_opened_path
.as_ref()
.and_then(|found_path| found_path.absolute.as_ref())
})
.map(|(history_path, abs_path)| FoundPath::new(history_path, abs_path)), .map(|(history_path, abs_path)| FoundPath::new(history_path, abs_path)),
) )
.collect(); .collect();
@ -330,7 +337,6 @@ impl FileFinderDelegate {
) -> (String, Vec<usize>, String, Vec<usize>) { ) -> (String, Vec<usize>, String, Vec<usize>) {
let path = &path_match.path; let path = &path_match.path;
let path_string = path.to_string_lossy(); let path_string = path.to_string_lossy();
// TODO kb full path could be very long, trim it to fit the panel width
let full_path = [path_match.path_prefix.as_ref(), path_string.as_ref()].join(""); let full_path = [path_match.path_prefix.as_ref(), path_string.as_ref()].join("");
let path_positions = path_match.positions.clone(); let path_positions = path_match.positions.clone();
@ -437,7 +443,7 @@ impl PickerDelegate for FileFinderDelegate {
} else { } else {
match history_match.absolute.as_ref() { match history_match.absolute.as_ref() {
Some(abs_path) => { Some(abs_path) => {
workspace.open_abs_path(abs_path.to_path_buf(), true, cx) workspace.open_abs_path(abs_path.to_path_buf(), false, cx)
} }
None => workspace.open_path( None => workspace.open_path(
ProjectPath { ProjectPath {
@ -1192,10 +1198,13 @@ mod tests {
.await; .await;
assert_eq!( assert_eq!(
history_after_first, history_after_first,
vec![dummy_found_path(ProjectPath { vec![FoundPath::new(
worktree_id, ProjectPath {
path: Arc::from(Path::new("test/first.rs")), worktree_id,
})], path: Arc::from(Path::new("test/first.rs")),
},
Some(PathBuf::from("/src/test/first.rs"))
)],
"Should show 1st opened item in the history when opening the 2nd item" "Should show 1st opened item in the history when opening the 2nd item"
); );
@ -1212,14 +1221,20 @@ mod tests {
assert_eq!( assert_eq!(
history_after_second, history_after_second,
vec![ vec![
dummy_found_path(ProjectPath { FoundPath::new(
worktree_id, ProjectPath {
path: Arc::from(Path::new("test/second.rs")), worktree_id,
}), path: Arc::from(Path::new("test/second.rs")),
dummy_found_path(ProjectPath { },
worktree_id, Some(PathBuf::from("/src/test/second.rs"))
path: Arc::from(Path::new("test/first.rs")), ),
}), FoundPath::new(
ProjectPath {
worktree_id,
path: Arc::from(Path::new("test/first.rs")),
},
Some(PathBuf::from("/src/test/first.rs"))
),
], ],
"Should show 1st and 2nd opened items in the history when opening the 3rd item. \ "Should show 1st and 2nd opened items in the history when opening the 3rd item. \
2nd item should be the first in the history, as the last opened." 2nd item should be the first in the history, as the last opened."
@ -1238,18 +1253,27 @@ mod tests {
assert_eq!( assert_eq!(
history_after_third, history_after_third,
vec![ vec![
dummy_found_path(ProjectPath { FoundPath::new(
worktree_id, ProjectPath {
path: Arc::from(Path::new("test/third.rs")), worktree_id,
}), path: Arc::from(Path::new("test/third.rs")),
dummy_found_path(ProjectPath { },
worktree_id, Some(PathBuf::from("/src/test/third.rs"))
path: Arc::from(Path::new("test/second.rs")), ),
}), FoundPath::new(
dummy_found_path(ProjectPath { ProjectPath {
worktree_id, worktree_id,
path: Arc::from(Path::new("test/first.rs")), path: Arc::from(Path::new("test/second.rs")),
}), },
Some(PathBuf::from("/src/test/second.rs"))
),
FoundPath::new(
ProjectPath {
worktree_id,
path: Arc::from(Path::new("test/first.rs")),
},
Some(PathBuf::from("/src/test/first.rs"))
),
], ],
"Should show 1st, 2nd and 3rd opened items in the history when opening the 2nd item again. \ "Should show 1st, 2nd and 3rd opened items in the history when opening the 2nd item again. \
3rd item should be the first in the history, as the last opened." 3rd item should be the first in the history, as the last opened."
@ -1268,24 +1292,162 @@ mod tests {
assert_eq!( assert_eq!(
history_after_second_again, history_after_second_again,
vec![ vec![
dummy_found_path(ProjectPath { FoundPath::new(
worktree_id, ProjectPath {
path: Arc::from(Path::new("test/second.rs")), worktree_id,
}), path: Arc::from(Path::new("test/second.rs")),
dummy_found_path(ProjectPath { },
worktree_id, Some(PathBuf::from("/src/test/second.rs"))
path: Arc::from(Path::new("test/third.rs")), ),
}), FoundPath::new(
dummy_found_path(ProjectPath { ProjectPath {
worktree_id, worktree_id,
path: Arc::from(Path::new("test/first.rs")), path: Arc::from(Path::new("test/third.rs")),
}), },
Some(PathBuf::from("/src/test/third.rs"))
),
FoundPath::new(
ProjectPath {
worktree_id,
path: Arc::from(Path::new("test/first.rs")),
},
Some(PathBuf::from("/src/test/first.rs"))
),
], ],
"Should show 1st, 2nd and 3rd opened items in the history when opening the 3rd item again. \ "Should show 1st, 2nd and 3rd opened items in the history when opening the 3rd item again. \
2nd item, as the last opened, 3rd item should go next as it was opened right before." 2nd item, as the last opened, 3rd item should go next as it was opened right before."
); );
} }
#[gpui::test]
async fn test_external_files_history(
deterministic: Arc<gpui::executor::Deterministic>,
cx: &mut gpui::TestAppContext,
) {
let app_state = init_test(cx);
app_state
.fs
.as_fake()
.insert_tree(
"/src",
json!({
"test": {
"first.rs": "// First Rust file",
"second.rs": "// Second Rust file",
}
}),
)
.await;
app_state
.fs
.as_fake()
.insert_tree(
"/external-src",
json!({
"test": {
"third.rs": "// Third Rust file",
"fourth.rs": "// Fourth Rust file",
}
}),
)
.await;
let project = Project::test(app_state.fs.clone(), ["/src".as_ref()], cx).await;
cx.update(|cx| {
project.update(cx, |project, cx| {
project.find_or_create_local_worktree("/external-src", false, cx)
})
})
.detach();
deterministic.run_until_parked();
let (window_id, workspace) = cx.add_window(|cx| Workspace::test_new(project, cx));
let worktree_id = cx.read(|cx| {
let worktrees = workspace.read(cx).worktrees(cx).collect::<Vec<_>>();
assert_eq!(worktrees.len(), 1,);
WorktreeId::from_usize(worktrees[0].id())
});
workspace
.update(cx, |workspace, cx| {
workspace.open_abs_path(PathBuf::from("/external-src/test/third.rs"), false, cx)
})
.detach();
deterministic.run_until_parked();
let external_worktree_id = cx.read(|cx| {
let worktrees = workspace.read(cx).worktrees(cx).collect::<Vec<_>>();
assert_eq!(
worktrees.len(),
2,
"External file should get opened in a new worktree"
);
WorktreeId::from_usize(
worktrees
.into_iter()
.find(|worktree| worktree.id() != worktree_id.to_usize())
.expect("New worktree should have a different id")
.id(),
)
});
close_active_item(&workspace, &deterministic, cx).await;
let initial_history_items = open_close_queried_buffer(
"sec",
1,
"second.rs",
window_id,
&workspace,
&deterministic,
cx,
)
.await;
assert_eq!(
initial_history_items,
vec![FoundPath::new(
ProjectPath {
worktree_id: external_worktree_id,
path: Arc::from(Path::new("")),
},
Some(PathBuf::from("/external-src/test/third.rs"))
)],
"Should show external file with its full path in the history after it was open"
);
let updated_history_items = open_close_queried_buffer(
"fir",
1,
"first.rs",
window_id,
&workspace,
&deterministic,
cx,
)
.await;
assert_eq!(
updated_history_items,
vec![
FoundPath::new(
ProjectPath {
worktree_id,
path: Arc::from(Path::new("test/second.rs")),
},
Some(PathBuf::from("/src/test/second.rs"))
),
FoundPath::new(
ProjectPath {
worktree_id: external_worktree_id,
path: Arc::from(Path::new("")),
},
Some(PathBuf::from("/external-src/test/third.rs"))
),
],
"Should keep external file with history updates",
);
}
async fn open_close_queried_buffer( async fn open_close_queried_buffer(
input: &str, input: &str,
expected_matches: usize, expected_matches: usize,
@ -1332,6 +1494,16 @@ mod tests {
); );
}); });
close_active_item(workspace, deterministic, cx).await;
history_items
}
async fn close_active_item(
workspace: &ViewHandle<Workspace>,
deterministic: &gpui::executor::Deterministic,
cx: &mut TestAppContext,
) {
let mut original_items = HashMap::new(); let mut original_items = HashMap::new();
cx.read(|cx| { cx.read(|cx| {
for pane in workspace.read(cx).panes() { for pane in workspace.read(cx).panes() {
@ -1341,6 +1513,8 @@ mod tests {
assert!(insertion_result.is_none(), "Pane id {pane_id} collision"); assert!(insertion_result.is_none(), "Pane id {pane_id} collision");
} }
}); });
let active_pane = cx.read(|cx| workspace.read(cx).active_pane().clone());
active_pane active_pane
.update(cx, |pane, cx| { .update(cx, |pane, cx| {
pane.close_active_item(&workspace::CloseActiveItem, cx) pane.close_active_item(&workspace::CloseActiveItem, cx)
@ -1365,8 +1539,10 @@ mod tests {
} }
} }
}); });
assert!(
history_items original_items.len() <= 1,
"At most one panel should got closed"
);
} }
fn init_test(cx: &mut TestAppContext) -> Arc<AppState> { fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {

View file

@ -3218,7 +3218,7 @@ impl Project {
) -> Result<(), anyhow::Error> { ) -> Result<(), anyhow::Error> {
let (worktree, relative_path) = self let (worktree, relative_path) = self
.find_local_worktree(&abs_path, cx) .find_local_worktree(&abs_path, cx)
.ok_or_else(|| anyhow!("no worktree found for diagnostics"))?; .ok_or_else(|| anyhow!("no worktree found for diagnostics path {abs_path:?}"))?;
let project_path = ProjectPath { let project_path = ProjectPath {
worktree_id: worktree.read(cx).id(), worktree_id: worktree.read(cx).id(),

View file

@ -1018,9 +1018,11 @@ impl Pane {
if let Some(path) = item.project_path(cx) { if let Some(path) = item.project_path(cx) {
let abs_path = self let abs_path = self
.workspace() .nav_history
.upgrade(cx) .borrow()
.and_then(|workspace| workspace.read(cx).absolute_path(&path, cx)); .paths_by_item
.get(&item.id())
.and_then(|(_, abs_path)| abs_path.clone());
self.nav_history self.nav_history
.borrow_mut() .borrow_mut()
.paths_by_item .paths_by_item

View file

@ -975,23 +975,25 @@ impl Workspace {
}); });
} }
let project = self.project.read(cx);
history history
.into_iter() .into_iter()
.sorted_by_key(|(_, (_, timestamp))| *timestamp) .sorted_by_key(|(_, (_, timestamp))| *timestamp)
.map(|(project_path, (fs_path, _))| (project_path, fs_path)) .map(|(project_path, (fs_path, _))| (project_path, fs_path))
.rev() .rev()
.filter(|(history_path, abs_path)| { .filter(|(history_path, abs_path)| {
project let latest_project_path_opened = abs_path
.worktree_for_id(history_path.worktree_id, cx) .as_ref()
.is_some() .and_then(|abs_path| abs_paths_opened.get(abs_path))
|| abs_path .and_then(|project_paths| {
.as_ref() project_paths
.and_then(|abs_path| { .iter()
let buffers_opened = abs_paths_opened.get(abs_path)?; .max_by(|b1, b2| b1.worktree_id.cmp(&b2.worktree_id))
Some(buffers_opened.len() < 2) });
})
.unwrap_or(false) match latest_project_path_opened {
Some(latest_project_path_opened) => latest_project_path_opened == history_path,
None => true,
}
}) })
.take(limit.unwrap_or(usize::MAX)) .take(limit.unwrap_or(usize::MAX))
.collect() .collect()