summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPiotr Wach <pwach@bloomberg.net>2024-01-08 23:17:53 +0000
committerPiotr Wach <pwach@bloomberg.net>2024-01-08 23:17:53 +0000
commitd903ea67a4f77c9483aed7bda1ef6694ee4465da (patch)
tree3254eadc317a6899bbce054d764b4bf2f757361d /src
parent6c63bf5a33ebb6b98516ca9a96796facfdab2277 (diff)
Fixed tests
Diffstat (limited to 'src')
-rw-r--r--src/interactive/app/eventloop.rs103
-rw-r--r--src/interactive/app/terminal_app.rs25
-rw-r--r--src/interactive/app/tests/journeys_readonly.rs48
-rw-r--r--src/interactive/app/tests/journeys_with_writes.rs6
-rw-r--r--src/interactive/app/tests/utils.rs34
-rw-r--r--src/traverse.rs14
6 files changed, 144 insertions, 86 deletions
diff --git a/src/interactive/app/eventloop.rs b/src/interactive/app/eventloop.rs
index 1a8539d..2de51b6 100644
--- a/src/interactive/app/eventloop.rs
+++ b/src/interactive/app/eventloop.rs
@@ -10,7 +10,7 @@ use crossbeam::channel::Receiver;
use crosstermion::crossterm::event::{KeyCode, KeyEvent, KeyEventKind, KeyModifiers};
use crosstermion::input::Event;
use dua::{
- traverse::{EntryData, ProcessEventResult, RunningTraversal, Traversal},
+ traverse::{EntryData, TraversalProcessingEvent, RunningTraversal, Traversal},
WalkOptions, WalkResult,
};
use std::path::PathBuf;
@@ -70,7 +70,7 @@ impl AppState {
walk_options: &WalkOptions,
input: Vec<PathBuf>,
) -> Result<()> {
- let running_traversal = RunningTraversal::new(traversal.root_index, walk_options, input)?;
+ let running_traversal = RunningTraversal::start(traversal.root_index, walk_options, input)?;
self.running_traversal = Some(running_traversal);
Ok(())
}
@@ -104,48 +104,71 @@ impl AppState {
self.refresh_screen(window, traversal, display, terminal)?;
loop {
- if let Some(running_traversal) = &mut self.running_traversal {
- crossbeam::select! {
- recv(events) -> event => {
- let Ok(event) = event else {
- continue;
- };
- let result = self.process_event(
- window,
- traversal,
- display,
- terminal,
- event)?;
- if let Some(processing_result) = result {
- return Ok(processing_result);
- }
- },
- recv(&running_traversal.event_rx) -> event => {
- let Ok(event) = event else {
- continue;
- };
-
- let result = running_traversal.process_event(traversal, event);
- if result != ProcessEventResult::NoOp {
- if result == ProcessEventResult::Finished {
- self.is_scanning = false;
- self.running_traversal = None;
- }
- self.update_state(traversal);
- self.refresh_screen(window, traversal, display, terminal)?;
+ if let Some(result) = self.process_event(
+ window,
+ traversal,
+ display,
+ terminal,
+ &events,
+ )? {
+ return Ok(result);
+ }
+ }
+ }
+
+ pub fn process_event<B>(
+ &mut self,
+ window: &mut MainWindow,
+ traversal: &mut Traversal,
+ display: &mut DisplayOptions,
+ terminal: &mut Terminal<B>,
+ events: &Receiver<Event>,
+ ) -> Result<Option<ProcessingResult>>
+ where
+ B: Backend,
+ {
+ if let Some(running_traversal) = &mut self.running_traversal {
+ crossbeam::select! {
+ recv(events) -> event => {
+ let Ok(event) = event else {
+ return Ok(Some(ProcessingResult::ExitRequested(WalkResult { num_errors: 0 })));
+ };
+ let result = self.process_terminal_event(
+ window,
+ traversal,
+ display,
+ terminal,
+ event)?;
+ if let Some(processing_result) = result {
+ return Ok(Some(processing_result));
+ }
+ },
+ recv(&running_traversal.event_rx) -> event => {
+ let Ok(event) = event else {
+ return Ok(None);
+ };
+
+ let result = running_traversal.process_event(traversal, event);
+ if result != TraversalProcessingEvent::None {
+ if result == TraversalProcessingEvent::Finished {
+ self.is_scanning = false;
+ self.running_traversal = None;
}
+ self.update_state(traversal);
+ self.refresh_screen(window, traversal, display, terminal)?;
}
}
- } else {
- let Ok(event) = events.recv() else {
- continue;
- };
- let result = self.process_event(window, traversal, display, terminal, event)?;
- if let Some(processing_result) = result {
- return Ok(processing_result);
- }
+ }
+ } else {
+ let Ok(event) = events.recv() else {
+ return Ok(Some(ProcessingResult::ExitRequested(WalkResult { num_errors: 0 })));
+ };
+ let result = self.process_terminal_event(window, traversal, display, terminal, event)?;
+ if let Some(processing_result) = result {
+ return Ok(Some(processing_result));
}
}
+ Ok(None)
}
fn update_state(&mut self, traversal: &Traversal) {
@@ -165,7 +188,7 @@ impl AppState {
self.reset_message(); // force "scanning" to appear
}
- fn process_event<B>(
+ fn process_terminal_event<B>(
&mut self,
window: &mut MainWindow,
traversal: &mut Traversal,
diff --git a/src/interactive/app/terminal_app.rs b/src/interactive/app/terminal_app.rs
index 757ac76..82d7199 100644
--- a/src/interactive/app/terminal_app.rs
+++ b/src/interactive/app/terminal_app.rs
@@ -103,4 +103,29 @@ impl TerminalApp {
ProcessingResult::ExitRequested(res) => Ok(res),
}
}
+
+ pub fn run_until_traversed<B>(
+ &mut self,
+ terminal: &mut Terminal<B>,
+ events: Receiver<Event>,
+ ) -> Result<WalkResult>
+ where
+ B: Backend
+ {
+ while self.state.running_traversal.is_some() {
+ match self.state.process_event(
+ &mut self.window,
+ &mut self.traversal,
+ &mut self.display,
+ terminal,
+ &events,
+ )? {
+ Some(ProcessingResult::ExitRequested(res)) => {
+ return Ok(res);
+ }
+ _ => {}
+ }
+ }
+ Ok(WalkResult { num_errors: 0 })
+ }
}
diff --git a/src/interactive/app/tests/journeys_readonly.rs b/src/interactive/app/tests/journeys_readonly.rs
index 72daf03..4821145 100644
--- a/src/interactive/app/tests/journeys_readonly.rs
+++ b/src/interactive/app/tests/journeys_readonly.rs
@@ -27,12 +27,9 @@ fn init_from_pdu_results() -> Result<()> {
fn simple_user_journey_read_only() -> Result<()> {
let long_root = "sample-02/dir";
let short_root = "sample-01";
- let (mut terminal, mut app, traversal_events) =
+ let (mut terminal, mut app) =
initialized_app_and_terminal_from_fixture(&[short_root, long_root])?;
-
- // TODO: process traversal events before continuing?
- // let (key_send, key_receive) = crossbeam::channel::bounded(0);
-
+
// POST-INIT
// after initialization, we expect that...
{
@@ -70,28 +67,28 @@ fn simple_user_journey_read_only() -> Result<()> {
// SORTING
{
// when hitting the M key
- app.process_events(&mut terminal, into_codes("m"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("m"))?;
assert_eq!(
app.state.sorting,
SortMode::MTimeDescending,
"it sets the sort mode to descending by mtime"
);
// when hitting the M key again
- app.process_events(&mut terminal, into_codes("m"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("m"))?;
assert_eq!(
app.state.sorting,
SortMode::MTimeAscending,
"it sets the sort mode to ascending by mtime"
);
// when hitting the C key
- app.process_events(&mut terminal, into_codes("c"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("c"))?;
assert_eq!(
app.state.sorting,
SortMode::CountDescending,
"it sets the sort mode to descending by count"
);
// when hitting the C key again
- app.process_events(&mut terminal, into_codes("c"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("c"))?;
assert_eq!(
app.state.sorting,
SortMode::CountAscending,
@@ -103,7 +100,7 @@ fn simple_user_journey_read_only() -> Result<()> {
"it recomputes the cached items"
);
// when hitting the S key
- app.process_events(&mut terminal, into_codes("s"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("s"))?;
assert_eq!(
app.state.sorting,
SortMode::SizeDescending,
@@ -115,14 +112,14 @@ fn simple_user_journey_read_only() -> Result<()> {
"it recomputes the cached items"
);
// when hitting the S key again
- app.process_events(&mut terminal, into_codes("s"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("s"))?;
assert_eq!(
app.state.sorting,
SortMode::SizeAscending,
"it sets the sort mode to ascending by size"
);
// hit the S key again to get Descending - the rest depends on it
- app.process_events(&mut terminal, into_codes("s"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("s"))?;
assert_eq!(app.state.sorting, SortMode::SizeDescending,);
assert_eq!(
@@ -135,35 +132,35 @@ fn simple_user_journey_read_only() -> Result<()> {
// Entry-Navigation
{
// when hitting the j key
- app.process_events(&mut terminal, into_codes("j"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("j"))?;
assert_eq!(
node_by_name(&app, fixture_str(long_root)),
node_by_index(&app, *app.state.navigation().selected.as_ref().unwrap()),
"it moves the cursor down and selects the next item based on the current sort mode"
);
// when hitting it while there is nowhere to go
- app.process_events(&mut terminal, into_codes("j"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("j"))?;
assert_eq!(
node_by_name(&app, fixture_str(long_root)),
node_by_index(&app, *app.state.navigation().selected.as_ref().unwrap()),
"it stays at the previous position"
);
// when hitting the k key
- app.process_events(&mut terminal, into_codes("k"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("k"))?;
assert_eq!(
node_by_name(&app, fixture_str(short_root)),
node_by_index(&app, *app.state.navigation().selected.as_ref().unwrap()),
"it moves the cursor up and selects the next item based on the current sort mode"
);
// when hitting the k key again
- app.process_events(&mut terminal, into_codes("k"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("k"))?;
assert_eq!(
node_by_name(&app, fixture_str(short_root)),
node_by_index(&app, *app.state.navigation().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_codes("o"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("o"))?;
{
let new_root_idx = index_by_name(&app, fixture_str(short_root));
assert_eq!(
@@ -178,7 +175,7 @@ fn simple_user_journey_read_only() -> Result<()> {
);
// when hitting the u key while inside a sub-directory
- app.process_events(&mut terminal, into_codes("u"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("u"))?;
{
assert_eq!(
app.traversal.root_index,
@@ -194,7 +191,7 @@ fn simple_user_journey_read_only() -> Result<()> {
}
// 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_codes("ju"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("ju"))?;
{
assert_eq!(
app.traversal.root_index,
@@ -212,9 +209,9 @@ fn simple_user_journey_read_only() -> Result<()> {
// Deletion
{
// when hitting the 'd' key (also move cursor back to start)
- app.process_events(&mut terminal, into_codes("k"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("k"))?;
let previously_selected_index = *app.state.navigation().selected.as_ref().unwrap();
- app.process_events(&mut terminal, into_codes("d"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("d"))?;
{
assert_eq!(
Some(1),
@@ -236,7 +233,7 @@ fn simple_user_journey_read_only() -> Result<()> {
// when hitting the 'd' key again
{
- app.process_events(&mut terminal, into_codes("d"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("d"))?;
assert_eq!(
Some(2),
@@ -253,7 +250,7 @@ fn simple_user_journey_read_only() -> Result<()> {
// when hitting the 'd' key once again
{
- app.process_events(&mut terminal, into_codes("d"), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("d"))?;
assert_eq!(
Some(1),
@@ -270,7 +267,7 @@ fn simple_user_journey_read_only() -> Result<()> {
}
// when hitting the spacebar (after moving up to the first entry)
{
- app.process_events(&mut terminal, into_codes("k "), traversal_events)?;
+ app.process_events(&mut terminal, into_codes("k "))?;
assert_eq!(
None,
@@ -289,7 +286,7 @@ fn simple_user_journey_read_only() -> Result<()> {
// Marking
{
// select something
- app.process_events(&mut terminal, into_codes(" j "), traversal_events)?;
+ app.process_events(&mut terminal, into_codes(" j "))?;
assert_eq!(
Some(false),
app.window.mark_pane.as_ref().map(|p| p.has_focus()),
@@ -306,7 +303,6 @@ fn simple_user_journey_read_only() -> Result<()> {
app.process_events(
&mut terminal,
into_keys(Some(KeyCode::Tab)),
- traversal_events,
)?;
{
assert_eq!(
diff --git a/src/interactive/app/tests/journeys_with_writes.rs b/src/interactive/app/tests/journeys_with_writes.rs
index 80e65d7..09ca1be 100644
--- a/src/interactive/app/tests/journeys_with_writes.rs
+++ b/src/interactive/app/tests/journeys_with_writes.rs
@@ -9,6 +9,8 @@ use pretty_assertions::assert_eq;
#[test]
#[cfg(not(target_os = "windows"))] // it stopped working here, don't know if it's truly broken or if it's the test. Let's wait for windows users to report.
fn basic_user_journey_with_deletion() -> Result<()> {
+ use crate::interactive::app::tests::utils::{into_keys, into_events};
+
let fixture = WritableFixture::from("sample-02");
let (mut terminal, mut app) = initialized_app_and_terminal_from_paths(&[fixture.root.clone()])?;
@@ -26,11 +28,11 @@ fn basic_user_journey_with_deletion() -> Result<()> {
// When selecting the marker window and pressing the combination to delete entries
app.process_events(
&mut terminal,
- vec![
+ into_events(vec![
Event::Key(KeyCode::Tab.into()),
Event::Key(KeyEvent::new(KeyCode::Char('r'), KeyModifiers::CONTROL)),
]
- .into_iter(),
+ .into_iter()),
)?;
assert!(
app.window.mark_pane.is_none(),
diff --git a/src/interactive/app/tests/utils.rs b/src/interactive/app/tests/utils.rs
index 133dd9a..4f8c6fd 100644
--- a/src/interactive/app/tests/utils.rs
+++ b/src/interactive/app/tests/utils.rs
@@ -1,6 +1,6 @@
use anyhow::{Context, Error, Result};
-use crossbeam::channel::Receiver;
-use crosstermion::crossterm::event::KeyCode;
+use crossbeam::channel::{Receiver, Sender};
+use crosstermion::{crossterm::{event::{KeyCode, KeyModifiers, KeyEvent}}, input::Event};
use dua::{
traverse::{EntryData, Tree, TreeIndex},
ByteFormat, TraversalSorting, WalkOptions,
@@ -21,15 +21,25 @@ use tui_react::Terminal;
use crate::interactive::{app::tests::FIXTURE_PATH, terminal_app::TerminalApp};
+pub fn into_events<'a>(
+ events: impl IntoIterator<Item = Event> + 'a,
+) -> Receiver<Event> {
+ let (key_send, key_receive) = crossbeam::channel::unbounded();
+ for event in events {
+ _ = key_send.send(event);
+ }
+ key_receive
+}
+
pub fn into_keys<'a>(
codes: impl IntoIterator<Item = KeyCode> + 'a,
-) -> impl Iterator<Item = crosstermion::input::Event> + 'a {
- codes
+) -> Receiver<Event> {
+ into_events(codes
.into_iter()
- .map(|code| crosstermion::input::Event::Key(code.into()))
+ .map(|code| crosstermion::input::Event::Key(code.into())))
}
-pub fn into_codes(input: &str) -> impl Iterator<Item = crosstermion::input::Event> + '_ {
+pub fn into_codes<'a>(input: &'a str) -> Receiver<Event> {
into_keys(input.chars().map(KeyCode::Char))
}
@@ -172,7 +182,7 @@ pub fn fixture_str(p: impl AsRef<Path>) -> String {
pub fn initialized_app_and_terminal_with_closure(
fixture_paths: &[impl AsRef<Path>],
mut convert: impl FnMut(&Path) -> PathBuf,
-) -> Result<(Terminal<TestBackend>, TerminalApp, Receiver<TraversalEvent>), Error> {
+) -> Result<(Terminal<TestBackend>, TerminalApp), Error> {
let mut terminal = new_test_terminal()?;
std::env::set_current_dir(Path::new(env!("CARGO_MANIFEST_DIR")))?;
@@ -185,12 +195,14 @@ pub fn initialized_app_and_terminal_with_closure(
ignore_dirs: Default::default(),
};
+ let (key_send, key_receive) = crossbeam::channel::bounded(0);
let mut app = TerminalApp::initialize(&mut terminal, walk_options, ByteFormat::Metric)?;
let input_paths = fixture_paths.iter().map(|c| convert(c.as_ref())).collect();
- let traversal_rx = app.traverse(input_paths)?;
+ app.traverse(input_paths)?;
+ app.run_until_traversed(&mut terminal, key_receive);
- Ok((terminal, app, traversal_rx))
+ Ok((terminal, app))
}
pub fn new_test_terminal() -> std::io::Result<Terminal<TestBackend>> {
@@ -199,7 +211,7 @@ pub fn new_test_terminal() -> std::io::Result<Terminal<TestBackend>> {
pub fn initialized_app_and_terminal_from_paths(
fixture_paths: &[PathBuf],
-) -> Result<(Terminal<TestBackend>, TerminalApp, Receiver<TraversalEvent>), Error> {
+) -> Result<(Terminal<TestBackend>, TerminalApp), Error> {
fn to_path_buf(p: &Path) -> PathBuf {
p.to_path_buf()
}
@@ -208,7 +220,7 @@ pub fn initialized_app_and_terminal_from_paths(
pub fn initialized_app_and_terminal_from_fixture(
fixture_paths: &[&str],
-) -> Result<(Terminal<TestBackend>, TerminalApp, Receiver<TraversalEvent>), Error> {
+) -> Result<(Terminal<TestBackend>, TerminalApp), Error> {
#[allow(clippy::redundant_closure)]
// doesn't actually work that way due to borrowchk - probably a bug
initialized_app_and_terminal_with_closure(fixture_paths, |p| fixture(p))
diff --git a/src/traverse.rs b/src/traverse.rs
index 0aba859..f221ace 100644
--- a/src/traverse.rs
+++ b/src/traverse.rs
@@ -143,14 +143,14 @@ pub struct RunningTraversal {
}
#[derive(PartialEq)]
-pub enum ProcessEventResult {
- NoOp,
+pub enum TraversalProcessingEvent {
+ None,
UpdateIsReady,
Finished,
}
impl RunningTraversal {
- pub fn new(
+ pub fn start(
root_idx: TreeIndex,
walk_options: &WalkOptions,
input: Vec<PathBuf>,
@@ -213,7 +213,7 @@ impl RunningTraversal {
&mut self,
t: &mut Traversal,
event: TraversalEvent,
- ) -> ProcessEventResult {
+ ) -> TraversalProcessingEvent {
match event {
TraversalEvent::Entry(entry, root_path, device_id) => {
t.entries_traversed += 1;
@@ -335,7 +335,7 @@ impl RunningTraversal {
if let Some(throttle) = &self.throttle {
if throttle.can_update() {
- return ProcessEventResult::UpdateIsReady;
+ return TraversalProcessingEvent::UpdateIsReady;
}
}
}
@@ -370,10 +370,10 @@ impl RunningTraversal {
t.total_bytes = Some(root_size);
t.elapsed = Some(t.start.elapsed());
- return ProcessEventResult::Finished;
+ return TraversalProcessingEvent::Finished;
}
}
- ProcessEventResult::NoOp
+ TraversalProcessingEvent::None
}
}