From d2cfae5dc72d2597a0ac9b62b65cb179d9f1aab6 Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Sun, 4 Feb 2024 07:28:51 -0500 Subject: [PATCH] Unit tests for tab::Message::Click Tests for selecting items and opening items with double clicks. --- src/app.rs | 41 +++++++++++++++++++++++++ src/tab.rs | 90 +++++++++++++++++++++++++++++++++++++++--------------- 2 files changed, 106 insertions(+), 25 deletions(-) diff --git a/src/app.rs b/src/app.rs index bb962ed..f323d73 100644 --- a/src/app.rs +++ b/src/app.rs @@ -1198,6 +1198,47 @@ pub(crate) mod test_utils { Ok(entries) } + /// Filter `path` for directories + pub fn filter_dirs(path: &Path) -> io::Result> { + Ok(path.read_dir()?.filter_map(|entry| { + entry.ok().and_then(|entry| { + let path = entry.path(); + if path.is_dir() { + Some(path) + } else { + None + } + }) + })) + } + + /// Boiler plate for Tab tests + pub fn tab_click_new( + files: usize, + hidden: usize, + dirs: usize, + nested: usize, + name_len: usize, + ) -> io::Result<(TempDir, Tab)> { + let fs = simple_fs(files, hidden, dirs, nested, name_len)?; + let path = fs.path(); + + // New tab with items + let location = Location::Path(path.to_owned()); + let items = location.scan(); + let mut tab = Tab::new(location); + tab.items_opt = Some(items); + + // Ensure correct number of directories as a sanity check + let items = tab + .items_opt + .as_deref() + .expect("tab should be populated with Items"); + assert_eq!(NUM_DIRS, items.len()); + + Ok((fs, tab)) + } + /// Equality for [Path] and [Item]. pub fn eq_path_item(path: &Path, item: &Item) -> bool { let name = path diff --git a/src/tab.rs b/src/tab.rs index 749f001..e127904 100644 --- a/src/tab.rs +++ b/src/tab.rs @@ -1044,20 +1044,53 @@ mod tests { use super::{scan_path, Item, Location, Message, Tab}; use crate::app::test_utils::{ - assert_eq_tab_path, assert_eq_tab_path_contents, empty_fs, eq_path_item, simple_fs, - sort_files, NAME_LEN, NUM_DIRS, NUM_FILES, NUM_HIDDEN, NUM_NESTED, + assert_eq_tab_path, assert_eq_tab_path_contents, empty_fs, eq_path_item, filter_dirs, + read_dir_sorted, simple_fs, sort_files, tab_click_new, NAME_LEN, NUM_DIRS, NUM_FILES, + NUM_HIDDEN, NUM_NESTED, }; + // Boilerplate for tab tests. Checks if simulated clicks selected items. + fn tab_selects_item( + clicks: &[usize], + modifiers: Modifiers, + expected_selected: &[bool], + ) -> io::Result<()> { + let (_fs, mut tab) = tab_click_new(NUM_FILES, NUM_NESTED, NUM_DIRS, NUM_NESTED, NAME_LEN)?; + + // Simulate clicks by triggering Message::Click + for &click in clicks { + debug!("Emitting Message::Click(Some({click})) with modifiers: {modifiers:?}"); + tab.update(Message::Click(Some(click)), modifiers); + } + + let items = tab + .items_opt + .as_deref() + .expect("tab should be populated with items"); + + for (i, (&expected, actual)) in expected_selected.into_iter().zip(items).enumerate() { + assert_eq!( + expected, + actual.selected, + "expected index {i} to be {}", + if expected { + "selected but it was deselected" + } else { + "deselected but it was selected" + } + ); + } + + Ok(()) + } + #[test] fn scan_path_succeeds_on_valid_path() -> io::Result<()> { let fs = simple_fs(NUM_FILES, NUM_HIDDEN, NUM_DIRS, NUM_NESTED, NAME_LEN)?; let path = fs.path(); - let mut entries: Vec<_> = path - .read_dir()? - .map(|maybe_entry| maybe_entry.map(|entry| entry.path())) - .collect::>()?; - entries.sort_by(|a, b| sort_files(a, b)); + // Read directory entries and sort as cosmic-files does + let entries = read_dir_sorted(path)?; debug!("Calling scan_path(\"{}\")", path.display()); let actual = scan_path(&path.to_owned()); @@ -1111,18 +1144,7 @@ mod tests { let path = fs.path(); // Next directory in temp directory - let next_dir = path - .read_dir()? - .filter_map(|entry| { - entry.ok().and_then(|entry| { - let path = entry.path(); - if path.is_dir() { - Some(path) - } else { - None - } - }) - }) + let next_dir = filter_dirs(path)? .next() .expect("temp directory should have at least one directory"); @@ -1150,20 +1172,38 @@ mod tests { #[test] fn tab_click_single_selects_item() -> io::Result<()> { - let fs = simple_fs(NUM_FILES, NUM_NESTED, NUM_DIRS, NUM_NESTED, NAME_LEN)?; - let path = fs.path(); - - todo!() + // Select the second directory with no keys held down + tab_selects_item(&[1], Modifiers::empty(), &[false, true]) } #[test] fn tab_click_double_opens_folder() -> io::Result<()> { - unimplemented!() + let (fs, mut tab) = tab_click_new(NUM_FILES, NUM_NESTED, NUM_DIRS, NUM_NESTED, NAME_LEN)?; + let path = fs.path(); + + // Simulate double clicking second directory + debug!("Emitting first Message::Click(Some(1))"); + tab.update(Message::Click(Some(1)), Modifiers::empty()); + debug!("Emitting second Message::Click(Some(1))"); + tab.update(Message::Click(Some(1)), Modifiers::empty()); + + // Path to second directory + let second_dir = read_dir_sorted(path)? + .iter() + .filter(|p| p.is_dir()) + .nth(1) + .expect("should be at least two directories"); + + // Location should have changed to second_dir + assert_eq_tab_path(&tab, &second_dir); + + Ok(()) } #[test] fn tab_click_ctrl_selects_multiple() -> io::Result<()> { - unimplemented!() + // Select the first and second directory by holding down ctrl + tab_selects_item(&[0, 1], Modifiers::CTRL, &[true, true]) } #[test]