552 lines · 16.7 KB · Rust
RawDownload
use std::sync::{Arc, atomic}; use fuzzy::{StringMatch, StringMatchCandidate};use gpui::{AppContext, Entity, TestAppContext, VisualTestContext};use picker::{Picker, PickerDelegate};use project::Project;use serde_json::json;use util::path;use workspace::{AppState, MultiWorkspace}; use crate::{CandidateInfo, DirectoryState, OpenPathDelegate}; #[gpui::test]async fn test_open_path_prompt(cx: &mut TestAppContext) {    let app_state = init_test(cx);    app_state        .fs        .as_fake()        .insert_tree(            path!("/root"),            json!({                ".a1": ".A1",                ".b1": ".B1",                "a1": "A1",                "a2": "A2",                "a3": "A3",                "dir1": {},                "dir2": {                    "c": "C",                    "d1": "D1",                    "d2": "D2",                    "d3": "D3",                    "dir3": {},                    "dir4": {}                }            }),        )        .await;     let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;     let (picker, cx) = build_open_path_prompt(project, false, false, cx);     insert_query(path!("sadjaoislkdjasldj"), &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), Vec::<String>::new());     let query = path!("/root");    insert_query(query, &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), vec!["root"]);     #[cfg(not(windows))]    let expected_separator = "./";    #[cfg(windows)]    let expected_separator = ".\\";     // If the query ends with a slash, the picker should show the contents of the directory and not show any of the hidden entries.    let query = path!("/root/");    insert_query(query, &picker, cx).await;    assert_eq!(        collect_match_candidates(&picker, cx),        vec![expected_separator, "dir1", "dir2", "a1", "a2", "a3"]    );     // Show candidates for the query "a".    let query = path!("/root/a");    insert_query(query, &picker, cx).await;    assert_eq!(        collect_match_candidates(&picker, cx),        vec!["a1", "a2", "a3"]    );     // Show candidates for the query "d".    let query = path!("/root/d");    insert_query(query, &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), vec!["dir1", "dir2"]);     let query = path!("/root/dir2");    insert_query(query, &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), vec!["dir2"]);     let query = path!("/root/dir2/");    insert_query(query, &picker, cx).await;    assert_eq!(        collect_match_candidates(&picker, cx),        vec![expected_separator, "dir3", "dir4", "c", "d1", "d2", "d3"]    );     // Show candidates for the query "d".    let query = path!("/root/dir2/d");    insert_query(query, &picker, cx).await;    assert_eq!(        collect_match_candidates(&picker, cx),        vec!["dir3", "dir4", "d1", "d2", "d3"]    );     let query = path!("/root/dir2/di");    insert_query(query, &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), vec!["dir3", "dir4"]);     // Don't show candidates for the query ".".    let query = path!("/root/.");    insert_query(query, &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), Vec::<String>::new());     // Don't show any candidates for the query ".a".    let query = path!("/root/.a");    insert_query(query, &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), Vec::<String>::new());     // Show candidates for the query "./".    // Should show current directory and contents.    let query = path!("/root/./");    insert_query(query, &picker, cx).await;    assert_eq!(        collect_match_candidates(&picker, cx),        vec![expected_separator, "dir1", "dir2", "a1", "a2", "a3"]    );     // Show candidates for the query "../". Show parent contents.    let query = path!("/root/dir1/../");    insert_query(query, &picker, cx).await;    assert_eq!(        collect_match_candidates(&picker, cx),        vec![expected_separator, "dir1", "dir2", "a1", "a2", "a3"]    );} #[gpui::test]async fn test_open_path_prompt_completion(cx: &mut TestAppContext) {    let app_state = init_test(cx);    app_state        .fs        .as_fake()        .insert_tree(            path!("/root"),            json!({                "a": "A",                "dir1": {},                "dir2": {                    "c": "C",                    "d": "D",                    "dir3": {},                    "dir4": {}                }            }),        )        .await;     let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;     let (picker, cx) = build_open_path_prompt(project, false, false, cx);     // Confirm completion for the query "/root", since it's a directory, it should add a trailing slash.    let query = path!("/root");    insert_query(query, &picker, cx).await;    assert_eq!(        confirm_completion(query, 0, &picker, cx).unwrap(),        path!("/root/")    );     // Confirm completion for the query "/root/", selecting the first candidate "dir1", since it's a directory, it should add a trailing slash.    let query = path!("/root/");    insert_query(query, &picker, cx).await;    assert_eq!(        confirm_completion(query, 0, &picker, cx),        None,        "First entry is `./` and when we confirm completion, it is tabbed below"    );    assert_eq!(        confirm_completion(query, 1, &picker, cx).unwrap(),        path!("/root/dir1/"),        "Second entry is the first directory"    );     // Confirm completion for the query "/root/", selecting the third candidate "a", since it's a file, it should not add a trailing slash.    let query = path!("/root/");    insert_query(query, &picker, cx).await;    assert_eq!(        confirm_completion(query, 3, &picker, cx).unwrap(),        path!("/root/a")    );     let query = path!("/root/a");    insert_query(query, &picker, cx).await;    assert_eq!(        confirm_completion(query, 0, &picker, cx).unwrap(),        path!("/root/a")    );     let query = path!("/root/d");    insert_query(query, &picker, cx).await;    assert_eq!(        confirm_completion(query, 1, &picker, cx).unwrap(),        path!("/root/dir2/")    );     let query = path!("/root/dir2");    insert_query(query, &picker, cx).await;    assert_eq!(        confirm_completion(query, 0, &picker, cx).unwrap(),        path!("/root/dir2/")    );     let query = path!("/root/dir2/");    insert_query(query, &picker, cx).await;    assert_eq!(        confirm_completion(query, 1, &picker, cx).unwrap(),        path!("/root/dir2/dir3/")    );     let query = path!("/root/dir2/");    insert_query(query, &picker, cx).await;    assert_eq!(        confirm_completion(query, 3, &picker, cx).unwrap(),        path!("/root/dir2/c")    );     let query = path!("/root/dir2/d");    insert_query(query, &picker, cx).await;    assert_eq!(        confirm_completion(query, 0, &picker, cx).unwrap(),        path!("/root/dir2/dir3/")    );     let query = path!("/root/dir2/d");    insert_query(query, &picker, cx).await;    assert_eq!(        confirm_completion(query, 1, &picker, cx).unwrap(),        path!("/root/dir2/dir4/")    );     let query = path!("/root/dir2/di");    insert_query(query, &picker, cx).await;    assert_eq!(        confirm_completion(query, 1, &picker, cx).unwrap(),        path!("/root/dir2/dir4/")    );} #[gpui::test]#[cfg_attr(not(target_os = "windows"), ignore)]async fn test_open_path_prompt_on_windows(cx: &mut TestAppContext) {    let app_state = init_test(cx);    app_state        .fs        .as_fake()        .insert_tree(            path!("/root"),            json!({                "a": "A",                "dir1": {},                "dir2": {}            }),        )        .await;     let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;     let (picker, cx) = build_open_path_prompt(project, false, false, cx);     // Support both forward and backward slashes.    let query = "C:/root/";    insert_query(query, &picker, cx).await;    assert_eq!(        collect_match_candidates(&picker, cx),        vec![".\\", "dir1", "dir2", "a"]    );    assert_eq!(        confirm_completion(query, 0, &picker, cx),        None,        "First entry is `.\\` and when we confirm completion, it is tabbed below"    );    assert_eq!(        confirm_completion(query, 1, &picker, cx).unwrap(),        "C:/root/dir1\\",        "Second entry is the first directory"    );     let query = "C:\\root/";    insert_query(query, &picker, cx).await;    assert_eq!(        collect_match_candidates(&picker, cx),        vec![".\\", "dir1", "dir2", "a"]    );    assert_eq!(        confirm_completion(query, 1, &picker, cx).unwrap(),        "C:\\root/dir1\\"    );     let query = "C:\\root\\";    insert_query(query, &picker, cx).await;    assert_eq!(        collect_match_candidates(&picker, cx),        vec![".\\", "dir1", "dir2", "a"]    );    assert_eq!(        confirm_completion(query, 1, &picker, cx).unwrap(),        "C:\\root\\dir1\\"    );     // Confirm completion for the query "C:/root/d", selecting the second candidate "dir2", since it's a directory, it should add a trailing slash.    let query = "C:/root/d";    insert_query(query, &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), vec!["dir1", "dir2"]);    assert_eq!(        confirm_completion(query, 1, &picker, cx).unwrap(),        "C:/root/dir2\\"    );     let query = "C:\\root/d";    insert_query(query, &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), vec!["dir1", "dir2"]);    assert_eq!(        confirm_completion(query, 0, &picker, cx).unwrap(),        "C:\\root/dir1\\"    );     let query = "C:\\root\\d";    insert_query(query, &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), vec!["dir1", "dir2"]);    assert_eq!(        confirm_completion(query, 0, &picker, cx).unwrap(),        "C:\\root\\dir1\\"    );} #[gpui::test]async fn test_new_path_prompt(cx: &mut TestAppContext) {    let app_state = init_test(cx);    app_state        .fs        .as_fake()        .insert_tree(            path!("/root"),            json!({                "a1": "A1",                "a2": "A2",                "a3": "A3",                "dir1": {},                "dir2": {                    "c": "C",                    "d1": "D1",                    "d2": "D2",                    "d3": "D3",                    "dir3": {},                    "dir4": {}                }            }),        )        .await;     let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;     let (picker, cx) = build_open_path_prompt(project, true, false, cx);     insert_query(path!("/root"), &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), vec!["root"]);     insert_query(path!("/root/d"), &picker, cx).await;    assert_eq!(        collect_match_candidates(&picker, cx),        vec!["d", "dir1", "dir2"]    );     insert_query(path!("/root/dir1"), &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), vec!["dir1"]);     insert_query(path!("/root/dir12"), &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), vec!["dir12"]);     insert_query(path!("/root/dir1"), &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), vec!["dir1"]);} #[gpui::test]async fn test_open_path_prompt_panics_with_stale_highlight_positions(cx: &mut TestAppContext) {    let app_state = init_test(cx);    app_state        .fs        .as_fake()        .insert_tree(path!("/root"), json!({}))        .await;     let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;    let (picker, cx) = build_open_path_prompt(project, false, false, cx);     picker.update_in(cx, |picker, window, cx| {        picker.delegate.prompt_root = "/".to_string();        picker.delegate.directory_state = DirectoryState::List {            parent_path: picker.delegate.prompt_root.clone(),            entries: vec![CandidateInfo {                path: StringMatchCandidate::new(0, "éclair"),                is_dir: false,            }],            error: None,        };        picker.delegate.string_matches = vec![StringMatch {            candidate_id: 0,            score: 0.0,            positions: vec![1],            string: "ab".to_string(),        }];         picker.delegate.render_match(0, false, window, cx);    });} #[gpui::test]async fn test_open_path_prompt_with_show_hidden(cx: &mut TestAppContext) {    let app_state = init_test(cx);    app_state        .fs        .as_fake()        .insert_tree(            path!("/root"),            json!({                "directory_1": {},                "directory_2": {},                ".hidden": {}            }),        )        .await;     let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;     let (picker, cx) = build_open_path_prompt(project, false, true, cx);     #[cfg(not(windows))]    let expected_separator = "./";    #[cfg(windows)]    let expected_separator = ".\\";     insert_query(path!("/root/"), &picker, cx).await;    assert_eq!(        collect_match_candidates(&picker, cx),        vec![expected_separator, ".hidden", "directory_1", "directory_2"]    );     insert_query(path!("/root/."), &picker, cx).await;    assert_eq!(collect_match_candidates(&picker, cx), vec![".hidden"]);} #[gpui::test]async fn test_dismiss_cancels_in_flight_match(cx: &mut TestAppContext) {    let app_state = init_test(cx);    app_state        .fs        .as_fake()        .insert_tree(            path!("/root"),            json!({                "a1": "A1",                "a2": "A2",                "a3": "A3",            }),        )        .await;     let project = Project::test(app_state.fs.clone(), [path!("/root").as_ref()], cx).await;    let (picker, cx) = build_open_path_prompt(project, false, false, cx);     insert_query(path!("/root/a"), &picker, cx).await;     let cancel_flag = picker.read_with(cx, |picker, _| picker.delegate.cancel_flag.clone());    assert!(        !cancel_flag.load(atomic::Ordering::Acquire),        "cancel flag should be clear while the prompt is active"    );     picker.update_in(cx, |picker, window, cx| {        picker.delegate.dismissed(window, cx);    });     assert!(        cancel_flag.load(atomic::Ordering::Acquire),        "dismissing the prompt must cancel the in-flight fuzzy match"    );} fn init_test(cx: &mut TestAppContext) -> Arc<AppState> {    cx.update(|cx| {        let state = AppState::test(cx);        theme_settings::init(theme::LoadThemes::JustBase, cx);         editor::init(cx);        state    })} fn build_open_path_prompt(    project: Entity<Project>,    creating_path: bool,    show_hidden: bool,    cx: &mut TestAppContext,) -> (Entity<Picker<OpenPathDelegate>>, &mut VisualTestContext) {    let (tx, _) = futures::channel::oneshot::channel();    let lister = project::DirectoryLister::Project(project.clone());     let (multi_workspace, cx) =        cx.add_window_view(|window, cx| MultiWorkspace::test_new(project, window, cx));

Lines 1–500 of 552.