ZIm/crates/tab_switcher/src/tab_switcher_tests.rs
Max Brunsfeld 38e3182bef
Handle buffer diff base updates and file renames properly for SSH projects (#14989)
Release Notes:

- N/A

---------

Co-authored-by: Conrad <conrad@zed.dev>
2024-07-23 11:32:37 -07:00

327 lines
11 KiB
Rust

use super::*;
use editor::Editor;
use gpui::{TestAppContext, VisualTestContext};
use menu::SelectPrev;
use project::{Project, ProjectPath};
use serde_json::json;
use std::path::Path;
use workspace::{AppState, Workspace};
#[ctor::ctor]
fn init_logger() {
if std::env::var("RUST_LOG").is_ok() {
env_logger::init();
}
}
#[gpui::test]
async fn test_open_with_prev_tab_selected_and_cycle_on_toggle_action(
cx: &mut gpui::TestAppContext,
) {
let app_state = init_test(cx);
app_state
.fs
.as_fake()
.insert_tree(
"/root",
json!({
"1.txt": "First file",
"2.txt": "Second file",
"3.txt": "Third file",
"4.txt": "Fourth file",
}),
)
.await;
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
let tab_1 = open_buffer("1.txt", &workspace, cx).await;
let tab_2 = open_buffer("2.txt", &workspace, cx).await;
let tab_3 = open_buffer("3.txt", &workspace, cx).await;
let tab_4 = open_buffer("4.txt", &workspace, cx).await;
// Starts with the previously opened item selected
let tab_switcher = open_tab_switcher(false, &workspace, cx);
tab_switcher.update(cx, |tab_switcher, _| {
assert_eq!(tab_switcher.delegate.matches.len(), 4);
assert_match_at_position(tab_switcher, 0, tab_4.boxed_clone());
assert_match_selection(tab_switcher, 1, tab_3.boxed_clone());
assert_match_at_position(tab_switcher, 2, tab_2.boxed_clone());
assert_match_at_position(tab_switcher, 3, tab_1.boxed_clone());
});
cx.dispatch_action(Toggle { select_last: false });
cx.dispatch_action(Toggle { select_last: false });
tab_switcher.update(cx, |tab_switcher, _| {
assert_eq!(tab_switcher.delegate.matches.len(), 4);
assert_match_at_position(tab_switcher, 0, tab_4.boxed_clone());
assert_match_at_position(tab_switcher, 1, tab_3.boxed_clone());
assert_match_at_position(tab_switcher, 2, tab_2.boxed_clone());
assert_match_selection(tab_switcher, 3, tab_1.boxed_clone());
});
cx.dispatch_action(SelectPrev);
tab_switcher.update(cx, |tab_switcher, _| {
assert_eq!(tab_switcher.delegate.matches.len(), 4);
assert_match_at_position(tab_switcher, 0, tab_4.boxed_clone());
assert_match_at_position(tab_switcher, 1, tab_3.boxed_clone());
assert_match_selection(tab_switcher, 2, tab_2.boxed_clone());
assert_match_at_position(tab_switcher, 3, tab_1.boxed_clone());
});
}
#[gpui::test]
async fn test_open_with_last_tab_selected(cx: &mut gpui::TestAppContext) {
let app_state = init_test(cx);
app_state
.fs
.as_fake()
.insert_tree(
"/root",
json!({
"1.txt": "First file",
"2.txt": "Second file",
"3.txt": "Third file",
}),
)
.await;
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
let tab_1 = open_buffer("1.txt", &workspace, cx).await;
let tab_2 = open_buffer("2.txt", &workspace, cx).await;
let tab_3 = open_buffer("3.txt", &workspace, cx).await;
// Starts with the last item selected
let tab_switcher = open_tab_switcher(true, &workspace, cx);
tab_switcher.update(cx, |tab_switcher, _| {
assert_eq!(tab_switcher.delegate.matches.len(), 3);
assert_match_at_position(tab_switcher, 0, tab_3);
assert_match_at_position(tab_switcher, 1, tab_2);
assert_match_selection(tab_switcher, 2, tab_1);
});
}
#[gpui::test]
async fn test_open_item_on_modifiers_release(cx: &mut gpui::TestAppContext) {
let app_state = init_test(cx);
app_state
.fs
.as_fake()
.insert_tree(
"/root",
json!({
"1.txt": "First file",
"2.txt": "Second file",
}),
)
.await;
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
let tab_1 = open_buffer("1.txt", &workspace, cx).await;
let tab_2 = open_buffer("2.txt", &workspace, cx).await;
cx.simulate_modifiers_change(Modifiers::control());
let tab_switcher = open_tab_switcher(false, &workspace, cx);
tab_switcher.update(cx, |tab_switcher, _| {
assert_eq!(tab_switcher.delegate.matches.len(), 2);
assert_match_at_position(tab_switcher, 0, tab_2.boxed_clone());
assert_match_selection(tab_switcher, 1, tab_1.boxed_clone());
});
cx.simulate_modifiers_change(Modifiers::none());
cx.read(|cx| {
let active_editor = workspace.read(cx).active_item_as::<Editor>(cx).unwrap();
assert_eq!(active_editor.read(cx).title(cx), "1.txt");
});
assert_tab_switcher_is_closed(workspace, cx);
}
#[gpui::test]
async fn test_open_on_empty_pane(cx: &mut gpui::TestAppContext) {
let app_state = init_test(cx);
app_state.fs.as_fake().insert_tree("/root", json!({})).await;
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
cx.simulate_modifiers_change(Modifiers::control());
let tab_switcher = open_tab_switcher(false, &workspace, cx);
tab_switcher.update(cx, |tab_switcher, _| {
assert!(tab_switcher.delegate.matches.is_empty());
});
cx.simulate_modifiers_change(Modifiers::none());
assert_tab_switcher_is_closed(workspace, cx);
}
#[gpui::test]
async fn test_open_with_single_item(cx: &mut gpui::TestAppContext) {
let app_state = init_test(cx);
app_state
.fs
.as_fake()
.insert_tree("/root", json!({"1.txt": "Single file"}))
.await;
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
let tab = open_buffer("1.txt", &workspace, cx).await;
let tab_switcher = open_tab_switcher(false, &workspace, cx);
tab_switcher.update(cx, |tab_switcher, _| {
assert_eq!(tab_switcher.delegate.matches.len(), 1);
assert_match_selection(tab_switcher, 0, tab);
});
}
#[gpui::test]
async fn test_close_selected_item(cx: &mut gpui::TestAppContext) {
let app_state = init_test(cx);
app_state
.fs
.as_fake()
.insert_tree(
"/root",
json!({
"1.txt": "First file",
"2.txt": "Second file",
}),
)
.await;
let project = Project::test(app_state.fs.clone(), ["/root".as_ref()], cx).await;
let (workspace, cx) = cx.add_window_view(|cx| Workspace::test_new(project.clone(), cx));
let tab_1 = open_buffer("1.txt", &workspace, cx).await;
let tab_2 = open_buffer("2.txt", &workspace, cx).await;
cx.simulate_modifiers_change(Modifiers::control());
let tab_switcher = open_tab_switcher(false, &workspace, cx);
tab_switcher.update(cx, |tab_switcher, _| {
assert_eq!(tab_switcher.delegate.matches.len(), 2);
assert_match_at_position(tab_switcher, 0, tab_2.boxed_clone());
assert_match_selection(tab_switcher, 1, tab_1.boxed_clone());
});
cx.simulate_modifiers_change(Modifiers::control());
cx.dispatch_action(CloseSelectedItem);
tab_switcher.update(cx, |tab_switcher, _| {
assert_eq!(tab_switcher.delegate.matches.len(), 1);
assert_match_selection(tab_switcher, 0, tab_2);
});
// Still switches tab on modifiers release
cx.simulate_modifiers_change(Modifiers::none());
cx.read(|cx| {
let active_editor = workspace.read(cx).active_item_as::<Editor>(cx).unwrap();
assert_eq!(active_editor.read(cx).title(cx), "2.txt");
});
assert_tab_switcher_is_closed(workspace, cx);
}
fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {
cx.update(|cx| {
let state = AppState::test(cx);
theme::init(theme::LoadThemes::JustBase, cx);
language::init(cx);
super::init(cx);
editor::init(cx);
workspace::init_settings(cx);
Project::init_settings(cx);
state
})
}
#[track_caller]
fn open_tab_switcher(
select_last: bool,
workspace: &View<Workspace>,
cx: &mut VisualTestContext,
) -> View<Picker<TabSwitcherDelegate>> {
cx.dispatch_action(Toggle { select_last });
get_active_tab_switcher(workspace, cx)
}
#[track_caller]
fn get_active_tab_switcher(
workspace: &View<Workspace>,
cx: &mut VisualTestContext,
) -> View<Picker<TabSwitcherDelegate>> {
workspace.update(cx, |workspace, cx| {
workspace
.active_modal::<TabSwitcher>(cx)
.expect("tab switcher is not open")
.read(cx)
.picker
.clone()
})
}
async fn open_buffer(
file_path: &str,
workspace: &View<Workspace>,
cx: &mut gpui::VisualTestContext,
) -> Box<dyn ItemHandle> {
let project = workspace.update(cx, |workspace, _| workspace.project().clone());
let worktree_id = project.update(cx, |project, cx| {
let worktree = project.worktrees(cx).last().expect("worktree not found");
worktree.read(cx).id()
});
let project_path = ProjectPath {
worktree_id,
path: Arc::from(Path::new(file_path)),
};
workspace
.update(cx, move |workspace, cx| {
workspace.open_path(project_path, None, true, cx)
})
.await
.unwrap()
}
#[track_caller]
fn assert_match_selection(
tab_switcher: &Picker<TabSwitcherDelegate>,
expected_selection_index: usize,
expected_item: Box<dyn ItemHandle>,
) {
assert_eq!(
tab_switcher.delegate.selected_index(),
expected_selection_index,
"item is not selected"
);
assert_match_at_position(tab_switcher, expected_selection_index, expected_item);
}
#[track_caller]
fn assert_match_at_position(
tab_switcher: &Picker<TabSwitcherDelegate>,
match_index: usize,
expected_item: Box<dyn ItemHandle>,
) {
let match_item = tab_switcher
.delegate
.matches
.get(match_index)
.unwrap_or_else(|| panic!("Tab Switcher has no match for index {match_index}"));
assert_eq!(match_item.item.item_id(), expected_item.item_id());
}
#[track_caller]
fn assert_tab_switcher_is_closed(workspace: View<Workspace>, cx: &mut VisualTestContext) {
workspace.update(cx, |workspace, cx| {
assert!(
workspace.active_modal::<TabSwitcher>(cx).is_none(),
"tab switcher is still open"
);
});
}