use std::path::Path;use std::sync::Arc; use repo_metadata::entry::{DirectoryEntry, Entry, FileMetadata};use repo_metadata::file_tree_store::FileTreeState;use repo_metadata::local_model::IndexedRepoState;use repo_metadata::repositories::DetectedRepositories;use repo_metadata::watcher::DirectoryWatcher;use repo_metadata::{RepoMetadataModel, RepositoryIdentifier};use settings::Setting;use virtual_fs::{Stub, VirtualFS};use warp_core::ui::appearance::Appearance;use warpui::platform::WindowStyle;use warpui::{App, ModelHandle, SingletonEntity}; use super::FileTreeView;use crate::auth::AuthStateProvider;use crate::server::server_api::team::MockTeamClient;use crate::server::server_api::workspace::MockWorkspaceClient;use crate::settings::CodeSettings;use crate::settings_view::keybindings::KeybindingChangedNotifier;use crate::test_util::settings::initialize_settings_for_tests;use crate::vim_registers::VimRegisters;use crate::workspace::ToastStack;use crate::workspace::sync_inputs::SyncedInputState;use crate::workspaces::user_workspaces::UserWorkspaces; fn std_path(path: &std::path::Path) -> warp_util::standardized_path::StandardizedPath { warp_util::standardized_path::StandardizedPath::try_from_local(path).unwrap()} fn initialize_app( app: &mut App,) -> ( ModelHandle<DetectedRepositories>, ModelHandle<RepoMetadataModel>,) { initialize_settings_for_tests(app); app.add_singleton_model(|_| Appearance::mock()); app.add_singleton_model(|_| ToastStack); app.add_singleton_model(|_| SyncedInputState::mock()); app.add_singleton_model(|_| VimRegisters::new()); app.add_singleton_model(|_| KeybindingChangedNotifier::mock()); app.add_singleton_model(|_| AuthStateProvider::new_for_test()); let team_client = Arc::new(MockTeamClient::new()); let workspace_client = Arc::new(MockWorkspaceClient::new()); app.add_singleton_model(|ctx| { UserWorkspaces::mock(team_client.clone(), workspace_client.clone(), vec![], ctx) }); let detected_repositories = app.add_singleton_model(|_| DetectedRepositories::default()); let repository_metadata_model = app.add_singleton_model(RepoMetadataModel::new); (detected_repositories, repository_metadata_model)} fn build_repo_state(repo_root: &std::path::Path) -> FileTreeState { let source_file = Entry::File(FileMetadata::new( repo_root.join("packages/app/src/main.rs"), false, )); let src_dir = Entry::Directory(DirectoryEntry { path: warp_util::standardized_path::StandardizedPath::try_from_local( &repo_root.join("packages/app/src"), ) .unwrap(), children: vec![source_file], ignored: false, loaded: true, }); let app_dir = Entry::Directory(DirectoryEntry { path: warp_util::standardized_path::StandardizedPath::try_from_local( &repo_root.join("packages/app"), ) .unwrap(), children: vec![src_dir], ignored: false, loaded: true, }); let packages_dir = Entry::Directory(DirectoryEntry { path: warp_util::standardized_path::StandardizedPath::try_from_local( &repo_root.join("packages"), ) .unwrap(), children: vec![app_dir], ignored: false, loaded: true, }); let root = Entry::Directory(DirectoryEntry { path: std_path(repo_root), children: vec![packages_dir], ignored: false, loaded: true, }); FileTreeState::new(root, vec![], None)} fn build_repo_state_with_unloaded_directory(repo_root: &std::path::Path) -> FileTreeState { let unloaded_src_dir = Entry::Directory(DirectoryEntry { path: warp_util::standardized_path::StandardizedPath::try_from_local( &repo_root.join("src"), ) .unwrap(), children: vec![], ignored: false, loaded: false, }); let root = Entry::Directory(DirectoryEntry { path: std_path(repo_root), children: vec![unloaded_src_dir], ignored: false, loaded: true, }); FileTreeState::new(root, vec![], None)} fn flattened_paths( view: &FileTreeView, root: &std::path::Path,) -> Vec<warp_util::standardized_path::StandardizedPath> { view.root_directories .get(&std_path(root)) .expect("root directory is tracked") .items .iter() .map(|item| item.path().clone()) .collect()} async fn await_repository_indexed( app: &mut App, repository_metadata_model: &ModelHandle<RepoMetadataModel>, repo_root: &Path,) { let id = RepositoryIdentifier::local(std_path(repo_root)); let completion = repository_metadata_model.update(app, |model, ctx| model.repository_indexed(&id, ctx)); completion.await; repository_metadata_model.read(app, |model, ctx| { assert!(matches!( model.repository_state(&id, ctx), Some(IndexedRepoState::Indexed(_)) )); }); futures_lite::future::yield_now().await;} async fn await_directory_loaded( app: &mut App, repository_metadata_model: &ModelHandle<RepoMetadataModel>, repo_root: &Path, dir_path: &Path,) { let repo_root = std_path(repo_root); let dir_path = std_path(dir_path); let completion = repository_metadata_model .update(app, |model, ctx| { model.load_directory_with_completion(&repo_root, &dir_path, ctx) }) .expect("directory load should start or join an in-flight load"); completion.await.expect("directory should load"); futures_lite::future::yield_now().await;} fn set_show_hidden_files(app: &mut App, show_hidden_files: bool) { CodeSettings::handle(app).update(app, |settings, ctx| { Setting::set_value(&mut settings.show_hidden_files, show_hidden_files, ctx) .expect("show hidden files setting updates"); });} #[test]fn hidden_files_are_filtered_until_setting_is_enabled() { VirtualFS::test("file_tree_hidden_files_setting", |dirs, mut vfs| { vfs.mkdir("tree/.config").with_files(vec![ Stub::FileWithContent("tree/.env", "SECRET=value\n"), Stub::FileWithContent("tree/.config/settings.toml", ""), Stub::FileWithContent("tree/visible.txt", "content\n"), ]); let tree = dirs.tests().join("tree"); let hidden_file = tree.join(".env"); let hidden_dir = tree.join(".config"); let visible_file = tree.join("visible.txt"); App::test((), |mut app| async move { let (_, repository_metadata_model) = initialize_app(&mut app); set_show_hidden_files(&mut app, false); let (_, file_tree_view) = app.add_window(WindowStyle::NotStealFocus, FileTreeView::new); file_tree_view.update(&mut app, |view, ctx| { view.set_is_active(true, ctx); view.set_root_directories(vec![tree.clone()], ctx); }); await_repository_indexed(&mut app, &repository_metadata_model, &tree).await; file_tree_view.read(&app, |view, _ctx| { let paths = flattened_paths(view, &tree); assert!(paths.contains(&std_path(&tree))); assert!(paths.contains(&std_path(&visible_file))); assert!(!paths.contains(&std_path(&hidden_file))); assert!(!paths.contains(&std_path(&hidden_dir))); }); set_show_hidden_files(&mut app, true); file_tree_view.read(&app, |view, _ctx| { let paths = flattened_paths(view, &tree); assert!(paths.contains(&std_path(&hidden_file))); assert!(paths.contains(&std_path(&hidden_dir))); }); }); });} #[test]fn hidden_root_directory_is_not_filtered() { VirtualFS::test("file_tree_hidden_root_directory", |dirs, mut vfs| { vfs.mkdir(".config").with_files(vec![ Stub::FileWithContent(".config/settings.toml", ""), Stub::FileWithContent(".config/.secret", ""), ]); let hidden_root = dirs.tests().join(".config"); let visible_file = hidden_root.join("settings.toml"); let hidden_file = hidden_root.join(".secret"); App::test((), |mut app| async move { let (_, repository_metadata_model) = initialize_app(&mut app); set_show_hidden_files(&mut app, false); let (_, file_tree_view) = app.add_window(WindowStyle::NotStealFocus, FileTreeView::new); file_tree_view.update(&mut app, |view, ctx| { view.set_is_active(true, ctx); view.set_root_directories(vec![hidden_root.clone()], ctx); }); await_repository_indexed(&mut app, &repository_metadata_model, &hidden_root).await; file_tree_view.read(&app, |view, _ctx| { let paths = flattened_paths(view, &hidden_root); assert!(paths.contains(&std_path(&hidden_root))); assert!(paths.contains(&std_path(&visible_file))); assert!(!paths.contains(&std_path(&hidden_file))); }); }); });} #[test]fn selected_hidden_file_is_cleared_when_filtered() { VirtualFS::test( "file_tree_selected_hidden_file_filtered", |dirs, mut vfs| { vfs.mkdir("tree").with_files(vec![ Stub::FileWithContent("tree/.env", "SECRET=value\n"), Stub::FileWithContent("tree/visible.txt", "content\n"), ]); let tree = dirs.tests().join("tree"); let hidden_file = tree.join(".env"); App::test((), |mut app| async move { let (_, repository_metadata_model) = initialize_app(&mut app); set_show_hidden_files(&mut app, true); let (_, file_tree_view) = app.add_window(WindowStyle::NotStealFocus, FileTreeView::new); file_tree_view.update(&mut app, |view, ctx| { view.set_is_active(true, ctx); view.set_root_directories(vec![tree.clone()], ctx); }); await_repository_indexed(&mut app, &repository_metadata_model, &tree).await; file_tree_view.update(&mut app, |view, ctx| { let root_dir = view.root_directories.get(&std_path(&tree)).unwrap(); let (index, _) = root_dir .items .iter() .enumerate() .find(|(_, item)| item.path() == &std_path(&hidden_file)) .expect("hidden file is visible"); let id = super::FileTreeIdentifier { root: std_path(&tree), index, }; view.select_id(&id, ctx); }); set_show_hidden_files(&mut app, false); file_tree_view.read(&app, |view, _ctx| { let paths = flattened_paths(view, &tree); assert!(!paths.contains(&std_path(&hidden_file))); assert!(view.selected_item.is_none()); }); }); }, );} #[test]fn repo_transition_unregisters_lazy_loaded_path() { VirtualFS::test("file_tree_repo_transition", |dirs, mut vfs| { vfs.mkdir("repo/.git/objects") .mkdir("repo/packages/app/src") .with_files(vec![ Stub::FileWithContent("repo/.git/HEAD", "ref: refs/heads/main"), Stub::FileWithContent("repo/.git/config", "[core]\n\trepositoryformatversion = 0"), Stub::FileWithContent("repo/packages/app/src/main.rs", "fn main() {}\n"), ]); let repo_root = dirs.tests().join("repo"); let displayed_root = repo_root.join("packages/app"); let canonical_repo_root = warp_util::standardized_path::StandardizedPath::from_local_canonicalized(&repo_root) .unwrap(); App::test((), |mut app| async move { let (detected_repositories, repository_metadata_model) = initialize_app(&mut app); let (_, file_tree_view) = app.add_window(WindowStyle::NotStealFocus, FileTreeView::new); detected_repositories.update(&mut app, |repositories, _ctx| { repositories.insert_test_repo_root(canonical_repo_root.clone()); }); file_tree_view.update(&mut app, |view, ctx| { view.set_is_active(true, ctx); view.set_root_directories(vec![displayed_root.clone()], ctx); }); file_tree_view.read(&app, |view, _ctx| { assert!( view.registered_lazy_loaded_paths.contains( &warp_util::standardized_path::StandardizedPath::try_from_local( &displayed_root ) .unwrap() ) ); let displayed_std = warp_util::standardized_path::StandardizedPath::try_from_local(&displayed_root) .unwrap(); assert_eq!( view.root_directories .get(&displayed_std) .map(|root_dir| root_dir.entry.root_directory().to_local_path_lossy()), Some(displayed_root.clone()) ); }); repository_metadata_model.read(&app, |model, ctx| { assert!( model.is_lazy_loaded_path( &warp_util::standardized_path::StandardizedPath::try_from_local( &displayed_root ) .unwrap(), ctx ) ); }); repository_metadata_model.update(&mut app, |model, ctx| { model.insert_test_state(canonical_repo_root, build_repo_state(&repo_root), ctx); }); file_tree_view.update(&mut app, |view, ctx| { view.set_root_directories(vec![displayed_root.clone()], ctx); }); file_tree_view.read(&app, |view, _ctx| { let displayed_std = warp_util::standardized_path::StandardizedPath::try_from_local(&displayed_root) .unwrap(); let repo_std = warp_util::standardized_path::StandardizedPath::try_from_local(&repo_root) .unwrap(); assert!(!view.registered_lazy_loaded_paths.contains(&displayed_std)); assert_eq!(view.root_for_path(&displayed_std), Some(repo_std.clone())); assert_eq!( view.root_directories .get(&displayed_std) .map(|root_dir| (**root_dir.entry.root_directory()).clone()), Some(repo_std) ); }); repository_metadata_model.read(&app, |model, ctx| { assert!( !model.is_lazy_loaded_path( &warp_util::standardized_path::StandardizedPath::try_from_local( &displayed_root ) .unwrap(), ctx ) ); }); }); });} #[test]fn repo_backed_unloaded_directory_loads_through_model() { VirtualFS::test("file_tree_repo_backed_load", |dirs, mut vfs| { vfs.mkdir("repo/.git/objects") .mkdir("repo/src/nested") .with_files(vec![ Stub::FileWithContent("repo/.git/HEAD", "ref: refs/heads/main"), Stub::FileWithContent( "repo/.git/config", "[core]\trepositoryformatversion = 0", ), Stub::FileWithContent( "repo/src/nested/main.rs", "fn main() {}", ), ]); let repo_root = dirs.tests().join("repo"); let src_dir = repo_root.join("src"); let nested_dir = repo_root.join("src/nested"); let source_file = repo_root.join("src/nested/main.rs"); let canonical_repo_root = warp_util::standardized_path::StandardizedPath::from_local_canonicalized(&repo_root) .unwrap(); App::test((), |mut app| async move { let (detected_repositories, repository_metadata_model) = initialize_app(&mut app); let (_, file_tree_view) = app.add_window(WindowStyle::NotStealFocus, FileTreeView::new); detected_repositories.update(&mut app, |repositories, _ctx| { repositories.insert_test_repo_root(canonical_repo_root.clone()); }); repository_metadata_model.update(&mut app, |model, ctx| { model.insert_test_state( canonical_repo_root, build_repo_state_with_unloaded_directory(&repo_root), ctx, ); }); file_tree_view.update(&mut app, |view, ctx| { view.set_is_active(true, ctx); view.set_root_directories(vec![repo_root.clone()], ctx); }); file_tree_view.read(&app, |view, _ctx| { assert!( !view .root_directories .get( &warp_util::standardized_path::StandardizedPath::try_from_local( &repo_root ) .unwrap() ) .is_some_and(|root_dir| root_dir.entry.contains( &warp_util::standardized_path::StandardizedPath::try_from_local( &source_file ) .unwrap() )) ); }); file_tree_view.update(&mut app, |view, ctx| { view.ensure_loaded_path( &warp_util::standardized_path::StandardizedPath::try_from_local(&repo_root) .unwrap(), &warp_util::standardized_path::StandardizedPath::try_from_local(&src_dir) .unwrap(), ctx, ); }); await_directory_loaded(&mut app, &repository_metadata_model, &repo_root, &src_dir) .await; file_tree_view.read(&app, |view, _ctx| { assert!( view.root_directories .get( &warp_util::standardized_path::StandardizedPath::try_from_local( &repo_root ) .unwrap() ) .is_some_and(|root_dir| root_dir.entry.contains( &warp_util::standardized_path::StandardizedPath::try_from_local( &nested_dir ) .unwrap() )) ); }); file_tree_view.update(&mut app, |view, ctx| { view.ensure_loaded_path(Lines 1–500 of 1221. Load more
use std::path::Path; use std::sync::Arc; use repo_metadata::entry::{DirectoryEntry, Entry, FileMetadata}; use repo_metadata::file_tree_store::FileTreeState; use repo_metadata::local_model::IndexedRepoState; use repo_metadata::repositories::DetectedRepositories; use repo_metadata::watcher::DirectoryWatcher; use repo_metadata::{RepoMetadataModel, RepositoryIdentifier}; use settings::Setting; use virtual_fs::{Stub, VirtualFS}; use warp_core::ui::appearance::Appearance; use warpui::platform::WindowStyle; use warpui::{App, ModelHandle, SingletonEntity}; use super::FileTreeView; use crate::auth::AuthStateProvider; use crate::server::server_api::team::MockTeamClient; use crate::server::server_api::workspace::MockWorkspaceClient; use crate::settings::CodeSettings; use crate::settings_view::keybindings::KeybindingChangedNotifier; use crate::test_util::settings::initialize_settings_for_tests; use crate::vim_registers::VimRegisters; use crate::workspace::ToastStack; use crate::workspace::sync_inputs::SyncedInputState; use crate::workspaces::user_workspaces::UserWorkspaces; fn std_path(path: &std::path::Path) -> warp_util::standardized_path::StandardizedPath { warp_util::standardized_path::StandardizedPath::try_from_local(path).unwrap() } fn initialize_app( app: &mut App, ) -> ( ModelHandle<DetectedRepositories>, ModelHandle<RepoMetadataModel>, ) { initialize_settings_for_tests(app); app.add_singleton_model(|_| Appearance::mock()); app.add_singleton_model(|_| ToastStack); app.add_singleton_model(|_| SyncedInputState::mock()); app.add_singleton_model(|_| VimRegisters::new()); app.add_singleton_model(|_| KeybindingChangedNotifier::mock()); app.add_singleton_model(|_| AuthStateProvider::new_for_test()); let team_client = Arc::new(MockTeamClient::new()); let workspace_client = Arc::new(MockWorkspaceClient::new()); app.add_singleton_model(|ctx| { UserWorkspaces::mock(team_client.clone(), workspace_client.clone(), vec![], ctx) }); let detected_repositories = app.add_singleton_model(|_| DetectedRepositories::default()); let repository_metadata_model = app.add_singleton_model(RepoMetadataModel::new); (detected_repositories, repository_metadata_model) } fn build_repo_state(repo_root: &std::path::Path) -> FileTreeState { let source_file = Entry::File(FileMetadata::new( repo_root.join("packages/app/src/main.rs"), false, )); let src_dir = Entry::Directory(DirectoryEntry { path: warp_util::standardized_path::StandardizedPath::try_from_local( &repo_root.join("packages/app/src"), ) .unwrap(), children: vec![source_file], ignored: false, loaded: true, }); let app_dir = Entry::Directory(DirectoryEntry { path: warp_util::standardized_path::StandardizedPath::try_from_local( &repo_root.join("packages/app"), ) .unwrap(), children: vec![src_dir], ignored: false, loaded: true, }); let packages_dir = Entry::Directory(DirectoryEntry { path: warp_util::standardized_path::StandardizedPath::try_from_local( &repo_root.join("packages"), ) .unwrap(), children: vec![app_dir], ignored: false, loaded: true, }); let root = Entry::Directory(DirectoryEntry { path: std_path(repo_root), children: vec![packages_dir], ignored: false, loaded: true, }); FileTreeState::new(root, vec![], None) } fn build_repo_state_with_unloaded_directory(repo_root: &std::path::Path) -> FileTreeState { let unloaded_src_dir = Entry::Directory(DirectoryEntry { path: warp_util::standardized_path::StandardizedPath::try_from_local( &repo_root.join("src"), ) .unwrap(), children: vec![], ignored: false, loaded: false, }); let root = Entry::Directory(DirectoryEntry { path: std_path(repo_root), children: vec![unloaded_src_dir], ignored: false, loaded: true, }); FileTreeState::new(root, vec![], None) } fn flattened_paths( view: &FileTreeView, root: &std::path::Path, ) -> Vec<warp_util::standardized_path::StandardizedPath> { view.root_directories .get(&std_path(root)) .expect("root directory is tracked") .items .iter() .map(|item| item.path().clone()) .collect() } async fn await_repository_indexed( app: &mut App, repository_metadata_model: &ModelHandle<RepoMetadataModel>, repo_root: &Path, ) { let id = RepositoryIdentifier::local(std_path(repo_root)); let completion = repository_metadata_model.update(app, |model, ctx| model.repository_indexed(&id, ctx)); completion.await; repository_metadata_model.read(app, |model, ctx| { assert!(matches!( model.repository_state(&id, ctx), Some(IndexedRepoState::Indexed(_)) )); }); futures_lite::future::yield_now().await; } async fn await_directory_loaded( app: &mut App, repository_metadata_model: &ModelHandle<RepoMetadataModel>, repo_root: &Path, dir_path: &Path, ) { let repo_root = std_path(repo_root); let dir_path = std_path(dir_path); let completion = repository_metadata_model .update(app, |model, ctx| { model.load_directory_with_completion(&repo_root, &dir_path, ctx) }) .expect("directory load should start or join an in-flight load"); completion.await.expect("directory should load"); futures_lite::future::yield_now().await; } fn set_show_hidden_files(app: &mut App, show_hidden_files: bool) { CodeSettings::handle(app).update(app, |settings, ctx| { Setting::set_value(&mut settings.show_hidden_files, show_hidden_files, ctx) .expect("show hidden files setting updates"); }); } #[test] fn hidden_files_are_filtered_until_setting_is_enabled() { VirtualFS::test("file_tree_hidden_files_setting", |dirs, mut vfs| { vfs.mkdir("tree/.config").with_files(vec![ Stub::FileWithContent("tree/.env", "SECRET=value\n"), Stub::FileWithContent("tree/.config/settings.toml", ""), Stub::FileWithContent("tree/visible.txt", "content\n"), ]); let tree = dirs.tests().join("tree"); let hidden_file = tree.join(".env"); let hidden_dir = tree.join(".config"); let visible_file = tree.join("visible.txt"); App::test((), |mut app| async move { let (_, repository_metadata_model) = initialize_app(&mut app); set_show_hidden_files(&mut app, false); let (_, file_tree_view) = app.add_window(WindowStyle::NotStealFocus, FileTreeView::new); file_tree_view.update(&mut app, |view, ctx| { view.set_is_active(true, ctx); view.set_root_directories(vec![tree.clone()], ctx); }); await_repository_indexed(&mut app, &repository_metadata_model, &tree).await; file_tree_view.read(&app, |view, _ctx| { let paths = flattened_paths(view, &tree); assert!(paths.contains(&std_path(&tree))); assert!(paths.contains(&std_path(&visible_file))); assert!(!paths.contains(&std_path(&hidden_file))); assert!(!paths.contains(&std_path(&hidden_dir))); }); set_show_hidden_files(&mut app, true); file_tree_view.read(&app, |view, _ctx| { let paths = flattened_paths(view, &tree); assert!(paths.contains(&std_path(&hidden_file))); assert!(paths.contains(&std_path(&hidden_dir))); }); }); }); } #[test] fn hidden_root_directory_is_not_filtered() { VirtualFS::test("file_tree_hidden_root_directory", |dirs, mut vfs| { vfs.mkdir(".config").with_files(vec![ Stub::FileWithContent(".config/settings.toml", ""), Stub::FileWithContent(".config/.secret", ""), ]); let hidden_root = dirs.tests().join(".config"); let visible_file = hidden_root.join("settings.toml"); let hidden_file = hidden_root.join(".secret"); App::test((), |mut app| async move { let (_, repository_metadata_model) = initialize_app(&mut app); set_show_hidden_files(&mut app, false); let (_, file_tree_view) = app.add_window(WindowStyle::NotStealFocus, FileTreeView::new); file_tree_view.update(&mut app, |view, ctx| { view.set_is_active(true, ctx); view.set_root_directories(vec![hidden_root.clone()], ctx); }); await_repository_indexed(&mut app, &repository_metadata_model, &hidden_root).await; file_tree_view.read(&app, |view, _ctx| { let paths = flattened_paths(view, &hidden_root); assert!(paths.contains(&std_path(&hidden_root))); assert!(paths.contains(&std_path(&visible_file))); assert!(!paths.contains(&std_path(&hidden_file))); }); }); }); } #[test] fn selected_hidden_file_is_cleared_when_filtered() { VirtualFS::test( "file_tree_selected_hidden_file_filtered", |dirs, mut vfs| { vfs.mkdir("tree").with_files(vec![ Stub::FileWithContent("tree/.env", "SECRET=value\n"), Stub::FileWithContent("tree/visible.txt", "content\n"), ]); let tree = dirs.tests().join("tree"); let hidden_file = tree.join(".env"); App::test((), |mut app| async move { let (_, repository_metadata_model) = initialize_app(&mut app); set_show_hidden_files(&mut app, true); let (_, file_tree_view) = app.add_window(WindowStyle::NotStealFocus, FileTreeView::new); file_tree_view.update(&mut app, |view, ctx| { view.set_is_active(true, ctx); view.set_root_directories(vec![tree.clone()], ctx); }); await_repository_indexed(&mut app, &repository_metadata_model, &tree).await; file_tree_view.update(&mut app, |view, ctx| { let root_dir = view.root_directories.get(&std_path(&tree)).unwrap(); let (index, _) = root_dir .items .iter() .enumerate() .find(|(_, item)| item.path() == &std_path(&hidden_file)) .expect("hidden file is visible"); let id = super::FileTreeIdentifier { root: std_path(&tree), index, }; view.select_id(&id, ctx); }); set_show_hidden_files(&mut app, false); file_tree_view.read(&app, |view, _ctx| { let paths = flattened_paths(view, &tree); assert!(!paths.contains(&std_path(&hidden_file))); assert!(view.selected_item.is_none()); }); }); }, ); } #[test] fn repo_transition_unregisters_lazy_loaded_path() { VirtualFS::test("file_tree_repo_transition", |dirs, mut vfs| { vfs.mkdir("repo/.git/objects") .mkdir("repo/packages/app/src") .with_files(vec![ Stub::FileWithContent("repo/.git/HEAD", "ref: refs/heads/main"), Stub::FileWithContent("repo/.git/config", "[core]\n\trepositoryformatversion = 0"), Stub::FileWithContent("repo/packages/app/src/main.rs", "fn main() {}\n"), ]); let repo_root = dirs.tests().join("repo"); let displayed_root = repo_root.join("packages/app"); let canonical_repo_root = warp_util::standardized_path::StandardizedPath::from_local_canonicalized(&repo_root) .unwrap(); App::test((), |mut app| async move { let (detected_repositories, repository_metadata_model) = initialize_app(&mut app); let (_, file_tree_view) = app.add_window(WindowStyle::NotStealFocus, FileTreeView::new); detected_repositories.update(&mut app, |repositories, _ctx| { repositories.insert_test_repo_root(canonical_repo_root.clone()); }); file_tree_view.update(&mut app, |view, ctx| { view.set_is_active(true, ctx); view.set_root_directories(vec![displayed_root.clone()], ctx); }); file_tree_view.read(&app, |view, _ctx| { assert!( view.registered_lazy_loaded_paths.contains( &warp_util::standardized_path::StandardizedPath::try_from_local( &displayed_root ) .unwrap() ) ); let displayed_std = warp_util::standardized_path::StandardizedPath::try_from_local(&displayed_root) .unwrap(); assert_eq!( view.root_directories .get(&displayed_std) .map(|root_dir| root_dir.entry.root_directory().to_local_path_lossy()), Some(displayed_root.clone()) ); }); repository_metadata_model.read(&app, |model, ctx| { assert!( model.is_lazy_loaded_path( &warp_util::standardized_path::StandardizedPath::try_from_local( &displayed_root ) .unwrap(), ctx ) ); }); repository_metadata_model.update(&mut app, |model, ctx| { model.insert_test_state(canonical_repo_root, build_repo_state(&repo_root), ctx); }); file_tree_view.update(&mut app, |view, ctx| { view.set_root_directories(vec![displayed_root.clone()], ctx); }); file_tree_view.read(&app, |view, _ctx| { let displayed_std = warp_util::standardized_path::StandardizedPath::try_from_local(&displayed_root) .unwrap(); let repo_std = warp_util::standardized_path::StandardizedPath::try_from_local(&repo_root) .unwrap(); assert!(!view.registered_lazy_loaded_paths.contains(&displayed_std)); assert_eq!(view.root_for_path(&displayed_std), Some(repo_std.clone())); assert_eq!( view.root_directories .get(&displayed_std) .map(|root_dir| (**root_dir.entry.root_directory()).clone()), Some(repo_std) ); }); repository_metadata_model.read(&app, |model, ctx| { assert!( !model.is_lazy_loaded_path( &warp_util::standardized_path::StandardizedPath::try_from_local( &displayed_root ) .unwrap(), ctx ) ); }); }); }); } #[test] fn repo_backed_unloaded_directory_loads_through_model() { VirtualFS::test("file_tree_repo_backed_load", |dirs, mut vfs| { vfs.mkdir("repo/.git/objects") .mkdir("repo/src/nested") .with_files(vec![ Stub::FileWithContent("repo/.git/HEAD", "ref: refs/heads/main"), Stub::FileWithContent( "repo/.git/config", "[core] \trepositoryformatversion = 0", ), Stub::FileWithContent( "repo/src/nested/main.rs", "fn main() {} ", ), ]); let repo_root = dirs.tests().join("repo"); let src_dir = repo_root.join("src"); let nested_dir = repo_root.join("src/nested"); let source_file = repo_root.join("src/nested/main.rs"); let canonical_repo_root = warp_util::standardized_path::StandardizedPath::from_local_canonicalized(&repo_root) .unwrap(); App::test((), |mut app| async move { let (detected_repositories, repository_metadata_model) = initialize_app(&mut app); let (_, file_tree_view) = app.add_window(WindowStyle::NotStealFocus, FileTreeView::new); detected_repositories.update(&mut app, |repositories, _ctx| { repositories.insert_test_repo_root(canonical_repo_root.clone()); }); repository_metadata_model.update(&mut app, |model, ctx| { model.insert_test_state( canonical_repo_root, build_repo_state_with_unloaded_directory(&repo_root), ctx, ); }); file_tree_view.update(&mut app, |view, ctx| { view.set_is_active(true, ctx); view.set_root_directories(vec![repo_root.clone()], ctx); }); file_tree_view.read(&app, |view, _ctx| { assert!( !view .root_directories .get( &warp_util::standardized_path::StandardizedPath::try_from_local( &repo_root ) .unwrap() ) .is_some_and(|root_dir| root_dir.entry.contains( &warp_util::standardized_path::StandardizedPath::try_from_local( &source_file ) .unwrap() )) ); }); file_tree_view.update(&mut app, |view, ctx| { view.ensure_loaded_path( &warp_util::standardized_path::StandardizedPath::try_from_local(&repo_root) .unwrap(), &warp_util::standardized_path::StandardizedPath::try_from_local(&src_dir) .unwrap(), ctx, ); }); await_directory_loaded(&mut app, &repository_metadata_model, &repo_root, &src_dir) .await; file_tree_view.read(&app, |view, _ctx| { assert!( view.root_directories .get( &warp_util::standardized_path::StandardizedPath::try_from_local( &repo_root ) .unwrap() ) .is_some_and(|root_dir| root_dir.entry.contains( &warp_util::standardized_path::StandardizedPath::try_from_local( &nested_dir ) .unwrap() )) ); }); file_tree_view.update(&mut app, |view, ctx| { view.ensure_loaded_path(