summaryrefslogtreecommitdiffstats
path: root/src/interactive/app/tests/journeys_readonly.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/interactive/app/tests/journeys_readonly.rs')
-rw-r--r--src/interactive/app/tests/journeys_readonly.rs264
1 files changed, 264 insertions, 0 deletions
diff --git a/src/interactive/app/tests/journeys_readonly.rs b/src/interactive/app/tests/journeys_readonly.rs
new file mode 100644
index 0000000..f704742
--- /dev/null
+++ b/src/interactive/app/tests/journeys_readonly.rs
@@ -0,0 +1,264 @@
+use anyhow::Result;
+use pretty_assertions::assert_eq;
+use std::ffi::OsString;
+
+use crate::interactive::app::tests::utils::{
+ fixture_str, index_by_name, initialized_app_and_terminal_from_fixture, into_keys,
+ node_by_index, node_by_name,
+};
+use crate::interactive::app::tests::FIXTURE_PATH;
+use crate::interactive::SortMode;
+
+#[test]
+fn simple_user_journey_read_only() -> Result<()> {
+ let long_root = "sample-02/dir";
+ let short_root = "sample-01";
+ let (mut terminal, mut app) =
+ initialized_app_and_terminal_from_fixture(&[short_root, long_root])?;
+
+ // POST-INIT
+ // after initialization, we expect that...
+ {
+ assert_eq!(
+ app.state.sorting,
+ SortMode::SizeDescending,
+ "it will sort entries in descending order by size"
+ );
+
+ assert_eq!(
+ app.state.is_scanning, false,
+ "it will not think it is still scanning"
+ );
+
+ let first_selected_path = OsString::from(format!("{}/{}", FIXTURE_PATH, long_root));
+ assert_eq!(
+ node_by_name(&app, &first_selected_path).name,
+ first_selected_path,
+ "the roots are always listed with the given (possibly long) names",
+ );
+
+ assert_eq!(
+ node_by_name(&app, fixture_str(short_root)),
+ node_by_index(&app, *app.state.selected.as_ref().unwrap()),
+ "it selects the first node in the list",
+ );
+
+ assert_eq!(
+ app.traversal.root_index, app.state.root,
+ "the root is the 'virtual' root",
+ );
+ }
+
+ // SORTING
+ {
+ // when hitting the S key
+ app.process_events(&mut terminal, into_keys(b"s".iter()))?;
+ assert_eq!(
+ app.state.sorting,
+ SortMode::SizeAscending,
+ "it sets the sort mode to ascending by size"
+ );
+ assert_eq!(
+ node_by_index(&app, app.state.entries[0].index),
+ node_by_name(&app, fixture_str(long_root)),
+ "it recomputes the cached entries"
+ );
+ // when hitting the S key again
+ app.process_events(&mut terminal, into_keys(b"s".iter()))?;
+ assert_eq!(
+ app.state.sorting,
+ SortMode::SizeDescending,
+ "it sets the sort mode to descending by size"
+ );
+ assert_eq!(
+ node_by_index(&app, app.state.entries[0].index),
+ node_by_name(&app, fixture_str(short_root)),
+ "it recomputes the cached entries"
+ );
+ }
+
+ // Entry-Navigation
+ {
+ // when hitting the j key
+ app.process_events(&mut terminal, into_keys(b"j".iter()))?;
+ assert_eq!(
+ node_by_name(&app, fixture_str(long_root)),
+ node_by_index(&app, *app.state.selected.as_ref().unwrap()),
+ "it moves the cursor down and selects the next entry based on the current sort mode"
+ );
+ // when hitting it while there is nowhere to go
+ app.process_events(&mut terminal, into_keys(b"j".iter()))?;
+ assert_eq!(
+ node_by_name(&app, fixture_str(long_root)),
+ node_by_index(&app, *app.state.selected.as_ref().unwrap()),
+ "it stays at the previous position"
+ );
+ // when hitting the k key
+ app.process_events(&mut terminal, into_keys(b"k".iter()))?;
+ assert_eq!(
+ node_by_name(&app, fixture_str(short_root)),
+ node_by_index(&app, *app.state.selected.as_ref().unwrap()),
+ "it moves the cursor up and selects the next entry based on the current sort mode"
+ );
+ // when hitting the k key again
+ app.process_events(&mut terminal, into_keys(b"k".iter()))?;
+ assert_eq!(
+ node_by_name(&app, fixture_str(short_root)),
+ node_by_index(&app, *app.state.selected.as_ref().unwrap()),
+ "it stays at the current cursor position as there is nowhere to go"
+ );
+ // when hitting the o key with a directory selected
+ app.process_events(&mut terminal, into_keys(b"o".iter()))?;
+ {
+ let new_root_idx = index_by_name(&app, fixture_str(short_root));
+ assert_eq!(
+ new_root_idx, app.state.root,
+ "it enters the entry if it is a directory, changing the root"
+ );
+ assert_eq!(
+ index_by_name(&app, "dir"),
+ *app.state.selected.as_ref().unwrap(),
+ "it selects the first entry in the directory"
+ );
+
+ // when hitting the u key while inside a sub-directory
+ app.process_events(&mut terminal, into_keys(b"u".iter()))?;
+ {
+ assert_eq!(
+ app.traversal.root_index, app.state.root,
+ "it sets the root to be the (roots) parent directory, being the virtual root"
+ );
+ assert_eq!(
+ node_by_name(&app, fixture_str(short_root)),
+ node_by_index(&app, *app.state.selected.as_ref().unwrap()),
+ "changes the selection to the first item in the list of entries"
+ );
+ }
+ }
+ // when hitting the u key while inside of the root directory
+ // We are moving the cursor down just to have a non-default selection
+ app.process_events(&mut terminal, into_keys(b"ju".iter()))?;
+ {
+ assert_eq!(
+ app.traversal.root_index, app.state.root,
+ "it keeps the root - it can't go further up"
+ );
+ assert_eq!(
+ node_by_name(&app, fixture_str(long_root)),
+ node_by_index(&app, *app.state.selected.as_ref().unwrap()),
+ "keeps the previous selection"
+ );
+ }
+ }
+
+ // Deletion
+ {
+ // when hitting the 'd' key (also move cursor back to start)
+ app.process_events(&mut terminal, into_keys(b"k".iter()))?;
+ let previously_selected_index = *app.state.selected.as_ref().unwrap();
+ app.process_events(&mut terminal, into_keys(b"d".iter()))?;
+ {
+ assert_eq!(
+ Some(1),
+ app.window.mark_pane.as_ref().map(|p| p.marked().len()),
+ "it marks only a single node",
+ );
+ assert!(
+ app.window.mark_pane.as_ref().map_or(false, |p| p
+ .marked()
+ .contains_key(&previously_selected_index)),
+ "it marks the selected node"
+ );
+ assert_eq!(
+ app.state.selected.as_ref().unwrap().index(),
+ app.state.entries[1].index.index(),
+ "moves the cursor down one level to facilitate many markings in a row"
+ );
+ }
+
+ // when hitting the 'd' key again
+ {
+ app.process_events(&mut terminal, into_keys(b"d".iter()))?;
+
+ assert_eq!(
+ Some(2),
+ app.window.mark_pane.as_ref().map(|p| p.marked().len()),
+ "it marks the currently selected, second node",
+ );
+
+ assert_eq!(
+ app.state.selected.as_ref().unwrap().index(),
+ app.state.entries[1].index.index(),
+ "it could not advance the cursor, thus the newly marked item is still selected"
+ );
+ }
+
+ // when hitting the 'd' key once again
+ {
+ app.process_events(&mut terminal, into_keys(b"d".iter()))?;
+
+ assert_eq!(
+ Some(1),
+ app.window.mark_pane.as_ref().map(|p| p.marked().len()),
+ "it toggled the previous selected entry off",
+ );
+
+ assert!(
+ app.window.mark_pane.as_ref().map_or(false, |p| p
+ .marked()
+ .contains_key(&previously_selected_index)),
+ "it leaves the first selected entry marked"
+ );
+ }
+ // when hitting the spacebar (after moving up to the first entry)
+ {
+ app.process_events(&mut terminal, into_keys(b"k ".iter()))?;
+
+ assert_eq!(
+ None,
+ app.window.mark_pane.as_ref().map(|p| p.marked().len()),
+ "it toggles the item off",
+ );
+
+ assert_eq!(
+ node_by_index(&app, previously_selected_index),
+ node_by_index(&app, *app.state.selected.as_ref().unwrap()),
+ "it does not advance the selection"
+ );
+ }
+ }
+
+ // Marking
+ {
+ // select something
+ app.process_events(&mut terminal, into_keys(b" j ".iter()))?;
+ assert_eq!(
+ Some(false),
+ app.window.mark_pane.as_ref().map(|p| p.has_focus()),
+ "the marker pane starts out without focus",
+ );
+
+ assert_eq!(
+ Some(2),
+ app.window.mark_pane.as_ref().map(|p| p.marked().len()),
+ "it has two items marked",
+ );
+
+ // when advancing the selection to the marker pane
+ app.process_events(&mut terminal, into_keys(b"\t".iter()))?;
+ {
+ assert_eq!(
+ Some(true),
+ app.window.mark_pane.as_ref().map(|p| p.has_focus()),
+ "after tabbing into it, it has focus",
+ );
+ }
+
+ // TODO: a bunch of additional tests are missing (handling of markers, deselecting them)
+ // Yes, caught me, no TDD for these things, just because in Rust it's not needed as things
+ // tend to just work when they compile, and while experimenting, tests can be in the way.
+ // However, if Dua should be more widely used, we need CI and these tests written.
+ }
+
+ Ok(())
+}