refactoring

This commit is contained in:
vcoppe committed 2026-10-11 10:54:06 +02:00
1 parent 9adb8e7221
commit d84ca47745
3 files changed
+141 -131

No files matched your search

+1 -51
View File
@@ -29,11 +29,6 @@ pub struct Engine {
clipboard: Option<Clipboard>, clipboard: Option<Clipboard>,
/// Whether what is stored was written by a newer version (see [`Engine::mark_outdated`]). /// Whether what is stored was written by a newer version (see [`Engine::mark_outdated`]).
outdated: bool, outdated: bool,
/// What the tests of the last action read, see `Engine::run`.
#[cfg(test)]
last: Outcome,
#[cfg(test)]
last_error: Option<CommandError>,
} }
impl Engine { impl Engine {
@@ -160,7 +155,7 @@ impl Engine {
self.stack = Stack::restored(files); self.stack = Stack::restored(files);
self.refresh(diff.as_ref()); self.refresh(diff.as_ref());
sort_diff(&mut diff, &self.order.0); sort_diff(&mut diff, &self.order.0);
let outcome = Outcome { Outcome {
changed: diff.is_some() changed: diff.is_some()
|| self.order.0 != order_before || self.order.0 != order_before
|| self.selection != selection_before, || self.selection != selection_before,
@@ -168,13 +163,7 @@ impl Engine {
order_changed: self.order.0 != order_before, order_changed: self.order.0 != order_before,
selection_changed: self.selection != selection_before, selection_changed: self.selection != selection_before,
clipboard_changed: false, clipboard_changed: false,
};
#[cfg(test)]
{
self.last = outcome.clone();
self.last_error = None;
} }
outcome
} }
/// Tells that what is stored was written by a newer version of the app, which cannot be read /// Tells that what is stored was written by a newer version of the app, which cannot be read
@@ -232,16 +221,6 @@ impl Engine {
/// it did nothing: an edit that fails or has nothing to do, or any change of the files while /// it did nothing: an edit that fails or has nothing to do, or any change of the files while
/// they are outdated (see [`Engine::is_outdated`]). /// they are outdated (see [`Engine::is_outdated`]).
pub fn execute(&mut self, action: Action) -> Result<Outcome, CommandError> { pub fn execute(&mut self, action: Action) -> Result<Outcome, CommandError> {
let result = self.apply(action);
#[cfg(test)]
{
self.last = result.clone().unwrap_or_default();
self.last_error = result.as_ref().err().cloned();
}
result
}
fn apply(&mut self, action: Action) -> Result<Outcome, CommandError> {
if self.outdated { if self.outdated {
return Err(CommandError::Outdated); return Err(CommandError::Outdated);
} }
@@ -365,34 +344,5 @@ fn sort_diff(diff: &mut Option<Diff>, order: &[FileId]) {
} }
} }
#[cfg(test)]
impl Engine {
/// Executes an action and tells whether it changed anything. What it did is kept for the
/// accessors below, which the tests read right after.
pub(crate) fn run(&mut self, action: Action) -> bool {
self.execute(action).is_ok_and(|outcome| outcome.changed)
}
pub(crate) fn last_diff(&self) -> Option<&Diff> {
self.last.diff.as_ref()
}
pub(crate) fn last_error(&self) -> Option<&CommandError> {
self.last_error.as_ref()
}
pub(crate) fn order_changed(&self) -> bool {
self.last.order_changed
}
pub(crate) fn selection_changed(&self) -> bool {
self.last.selection_changed
}
pub(crate) fn clipboard_changed(&self) -> bool {
self.last.clipboard_changed
}
}
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
+123 -64
View File
@@ -8,6 +8,66 @@ use crate::{
use super::*; use super::*;
/// An engine that remembers what the last action it was given did, for the tests to read right
/// after (see `run`).
#[derive(Default)]
struct TestEngine {
engine: Engine,
last: Outcome,
last_error: Option<CommandError>,
}
impl std::ops::Deref for TestEngine {
type Target = Engine;
fn deref(&self) -> &Engine {
&self.engine
}
}
impl std::ops::DerefMut for TestEngine {
fn deref_mut(&mut self) -> &mut Engine {
&mut self.engine
}
}
impl TestEngine {
/// Executes an action and tells whether it changed anything.
fn run(&mut self, action: Action) -> bool {
let result = self.engine.execute(action);
self.last = result.clone().unwrap_or_default();
self.last_error = result.as_ref().err().cloned();
result.is_ok_and(|outcome| outcome.changed)
}
fn restore(&mut self, restored: Restored) -> Outcome {
let outcome = self.engine.restore(restored);
self.last = outcome.clone();
self.last_error = None;
outcome
}
fn last_diff(&self) -> Option<&Diff> {
self.last.diff.as_ref()
}
fn last_error(&self) -> Option<&CommandError> {
self.last_error.as_ref()
}
fn order_changed(&self) -> bool {
self.last.order_changed
}
fn selection_changed(&self) -> bool {
self.last.selection_changed
}
fn clipboard_changed(&self) -> bool {
self.last.clipboard_changed
}
}
fn expand(intervals: &crate::Intervals, len: usize) -> Vec<u8> { fn expand(intervals: &crate::Intervals, len: usize) -> Vec<u8> {
let mut values = Vec::new(); let mut values = Vec::new();
for (i, value) in intervals.values.iter().enumerate() { for (i, value) in intervals.values.iter().enumerate() {
@@ -17,11 +77,11 @@ fn expand(intervals: &crate::Intervals, len: usize) -> Vec<u8> {
values values
} }
fn edit(engine: &mut Engine, command: Command) -> bool { fn edit(engine: &mut TestEngine, command: Command) -> bool {
engine.run(Action::Edit(command)) engine.run(Action::Edit(command))
} }
fn new(engine: &mut Engine, name: &str) -> bool { fn new(engine: &mut TestEngine, name: &str) -> bool {
edit( edit(
engine, engine,
Command::New(New { Command::New(New {
@@ -31,7 +91,7 @@ fn new(engine: &mut Engine, name: &str) -> bool {
) )
} }
fn load(engine: &mut Engine, path: &str) -> bool { fn load(engine: &mut TestEngine, path: &str) -> bool {
let data = std::fs::read(path).unwrap(); let data = std::fs::read(path).unwrap();
edit( edit(
engine, engine,
@@ -51,14 +111,14 @@ fn selected(engine: &Engine) -> Vec<FileId> {
#[test] #[test]
fn test_load_file() { fn test_load_file() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
assert!(load(&mut engine, "data/simple.gpx")); assert!(load(&mut engine, "data/simple.gpx"));
assert_eq!(engine.statistics_buffer.total_distance.len(), 80); assert_eq!(engine.statistics_buffer.total_distance.len(), 80);
} }
#[test] #[test]
fn test_new_file_has_no_statistics() { fn test_new_file_has_no_statistics() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
assert!(new(&mut engine, "empty")); assert!(new(&mut engine, "empty"));
assert_eq!(engine.stack.current().unwrap().len(), 1); assert_eq!(engine.stack.current().unwrap().len(), 1);
assert_eq!(engine.order.0.len(), 1); assert_eq!(engine.order.0.len(), 1);
@@ -67,7 +127,7 @@ fn test_new_file_has_no_statistics() {
#[test] #[test]
fn test_statistics_follow_selection() { fn test_statistics_follow_selection() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
assert!(load(&mut engine, "data/simple.gpx")); assert!(load(&mut engine, "data/simple.gpx"));
let n = engine.statistics().total_distance.len(); let n = engine.statistics().total_distance.len();
assert!(n > 0); assert!(n > 0);
@@ -84,7 +144,7 @@ fn test_statistics_follow_selection() {
#[test] #[test]
fn test_invalid_load_is_rejected() { fn test_invalid_load_is_rejected() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
assert!(!edit( assert!(!edit(
&mut engine, &mut engine,
Command::Load(Load { Command::Load(Load {
@@ -99,7 +159,7 @@ fn test_invalid_load_is_rejected() {
#[test] #[test]
fn test_command_with_nothing_to_do_is_rejected() { fn test_command_with_nothing_to_do_is_rejected() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "file"); new(&mut engine, "file");
assert!(!edit(&mut engine, Command::Reverse(crate::Reverse))); assert!(!edit(&mut engine, Command::Reverse(crate::Reverse)));
assert!(!engine.stack.can_redo()); assert!(!engine.stack.can_redo());
@@ -108,7 +168,7 @@ fn test_command_with_nothing_to_do_is_rejected() {
#[test] #[test]
fn test_metadata_renames_selected_file() { fn test_metadata_renames_selected_file() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "before"); new(&mut engine, "before");
assert!(edit( assert!(edit(
&mut engine, &mut engine,
@@ -124,7 +184,7 @@ fn test_metadata_renames_selected_file() {
#[test] #[test]
fn test_metadata_without_selection_does_not_modify_files() { fn test_metadata_without_selection_does_not_modify_files() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "file"); new(&mut engine, "file");
engine.selection = Selection::Empty; engine.selection = Selection::Empty;
edit( edit(
@@ -140,7 +200,7 @@ fn test_metadata_without_selection_does_not_modify_files() {
#[test] #[test]
fn test_edit_changes_statistics_when_segments_change() { fn test_edit_changes_statistics_when_segments_change() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
load(&mut engine, "data/simple.gpx"); load(&mut engine, "data/simple.gpx");
let before = engine let before = engine
.statistics_cache .statistics_cache
@@ -163,7 +223,7 @@ fn test_edit_changes_statistics_when_segments_change() {
#[test] #[test]
fn test_undo_redo_keep_selection_and_order_consistent() { fn test_undo_redo_keep_selection_and_order_consistent() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "a"); new(&mut engine, "a");
let a = selected(&engine)[0]; let a = selected(&engine)[0];
new(&mut engine, "b"); new(&mut engine, "b");
@@ -186,7 +246,7 @@ fn test_undo_redo_keep_selection_and_order_consistent() {
#[test] #[test]
fn test_reorder_is_not_undoable_and_returning_files_go_last() { fn test_reorder_is_not_undoable_and_returning_files_go_last() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "a"); new(&mut engine, "a");
let a = engine.order.0[0]; let a = engine.order.0[0];
new(&mut engine, "b"); new(&mut engine, "b");
@@ -214,7 +274,7 @@ fn test_reorder_is_not_undoable_and_returning_files_go_last() {
#[test] #[test]
fn test_structures_and_coordinates_follow_actions() { fn test_structures_and_coordinates_follow_actions() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
assert!(engine.order().is_empty()); assert!(engine.order().is_empty());
load(&mut engine, "data/simple.gpx"); load(&mut engine, "data/simple.gpx");
let loaded_id = engine.order()[0]; let loaded_id = engine.order()[0];
@@ -267,7 +327,7 @@ fn test_structures_and_coordinates_follow_actions() {
#[test] #[test]
fn test_selection_changed_flag() { fn test_selection_changed_flag() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "a"); new(&mut engine, "a");
let a = engine.order()[0]; let a = engine.order()[0];
// a new file is selected by the edit // a new file is selected by the edit
@@ -285,7 +345,7 @@ fn test_selection_changed_flag() {
#[test] #[test]
fn test_undo_updates_statistics() { fn test_undo_updates_statistics() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
load(&mut engine, "data/simple.gpx"); load(&mut engine, "data/simple.gpx");
assert!(!engine.statistics().total_distance.is_empty()); assert!(!engine.statistics().total_distance.is_empty());
engine.run(Action::Undo); engine.run(Action::Undo);
@@ -297,7 +357,7 @@ fn test_undo_updates_statistics() {
#[test] #[test]
fn test_selection_actions() { fn test_selection_actions() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "a"); new(&mut engine, "a");
let a = selected(&engine)[0]; let a = selected(&engine)[0];
new(&mut engine, "b"); new(&mut engine, "b");
@@ -317,14 +377,14 @@ fn test_selection_actions() {
#[test] #[test]
fn test_selection_does_not_create_undo_steps() { fn test_selection_does_not_create_undo_steps() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "a"); new(&mut engine, "a");
select_all(&mut engine); select_all(&mut engine);
engine.run(Action::Undo); engine.run(Action::Undo);
assert!(engine.stack.current().is_none()); assert!(engine.stack.current().is_none());
} }
fn select_elements(engine: &mut Engine, selection: Selection, mode: SelectMode) -> bool { fn select_elements(engine: &mut TestEngine, selection: Selection, mode: SelectMode) -> bool {
engine.run(Action::Select { selection, mode }) engine.run(Action::Select { selection, mode })
} }
@@ -334,18 +394,18 @@ fn files(ids: &[FileId]) -> Selection {
} }
} }
fn select_files(engine: &mut Engine, ids: &[FileId]) -> bool { fn select_files(engine: &mut TestEngine, ids: &[FileId]) -> bool {
select_elements(engine, files(ids), SelectMode::Replace) select_elements(engine, files(ids), SelectMode::Replace)
} }
fn select_all(engine: &mut Engine) -> bool { fn select_all(engine: &mut TestEngine) -> bool {
let ids = engine.order().to_vec(); let ids = engine.order().to_vec();
select_files(engine, &ids) select_files(engine, &ids)
} }
#[test] #[test]
fn test_select_elements() { fn test_select_elements() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
load(&mut engine, "data/with_tracks_and_segments.gpx"); load(&mut engine, "data/with_tracks_and_segments.gpx");
let file = engine let file = engine
.stack .stack
@@ -444,7 +504,7 @@ fn test_select_elements() {
#[test] #[test]
fn test_toggle_elements() { fn test_toggle_elements() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
load(&mut engine, "data/with_tracks_and_segments.gpx"); load(&mut engine, "data/with_tracks_and_segments.gpx");
let file = engine let file = engine
.stack .stack
@@ -459,7 +519,7 @@ fn test_toggle_elements() {
file_id: file.id, file_id: file.id,
trk_ids: ids.iter().copied().collect(), trk_ids: ids.iter().copied().collect(),
}; };
let toggle = |engine: &mut Engine, ids: &[TrackId]| { let toggle = |engine: &mut TestEngine, ids: &[TrackId]| {
select_elements(engine, tracks(ids), SelectMode::Toggle) select_elements(engine, tracks(ids), SelectMode::Toggle)
}; };
@@ -478,7 +538,7 @@ fn test_toggle_elements() {
#[test] #[test]
fn test_selected_elements_are_dropped_when_they_disappear() { fn test_selected_elements_are_dropped_when_they_disappear() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
load(&mut engine, "data/with_tracks_and_segments.gpx"); load(&mut engine, "data/with_tracks_and_segments.gpx");
let file = engine let file = engine
.stack .stack
@@ -503,7 +563,7 @@ fn test_selected_elements_are_dropped_when_they_disappear() {
#[test] #[test]
fn test_can_undo_and_redo() { fn test_can_undo_and_redo() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
assert!(!engine.can_undo() && !engine.can_redo()); assert!(!engine.can_undo() && !engine.can_redo());
new(&mut engine, "a"); new(&mut engine, "a");
assert!(engine.can_undo() && !engine.can_redo()); assert!(engine.can_undo() && !engine.can_redo());
@@ -521,7 +581,7 @@ fn test_can_undo_and_redo() {
#[test] #[test]
fn test_select_all_follows_the_selected_level() { fn test_select_all_follows_the_selected_level() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "a"); new(&mut engine, "a");
new(&mut engine, "b"); new(&mut engine, "b");
let order = engine.order().to_vec(); let order = engine.order().to_vec();
@@ -534,7 +594,7 @@ fn test_select_all_follows_the_selected_level() {
assert!(!engine.run(Action::SelectAll)); assert!(!engine.run(Action::SelectAll));
// the tracks of a file // the tracks of a file
let load = |engine: &mut Engine| load(engine, "data/with_tracks_and_segments.gpx"); let load = |engine: &mut TestEngine| load(engine, "data/with_tracks_and_segments.gpx");
load(&mut engine); load(&mut engine);
let file = engine let file = engine
.stack .stack
@@ -582,7 +642,7 @@ fn test_select_all_follows_the_selected_level() {
#[test] #[test]
fn test_arrow_select() { fn test_arrow_select() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "file"); new(&mut engine, "file");
for _ in 0..3 { for _ in 0..3 {
edit(&mut engine, Command::NewTrack(NewTrack)); edit(&mut engine, Command::NewTrack(NewTrack));
@@ -601,7 +661,7 @@ fn test_arrow_select() {
file_id: file.id, file_id: file.id,
trk_ids: ids.iter().copied().collect(), trk_ids: ids.iter().copied().collect(),
}; };
let arrow = |engine: &mut Engine, down, add| engine.run(Action::ArrowSelect { down, add }); let arrow = |engine: &mut TestEngine, down, add| engine.run(Action::ArrowSelect { down, add });
select_elements(&mut engine, tracks(&[ids[0]]), SelectMode::Replace); select_elements(&mut engine, tracks(&[ids[0]]), SelectMode::Replace);
// without shift the next one replaces the selection // without shift the next one replaces the selection
@@ -626,7 +686,7 @@ fn test_arrow_select() {
#[test] #[test]
fn test_arrow_select_does_not_create_undo_steps() { fn test_arrow_select_does_not_create_undo_steps() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "a"); new(&mut engine, "a");
new(&mut engine, "b"); new(&mut engine, "b");
let a = engine.order()[0]; let a = engine.order()[0];
@@ -643,7 +703,7 @@ fn test_arrow_select_does_not_create_undo_steps() {
} }
/// A file named `name` with `n` tracks, selected. /// A file named `name` with `n` tracks, selected.
fn file_with_tracks(engine: &mut Engine, name: &str, n: usize) -> FileId { fn file_with_tracks(engine: &mut TestEngine, name: &str, n: usize) -> FileId {
new(engine, name); new(engine, name);
for _ in 0..n { for _ in 0..n {
edit(engine, Command::NewTrack(NewTrack)); edit(engine, Command::NewTrack(NewTrack));
@@ -661,13 +721,13 @@ fn track_ids(engine: &Engine, id: FileId) -> Vec<TrackId> {
.collect() .collect()
} }
fn paste(engine: &mut Engine) -> bool { fn paste(engine: &mut TestEngine) -> bool {
edit(engine, Command::Paste(Paste)) edit(engine, Command::Paste(Paste))
} }
#[test] #[test]
fn test_copy_and_paste() { fn test_copy_and_paste() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
let a = file_with_tracks(&mut engine, "a", 2); let a = file_with_tracks(&mut engine, "a", 2);
let b = file_with_tracks(&mut engine, "b", 0); let b = file_with_tracks(&mut engine, "b", 0);
assert!(engine.clipboard().is_none() && !engine.can_paste()); assert!(engine.clipboard().is_none() && !engine.can_paste());
@@ -724,7 +784,7 @@ fn test_copy_and_paste() {
#[test] #[test]
fn test_cut_and_paste_moves_after_the_paste() { fn test_cut_and_paste_moves_after_the_paste() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
let a = file_with_tracks(&mut engine, "a", 2); let a = file_with_tracks(&mut engine, "a", 2);
let b = file_with_tracks(&mut engine, "b", 0); let b = file_with_tracks(&mut engine, "b", 0);
let tracks = track_ids(&engine, a); let tracks = track_ids(&engine, a);
@@ -752,7 +812,7 @@ fn test_cut_and_paste_moves_after_the_paste() {
#[test] #[test]
fn test_clipboard_survives_what_happens_to_the_elements() { fn test_clipboard_survives_what_happens_to_the_elements() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
let a = file_with_tracks(&mut engine, "a", 2); let a = file_with_tracks(&mut engine, "a", 2);
let tracks = track_ids(&engine, a); let tracks = track_ids(&engine, a);
select_elements( select_elements(
@@ -801,7 +861,7 @@ fn test_clipboard_survives_what_happens_to_the_elements() {
#[test] #[test]
fn test_copy_replaces_the_clipboard_and_does_not_change_the_history() { fn test_copy_replaces_the_clipboard_and_does_not_change_the_history() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
let a = file_with_tracks(&mut engine, "a", 0); let a = file_with_tracks(&mut engine, "a", 0);
let b = file_with_tracks(&mut engine, "b", 0); let b = file_with_tracks(&mut engine, "b", 0);
select_files(&mut engine, &[a]); select_files(&mut engine, &[a]);
@@ -825,7 +885,7 @@ fn test_copy_replaces_the_clipboard_and_does_not_change_the_history() {
fn test_move_elements_is_an_edit_and_selects_what_moved() { fn test_move_elements_is_an_edit_and_selects_what_moved() {
use crate::{Move, MoveTarget}; use crate::{Move, MoveTarget};
let mut engine = Engine::default(); let mut engine = TestEngine::default();
let a = file_with_tracks(&mut engine, "a", 3); let a = file_with_tracks(&mut engine, "a", 3);
let tracks = track_ids(&engine, a); let tracks = track_ids(&engine, a);
let moved = Selection::Track { let moved = Selection::Track {
@@ -865,7 +925,7 @@ fn test_move_elements_is_an_edit_and_selects_what_moved() {
fn test_added_files_are_reported_in_the_order_of_the_files() { fn test_added_files_are_reported_in_the_order_of_the_files() {
use crate::LoadFiles; use crate::LoadFiles;
let mut engine = Engine::default(); let mut engine = TestEngine::default();
let datas: Vec<Vec<u8>> = (0..12) let datas: Vec<Vec<u8>> = (0..12)
.map(|i| { .map(|i| {
format!(r#"<gpx version="1.1"><metadata><name>{i}</name></metadata></gpx>"#) format!(r#"<gpx version="1.1"><metadata><name>{i}</name></metadata></gpx>"#)
@@ -892,7 +952,7 @@ fn test_added_files_are_reported_in_the_order_of_the_files() {
fn test_load_several_files_is_one_edit() { fn test_load_several_files_is_one_edit() {
use crate::LoadFiles; use crate::LoadFiles;
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "before"); new(&mut engine, "before");
let gpx = |name: &str| { let gpx = |name: &str| {
format!(r#"<gpx version="1.1"><metadata><name>{name}</name></metadata></gpx>"#).into_bytes() format!(r#"<gpx version="1.1"><metadata><name>{name}</name></metadata></gpx>"#).into_bytes()
@@ -930,7 +990,7 @@ fn test_load_several_files_is_one_edit() {
fn test_create_edit_and_move_a_waypoint() { fn test_create_edit_and_move_a_waypoint() {
use crate::{EditWaypoint, MoveWaypoint, NewWaypoint}; use crate::{EditWaypoint, MoveWaypoint, NewWaypoint};
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "file"); new(&mut engine, "file");
let file = engine.order()[0]; let file = engine.order()[0];
assert!(edit( assert!(edit(
@@ -1019,7 +1079,7 @@ fn test_create_edit_and_move_a_waypoint() {
#[test] #[test]
fn test_categories_are_shared_and_kept_by_the_history() { fn test_categories_are_shared_and_kept_by_the_history() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
assert!(engine.categories().surface.names().is_empty()); assert!(engine.categories().surface.names().is_empty());
load(&mut engine, "data/with_highway.gpx"); load(&mut engine, "data/with_highway.gpx");
@@ -1064,7 +1124,7 @@ fn test_categories_are_shared_and_kept_by_the_history() {
#[test] #[test]
fn test_trackpoint() { fn test_trackpoint() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
load(&mut engine, "data/simple.gpx"); load(&mut engine, "data/simple.gpx");
let file = engine.order()[0]; let file = engine.order()[0];
let structure = engine.file_structure(&file).unwrap(); let structure = engine.file_structure(&file).unwrap();
@@ -1082,7 +1142,7 @@ fn test_trackpoint() {
#[test] #[test]
fn test_export_writes_the_file_as_it_is() { fn test_export_writes_the_file_as_it_is() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
assert!( assert!(
engine engine
.export(&FileId::default(), ExportOptions::ALL) .export(&FileId::default(), ExportOptions::ALL)
@@ -1110,7 +1170,7 @@ fn test_export_writes_the_file_as_it_is() {
#[test] #[test]
fn test_exportable_data_is_the_union_over_the_files() { fn test_exportable_data_is_the_union_over_the_files() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
assert_eq!(engine.exportable_data(&[]), ExportOptions::NONE); assert_eq!(engine.exportable_data(&[]), ExportOptions::NONE);
load(&mut engine, "data/simple.gpx"); load(&mut engine, "data/simple.gpx");
@@ -1129,7 +1189,7 @@ fn test_exportable_data_is_the_union_over_the_files() {
#[test] #[test]
fn test_file_statistics_are_the_ones_of_the_whole_file() { fn test_file_statistics_are_the_ones_of_the_whole_file() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
assert!(engine.file_statistics(&FileId::default()).is_none()); assert!(engine.file_statistics(&FileId::default()).is_none());
load(&mut engine, "data/simple.gpx"); load(&mut engine, "data/simple.gpx");
@@ -1156,7 +1216,7 @@ fn test_file_statistics_are_the_ones_of_the_whole_file() {
#[test] #[test]
fn test_reduction_distances_follow_the_selection() { fn test_reduction_distances_follow_the_selection() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
assert!(engine.reduction_distances().is_empty()); assert!(engine.reduction_distances().is_empty());
load(&mut engine, "data/simple.gpx"); load(&mut engine, "data/simple.gpx");
@@ -1174,7 +1234,7 @@ fn test_reduction_distances_follow_the_selection() {
#[test] #[test]
fn test_routing_describes_the_anchors_of_the_selection() { fn test_routing_describes_the_anchors_of_the_selection() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
assert!(engine.routing().anchor_indices.is_empty()); assert!(engine.routing().anchor_indices.is_empty());
load(&mut engine, "data/simple.gpx"); load(&mut engine, "data/simple.gpx");
@@ -1207,7 +1267,7 @@ fn test_routing_describes_the_anchors_of_the_selection() {
#[test] #[test]
fn test_last_error_tells_why_an_edit_did_nothing() { fn test_last_error_tells_why_an_edit_did_nothing() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
assert!(engine.last_error().is_none()); assert!(engine.last_error().is_none());
// invalid data // invalid data
@@ -1240,7 +1300,7 @@ fn test_last_error_tells_why_an_edit_did_nothing() {
#[test] #[test]
fn test_an_edit_that_changes_nothing_is_not_an_undo_step() { fn test_an_edit_that_changes_nothing_is_not_an_undo_step() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "file"); new(&mut engine, "file");
// "file" is selected: naming it the same still builds a new file, but selecting nothing // "file" is selected: naming it the same still builds a new file, but selecting nothing
// leaves nothing to rename // leaves nothing to rename
@@ -1266,7 +1326,7 @@ fn test_an_edit_that_changes_nothing_is_not_an_undo_step() {
#[test] #[test]
fn test_execute_returns_what_the_action_did() { fn test_execute_returns_what_the_action_did() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
let data = std::fs::read("data/simple.gpx").unwrap(); let data = std::fs::read("data/simple.gpx").unwrap();
let outcome = engine let outcome = engine
.execute(Action::Edit(Command::Load(Load { .execute(Action::Edit(Command::Load(Load {
@@ -1286,9 +1346,10 @@ fn test_execute_returns_what_the_action_did() {
// a selection only changes the selection // a selection only changes the selection
engine.execute(Action::Redo).unwrap(); engine.execute(Action::Redo).unwrap();
let selection = files(engine.order());
let outcome = engine let outcome = engine
.execute(Action::Select { .execute(Action::Select {
selection: files(engine.order()), selection,
mode: SelectMode::Replace, mode: SelectMode::Replace,
}) })
.unwrap(); .unwrap();
@@ -1330,7 +1391,7 @@ fn restored_from(engine: &Engine, keep: &[FileId], extra: Vec<Rc<File>>) -> crat
#[test] #[test]
fn test_overwriting_reports_what_was_added_removed_and_modified() { fn test_overwriting_reports_what_was_added_removed_and_modified() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "kept"); new(&mut engine, "kept");
new(&mut engine, "modified"); new(&mut engine, "modified");
new(&mut engine, "removed"); new(&mut engine, "removed");
@@ -1355,7 +1416,7 @@ fn test_overwriting_reports_what_was_added_removed_and_modified() {
#[test] #[test]
fn test_overwriting_with_the_same_files_changes_nothing() { fn test_overwriting_with_the_same_files_changes_nothing() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "a"); new(&mut engine, "a");
let ids = engine.order().to_vec(); let ids = engine.order().to_vec();
let outcome = engine.restore(restored_from(&engine, &ids, vec![])); let outcome = engine.restore(restored_from(&engine, &ids, vec![]));
@@ -1365,7 +1426,7 @@ fn test_overwriting_with_the_same_files_changes_nothing() {
#[test] #[test]
fn test_overwriting_forgets_the_history() { fn test_overwriting_forgets_the_history() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "a"); new(&mut engine, "a");
new(&mut engine, "b"); new(&mut engine, "b");
assert!(engine.can_undo()); assert!(engine.can_undo());
@@ -1376,7 +1437,7 @@ fn test_overwriting_forgets_the_history() {
#[test] #[test]
fn test_files_cannot_be_changed_when_what_is_stored_is_from_a_newer_version() { fn test_files_cannot_be_changed_when_what_is_stored_is_from_a_newer_version() {
let mut engine = Engine::default(); let mut engine = TestEngine::default();
new(&mut engine, "file"); new(&mut engine, "file");
let id = engine.order()[0]; let id = engine.order()[0];
@@ -1395,14 +1456,12 @@ fn test_files_cannot_be_changed_when_what_is_stored_is_from_a_newer_version() {
} }
assert_eq!(engine.order(), [id]); assert_eq!(engine.order(), [id]);
// looking at the files still works // so is anything else, the selection included
let outcome = engine let result = engine.execute(Action::Select {
.execute(Action::Select { selection: Selection::Empty,
selection: Selection::Empty, mode: SelectMode::Replace,
mode: SelectMode::Replace, });
}) assert_eq!(result, Err(CommandError::Outdated));
.unwrap();
assert!(outcome.selection_changed);
// reading a storage that is not newer lifts it // reading a storage that is not newer lifts it
engine.restore(restored_from(&engine, &[id], vec![])); engine.restore(restored_from(&engine, &[id], vec![]));
+17 -16
View File
@@ -710,12 +710,18 @@ mod tests {
fn test_an_engine_starts_from_what_is_restored() { fn test_an_engine_starts_from_what_is_restored() {
let storage = Recording::default(); let storage = Recording::default();
let mut engine = Engine::default(); let mut engine = Engine::default();
for path in FILES { let load = |engine: &mut Engine, path: &str| {
let data = std::fs::read(path).unwrap(); let data = std::fs::read(path).unwrap();
assert!(engine.run(Action::Edit(Command::Load(Load { engine
data: &data, .execute(Action::Edit(Command::Load(Load {
name: "file", data: &data,
})))); name: "file",
})))
.unwrap()
.changed
};
for path in FILES {
assert!(load(&mut engine, path));
} }
let snapshot = engine.snapshot(); let snapshot = engine.snapshot();
assert_eq!(snapshot.files.len(), FILES.len()); assert_eq!(snapshot.files.len(), FILES.len());
@@ -723,25 +729,20 @@ mod tests {
let restored = block_on(Persister::default().restore(&storage)).unwrap(); let restored = block_on(Persister::default().restore(&storage)).unwrap();
let mut engine = Engine::default(); let mut engine = Engine::default();
engine.restore(restored); let outcome = engine.restore(restored);
assert_eq!(engine.snapshot().order, snapshot.order); assert_eq!(engine.snapshot().order, snapshot.order);
let diff = engine.last_diff().unwrap(); assert_eq!(outcome.diff.unwrap().added.len(), FILES.len());
assert_eq!(diff.added.len(), FILES.len()); assert!(outcome.order_changed);
assert!(engine.order_changed());
for id in &snapshot.order { for id in &snapshot.order {
assert!(engine.file_structure(id).is_some()); assert!(engine.file_structure(id).is_some());
} }
// the files that were restored are not undone // the files that were restored are not undone
assert!(!engine.can_undo()); assert!(!engine.can_undo());
assert!(!engine.run(Action::Undo)); assert!(!engine.execute(Action::Undo).unwrap().changed);
let data = std::fs::read(FILES[0]).unwrap(); assert!(load(&mut engine, FILES[0]));
assert!(engine.run(Action::Edit(Command::Load(Load {
data: &data,
name: "file",
}))));
assert!(engine.can_undo()); assert!(engine.can_undo());
assert!(engine.run(Action::Undo)); assert!(engine.execute(Action::Undo).unwrap().changed);
assert_eq!(engine.snapshot().files.len(), FILES.len()); assert_eq!(engine.snapshot().files.len(), FILES.len());
assert!(!engine.can_undo()); assert!(!engine.can_undo());
} }