summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Oram <dev@mitmaro.ca>2022-02-16 08:47:10 -0330
committerTim Oram <dev@mitmaro.ca>2022-02-26 13:15:19 -0330
commit3d508664b8fae035f3e126902213c4415a1ae828 (patch)
treeb8a79a18644026c7de428e9e45604060d7c8e107
parent03bacf4672dfe9ccce9ea012e8658e572c64206f (diff)
Move event handling too a separate thread
-rw-r--r--Cargo.lock2
-rw-r--r--src/core/src/module/modules.rs45
-rw-r--r--src/core/src/modules/external_editor/tests.rs160
-rw-r--r--src/core/src/modules/show_commit/tests.rs4
-rw-r--r--src/core/src/process/mod.rs43
-rw-r--r--src/core/src/process/tests.rs630
-rw-r--r--src/core/src/run.rs27
-rw-r--r--src/core/src/tests.rs29
-rw-r--r--src/core/src/testutil/mod.rs7
-rw-r--r--src/core/src/testutil/module_test.rs15
-rw-r--r--src/core/src/testutil/test_module.rs32
-rw-r--r--src/input/Cargo.toml2
-rw-r--r--src/input/src/event_action.rs9
-rw-r--r--src/input/src/event_handler.rs138
-rw-r--r--src/input/src/lib.rs5
-rw-r--r--src/input/src/sender.rs90
-rw-r--r--src/input/src/testutil.rs133
-rw-r--r--src/input/src/thread.rs190
-rw-r--r--src/view/src/testutil.rs2
19 files changed, 808 insertions, 755 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 456200c..0c522db 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -233,8 +233,10 @@ version = "1.0.0"
dependencies = [
"anyhow",
"bitflags",
+ "crossbeam-channel",
"crossterm",
"girt-config",
+ "parking_lot 0.12.0",
"rstest 0.12.0",
"rustc_version",
]
diff --git a/src/core/src/module/modules.rs b/src/core/src/module/modules.rs
index 75aaf38..03d9e37 100644
--- a/src/core/src/module/modules.rs
+++ b/src/core/src/module/modules.rs
@@ -1,18 +1,20 @@
use std::collections::HashMap;
-use input::EventHandler;
+use input::{EventHandler, Sender as EventSender};
use todo_file::TodoFile;
use view::{RenderContext, ViewData, ViewSender};
use super::{Module, ProcessResult, State};
pub(crate) struct Modules<'m> {
+ event_handler: EventHandler,
modules: HashMap<State, Box<dyn Module + 'm>>,
}
impl<'m> Modules<'m> {
- pub(crate) fn new() -> Self {
+ pub(crate) fn new(event_handler: EventHandler) -> Self {
Self {
+ event_handler,
modules: HashMap::new(),
}
}
@@ -28,6 +30,13 @@ impl<'m> Modules<'m> {
.unwrap_or_else(|| panic!("Invalid module for provided state: {:?}. Please report.", state))
}
+ #[allow(clippy::borrowed_box, clippy::panic)]
+ fn get_module(&self, state: State) -> &Box<dyn Module + 'm> {
+ self.modules
+ .get(&state)
+ .unwrap_or_else(|| panic!("Invalid module for provided state: {:?}", state))
+ }
+
pub(crate) fn activate(&mut self, state: State, rebase_todo: &TodoFile, previous_state: State) -> ProcessResult {
self.get_mut_module(state).activate(rebase_todo, previous_state)
}
@@ -48,16 +57,18 @@ impl<'m> Modules<'m> {
pub(crate) fn handle_event(
&mut self,
state: State,
- event_handler: &EventHandler,
+ event_sender: &mut EventSender,
view_sender: &ViewSender,
rebase_todo: &mut TodoFile,
) -> ProcessResult {
- let module = self.get_mut_module(state);
+ let module = self.get_module(state);
let input_options = module.input_options();
- let event = event_handler.read_event(input_options, |event, key_bindings| {
- module.read_event(event, key_bindings)
- });
- module.handle_event(event, view_sender, rebase_todo)
+ let event = self
+ .event_handler
+ .read_event(event_sender.read_event(), input_options, |event, key_bindings| {
+ module.read_event(event, key_bindings)
+ });
+ self.get_mut_module(state).handle_event(event, view_sender, rebase_todo)
}
pub(crate) fn error(&mut self, state: State, error: &anyhow::Error) {
@@ -117,7 +128,7 @@ mod tests {
#[test]
fn module_lifecycle() {
module_test(&["pick aaa comment"], &[Event::Meta(MetaEvent::Exit)], |mut context| {
- let mut modules = Modules::new();
+ let mut modules = Modules::new(context.event_handler_context.event_handler);
let trace = Rc::new(RefCell::new(Vec::new()));
let test_module = TestModule::new(Rc::clone(&trace));
modules.register_module(State::List, test_module);
@@ -125,7 +136,7 @@ mod tests {
let _ = modules.activate(State::List, &context.rebase_todo_file, State::Insert);
let _ = modules.handle_event(
State::List,
- &context.event_handler_context.event_handler,
+ &mut context.event_handler_context.sender,
&context.view_sender_context.sender,
&mut context.rebase_todo_file,
);
@@ -140,11 +151,13 @@ mod tests {
#[test]
fn error() {
- let mut modules = Modules::new();
- let trace = Rc::new(RefCell::new(Vec::new()));
- let test_module = TestModule::new(Rc::clone(&trace));
- modules.register_module(State::Error, test_module);
- modules.error(State::Error, &anyhow!("Test Error"));
- assert_eq!((*trace).borrow().join(","), "Test Error");
+ module_test(&["pick aaa comment"], &[Event::Meta(MetaEvent::Exit)], |context| {
+ let mut modules = Modules::new(context.event_handler_context.event_handler);
+ let trace = Rc::new(RefCell::new(Vec::new()));
+ let test_module = TestModule::new(Rc::clone(&trace));
+ modules.register_module(State::Error, test_module);
+ modules.error(State::Error, &anyhow!("Test Error"));
+ assert_eq!((*trace).borrow().join(","), "Test Error");
+ });
}
}
diff --git a/src/core/src/modules/external_editor/tests.rs b/src/core/src/modules/external_editor/tests.rs
index 2a6ba3b..29dea36 100644
--- a/src/core/src/modules/external_editor/tests.rs
+++ b/src/core/src/modules/external_editor/tests.rs
@@ -107,55 +107,56 @@ fn deactivate() {
#[test]
fn edit_success() {
- module_test(&["pick aaa comment"], &[], |mut test_context| {
- test_context
- .event_handler_context
- .event_handler
- .push_event(Event::from(MetaEvent::ExternalCommandSuccess));
- let mut module = ExternalEditor::new("editor");
- let _ = test_context.activate(&mut module, State::List);
- let view_data = test_context.build_view_data(&mut module);
- assert_rendered_output!(view_data, "{TITLE}", "{LEADING}", "{Normal}Editing...");
- assert_process_result!(
- test_context.handle_event(&mut module),
- event = Event::from(MetaEvent::ExternalCommandSuccess),
- state = State::List
- );
- assert_external_editor_state_eq!(module.state, ExternalEditorState::Active);
- });
+ module_test(
+ &["pick aaa comment"],
+ &[Event::from(MetaEvent::ExternalCommandSuccess)],
+ |mut test_context| {
+ let mut module = ExternalEditor::new("editor");
+ let _ = test_context.activate(&mut module, State::List);
+ let view_data = test_context.build_view_data(&mut module);
+ assert_rendered_output!(view_data, "{TITLE}", "{LEADING}", "{Normal}Editing...");
+ assert_process_result!(
+ test_context.handle_event(&mut module),
+ event = Event::from(MetaEvent::ExternalCommandSuccess),
+ state = State::List
+ );
+ assert_external_editor_state_eq!(module.state, ExternalEditorState::Active);
+ },
+ );
}
#[test]
fn empty_edit_error() {
- module_test(&["pick aaa comment"], &[Event::from('1')], |mut test_context| {
- test_context
- .event_handler_context
- .event_handler
- .push_event(Event::from(MetaEvent::ExternalCommandSuccess));
- let mut module = ExternalEditor::new("editor");
- let _ = test_context.activate(&mut module, State::List);
- test_context.rebase_todo_file.set_lines(vec![]);
- test_context.rebase_todo_file.write_file().unwrap();
- assert_process_result!(
- test_context.handle_event(&mut module),
- event = Event::from(MetaEvent::ExternalCommandSuccess)
- );
- assert_external_editor_state_eq!(module.state, ExternalEditorState::Empty);
- let view_data = test_context.build_view_data(&mut module);
- assert_rendered_output!(
- view_data,
- "{TITLE}",
- "{LEADING}",
- "{Normal}The rebase file is empty.",
- "",
- "{BODY}",
- "{Normal}1) Abort rebase",
- "{Normal}2) Edit rebase file",
- "{Normal}3) Undo modifications and edit rebase file",
- "",
- "{IndicatorColor}Please choose an option."
- );
- });
+ module_test(
+ &["pick aaa comment"],
+ &[Event::from('1'), Event::from(MetaEvent::ExternalCommandSuccess)],
+ |mut test_context| {
+ let mut module = ExternalEditor::new("editor");
+ let _ = test_context.activate(&mut module, State::List);
+ test_context.rebase_todo_file.set_lines(vec![]);
+ test_context.rebase_todo_file.write_file().unwrap();
+ let _ = test_context.handle_event(&mut module);
+ assert_process_result!(
+ test_context.handle_event(&mut module),
+ event = Event::from(MetaEvent::ExternalCommandSuccess)
+ );
+ assert_external_editor_state_eq!(module.state, ExternalEditorState::Empty);
+ let view_data = test_context.build_view_data(&mut module);
+ assert_rendered_output!(
+ view_data,
+ "{TITLE}",
+ "{LEADING}",
+ "{Normal}The rebase file is empty.",
+ "",
+ "{BODY}",
+ "{Normal}1) Abort rebase",
+ "{Normal}2) Edit rebase file",
+ "{Normal}3) Undo modifications and edit rebase file",
+ "",
+ "{IndicatorColor}Please choose an option."
+ );
+ },
+ );
}
#[test]
@@ -252,53 +253,50 @@ fn no_editor_set() {
#[test]
fn editor_non_zero_exit() {
- module_test(&["pick aaa comment"], &[], |mut test_context| {
- let mut module = ExternalEditor::new("editor");
- test_context
- .event_handler_context
- .event_handler
- .push_event(Event::from(MetaEvent::ExternalCommandError));
- let _ = test_context.activate(&mut module, State::List);
- assert_process_result!(
- test_context.handle_event(&mut module),
- event = Event::from(MetaEvent::ExternalCommandError)
- );
- assert_external_editor_state_eq!(
- module.state,
- ExternalEditorState::Error(anyhow!("Editor returned a non-zero exit status"))
- );
- let view_data = test_context.build_view_data(&mut module);
- assert_rendered_output!(
- view_data,
- "{TITLE}",
- "{LEADING}",
- "{Normal}Editor returned a non-zero exit status",
- "",
- "{BODY}",
- "{Normal}1) Abort rebase",
- "{Normal}2) Edit rebase file",
- "{Normal}3) Restore rebase file and abort edit",
- "{Normal}4) Undo modifications and edit rebase file",
- "",
- "{IndicatorColor}Please choose an option."
- );
- });
+ module_test(
+ &["pick aaa comment"],
+ &[Event::from(MetaEvent::ExternalCommandError)],
+ |mut test_context| {
+ let mut module = ExternalEditor::new("editor");
+ let _ = test_context.activate(&mut module, State::List);
+ assert_process_result!(
+ test_context.handle_event(&mut module),
+ event = Event::from(MetaEvent::ExternalCommandError)
+ );
+ assert_external_editor_state_eq!(
+ module.state,
+ ExternalEditorState::Error(anyhow!("Editor returned a non-zero exit status"))
+ );
+ let view_data = test_context.build_view_data(&mut module);
+ assert_rendered_output!(
+ view_data,
+ "{TITLE}",
+ "{LEADING}",
+ "{Normal}Editor returned a non-zero exit status",
+ "",
+ "{BODY}",
+ "{Normal}1) Abort rebase",
+ "{Normal}2) Edit rebase file",
+ "{Normal}3) Restore rebase file and abort edit",
+ "{Normal}4) Undo modifications and edit rebase file",
+ "",
+ "{IndicatorColor}Please choose an option."
+ );
+ },
+ );
}
#[test]
fn editor_reload_error() {
module_test(
&["pick aaa comment"],
- &[Event::from(KeyCode::Up)],
+ &[Event::from(KeyCode::Up), Event::from(MetaEvent::ExternalCommandSuccess)],
|mut test_context| {
let todo_path = test_context.get_todo_file_path();
let mut module = ExternalEditor::new("editor");
- test_context
- .event_handler_context
- .event_handler
- .push_event(Event::from(MetaEvent::ExternalCommandSuccess));
let _ = test_context.activate(&mut module, State::List);
test_context.delete_todo_file();
+ let _ = test_context.handle_event(&mut module);
assert_process_result!(
test_context.handle_event(&mut module),
event = Event::from(MetaEvent::ExternalCommandSuccess)
diff --git a/src/core/src/modules/show_commit/tests.rs b/src/core/src/modules/show_commit/tests.rs
index 2e020ae..37f3c57 100644
--- a/src/core/src/modules/show_commit/tests.rs
+++ b/src/core/src/modules/show_commit/tests.rs
@@ -1133,7 +1133,7 @@ fn handle_event_toggle_overview_to_diff() {
with_temp_repository(|repo| {
module_test(
&["pick 0123456789abcdef0123456789abcdef c1"],
- &[Event::from(MetaEvent::ShowDiff)],
+ &[Event::from('d')],
|mut test_context| {
let mut module = ShowCommit::new(&Config::new(), &repo);
module
@@ -1211,7 +1211,7 @@ fn handle_help_event_hide() {
with_temp_repository(|repo| {
module_test(
&["pick aaa c1"],
- &[Event::from(MetaEvent::Help), Event::from(MetaEvent::Help)],
+ &[Event::from(MetaEvent::Help), Event::from('?')],
|mut test_context| {
let mut module = ShowCommit::new(&Config::new(), &repo);
let _ = test_context.handle_all_events(&mut module);
diff --git a/src/core/src/process/mod.rs b/src/core/src/process/mod.rs
index b9dbd72..652eb92 100644
--- a/src/core/src/process/mod.rs
+++ b/src/core/src/process/mod.rs
@@ -4,44 +4,42 @@ mod tests;
use std::{process::Command, thread};
use anyhow::{anyhow, Result};
-use display::Tui;
-use input::{Event, EventHandler, MetaEvent};
+use display::{CrossTerm, Tui};
+use input::{spawn_event_thread, Event, MetaEvent, Sender as EventSender};
use todo_file::TodoFile;
use view::{spawn_view_thread, RenderContext, View, ViewSender};
use crate::module::{ExitStatus, Modules, ProcessResult, State};
pub(crate) struct Process {
- event_handler: EventHandler,
exit_status: Option<ExitStatus>,
rebase_todo: TodoFile,
render_context: RenderContext,
state: State,
threads: Vec<thread::JoinHandle<()>>,
view_sender: ViewSender,
+ event_sender: EventSender,
}
impl Process {
- pub(crate) fn new<C: Tui + Send + 'static>(
- rebase_todo: TodoFile,
- event_handler: EventHandler,
- view: View<C>,
- ) -> Self {
+ pub(crate) fn new<C: Tui + Send + 'static>(rebase_todo: TodoFile, view: View<C>) -> Self {
#[allow(deprecated)]
let view_size = view.get_view_size();
let mut threads = vec![];
let (view_sender, view_thread) = spawn_view_thread(view);
threads.push(view_thread);
+ let (event_sender, event_thread) = spawn_event_thread(CrossTerm::read_event);
+ threads.push(event_thread);
Self {
- event_handler,
exit_status: None,
rebase_todo,
render_context: RenderContext::new(view_size.width() as u16, view_size.height() as u16),
state: State::List,
threads,
view_sender,
+ event_sender,
}
}
@@ -58,6 +56,7 @@ impl Process {
self.render_context.height() as u16,
)),
);
+
self.activate(&mut modules, State::List);
while self.exit_status.is_none() {
let view_data = modules.build_view_data(self.state, &self.render_context, &self.rebase_todo);
@@ -72,11 +71,15 @@ impl Process {
}
let result = modules.handle_event(
self.state,
- &self.event_handler,
+ &mut self.event_sender,
&self.view_sender,
&mut self.rebase_todo,
);
+ if self.exit_status.is_some() {
+ break;
+ }
+
if let Some(event) = result.event {
if event != Event::None {
self.handle_process_result(&mut modules, &result);
@@ -94,7 +97,9 @@ impl Process {
}
}
- if self.view_sender.end().is_err() {
+ let (view_end_result, event_end_result) = (self.view_sender.end(), self.event_sender.end());
+
+ if view_end_result.is_err() || event_end_result.is_err() {
return Ok(ExitStatus::StateError);
}
@@ -151,7 +156,11 @@ impl Process {
if let Some(ref external_command) = result.external_command {
match self.run_command(external_command) {
- Ok(meta_event) => self.event_handler.push_event(Event::from(meta_event)),
+ Ok(meta_event) => {
+ self.event_sender
+ .enqueue_event(Event::from(meta_event))
+ .expect("Enqueue event failed");
+ },
Err(err) => {
self.handle_process_result(
modules,
@@ -192,10 +201,12 @@ impl Process {
fn activate(&mut self, modules: &mut Modules<'_>, previous_state: State) {
let result = modules.activate(self.state, &self.rebase_todo, previous_state);
// always trigger a resize on activate, for modules that track size
- self.event_handler.push_event(Event::Resize(
- self.render_context.width() as u16,
- self.render_context.height() as u16,
- ));
+ self.event_sender
+ .enqueue_event(Event::Resize(
+ self.render_context.width() as u16,
+ self.render_context.height() as u16,
+ ))
+ .expect("Enqueue Resize event failed");
self.handle_process_result(modules, &result);
}
}
diff --git a/src/core/src/process/tests.rs b/src/core/src/process/tests.rs
index 3a86acf..e0e3984 100644
--- a/src/core/src/process/tests.rs
+++ b/src/core/src/process/tests.rs
@@ -1,45 +1,18 @@
-use std::{path::Path, sync::atomic::Ordering};
+use std::{io::Write, path::Path, sync::atomic::Ordering};
use anyhow::anyhow;
use config::Theme;
use display::{testutil::CrossTerm, Display, Size};
-use input::InputOptions;
-use view::{assert_rendered_output, render_line, ViewData};
+use input::{testutil::create_test_keybindings, EventHandler};
+use tempfile::{Builder, NamedTempFile};
+use view::{assert_rendered_output, render_line};
use super::*;
use crate::{
- module::Module,
modules::{Error, WindowSizeError},
- testutil::module_test,
+ testutil::TestModule,
};
-struct TestModule {
- event_callback: Box<dyn Fn(Event, &ViewSender, &mut TodoFile) -> ProcessResult>,
- view_data: ViewData,
- view_data_callback: Box<dyn Fn(&mut ViewData)>,
-}
-
-impl TestModule {
- fn new() -> Self {
- Self {
- event_callback: Box::new(|_, _, _| ProcessResult::new().event(Event::from(MetaEvent::Kill))),
- view_data: ViewData::new(|_| {}),
- view_data_callback: Box::new(|_| {}),
- }
- }
-}
-
-impl Module for TestModule {
- fn build_view_data(&mut self, _render_context: &RenderContext, _rebase_todo: &TodoFile) -> &ViewData {
- (self.view_data_callback)(&mut self.view_data);
- &self.view_data
- }
-
- fn handle_event(&mut self, event: Event, view_sender: &ViewSender, todo_file: &mut TodoFile) -> ProcessResult {
- (self.event_callback)(event, view_sender, todo_file)
- }
-}
-
fn create_crossterm() -> CrossTerm {
let mut crossterm = CrossTerm::new();
crossterm.set_size(Size::new(100, 300));
@@ -47,438 +20,325 @@ fn create_crossterm() -> CrossTerm {
}
fn create_modules() -> Modules<'static> {
- let mut modules = Modules::new();
+ let mut modules = Modules::new(EventHandler::new(create_test_keybindings()));
modules.register_module(State::Error, Error::new());
modules.register_module(State::WindowSizeError, WindowSizeError::new());
+ modules.register_module(State::List, TestModule::new());
modules
}
+fn create_todo_file() -> (TodoFile, NamedTempFile) {
+ let todo_file_path = Builder::new()
+ .prefix("git-rebase-todo-scratch")
+ .suffix("")
+ .tempfile()
+ .unwrap();
+ write!(todo_file_path.as_file(), "pick aaa comment").unwrap();
+ let mut todo_file = TodoFile::new(todo_file_path.path().to_str().unwrap(), 1, "#");
+ todo_file.load_file().unwrap();
+ (todo_file, todo_file_path)
+}
+
+fn create_shadow_todo_file(todo_file: &TodoFile) -> TodoFile {
+ TodoFile::new(todo_file.get_filepath(), 1, "#")
+}
+
+fn create_process(rebase_todo_file: TodoFile, events: &[Event]) -> Process {
+ let crossterm = create_crossterm();
+ let display = Display::new(crossterm, &Theme::new());
+ let view = View::new(display, "~", "?");
+ let process = Process::new(rebase_todo_file, view);
+ for event in events {
+ process.event_sender.enqueue_event(*event).unwrap();
+ }
+ process
+ .event_sender
+ .enqueue_event(Event::from(MetaEvent::Kill))
+ .unwrap();
+ process
+}
+
#[test]
fn view_start_error() {
- module_test(&["pick aaa comment"], &[], |test_context| {
- let crossterm = create_crossterm();
- let display = Display::new(crossterm, &Theme::new());
- let view = View::new(display, "~", "?");
- let mut process = Process::new(
- test_context.rebase_todo_file,
- test_context.event_handler_context.event_handler,
- view,
- );
- let mut modules = create_modules();
- modules.register_module(State::List, TestModule::new());
- while process.view_sender.end().is_ok() {}
- assert_eq!(process.run(modules).unwrap(), ExitStatus::StateError);
- });
+ let (rebase_todo_file, _file_path) = create_todo_file();
+ let mut process = create_process(rebase_todo_file, &[]);
+ let modules = create_modules();
+ while process.view_sender.end().is_ok() {}
+ assert_eq!(process.run(modules).unwrap(), ExitStatus::StateError);
}
#[test]
fn window_too_small_on_start() {
- module_test(&["pick aaa comment"], &[Event::from(MetaEvent::Exit)], |test_context| {
- let mut crossterm = create_crossterm();
- crossterm.set_size(Size::new(1, 1));
- let display = Display::new(crossterm, &Theme::new());
- let view = View::new(display, "~", "?");
- let mut process = Process::new(
- test_context.rebase_todo_file,
- test_context.event_handler_context.event_handler,
- view,
- );
- let modules = create_modules();
- let _ = process.run(modules).unwrap();
- assert_eq!(process.state, State::WindowSizeError);
- });
+ let (rebase_todo_file, _file_path) = create_todo_file();
+ let mut process = create_process(rebase_todo_file, &[Event::Resize(1, 1)]);
+ let modules = create_modules();
+ let _ = process.run(modules).unwrap();
+ assert_eq!(process.state, State::WindowSizeError);
}
#[test]
fn render_error() {
- module_test(&["pick aaa comment"], &[Event::from(MetaEvent::Exit)], |test_context| {
- let crossterm = create_crossterm();
- let display = Display::new(crossterm, &Theme::new());
- let view = View::new(display, "~", "?");
- let mut process = Process::new(
- test_context.rebase_todo_file,
- test_context.event_handler_context.event_handler,
- view,
- );
- let mut modules = create_modules();
- let mut test_module = TestModule::new();
- let sender = process.view_sender.clone();
- test_module.view_data_callback = Box::new(move |_| while sender.end().is_ok() {});
- modules.register_module(State::List, test_module);
- assert_eq!(process.run(modules).unwrap(), ExitStatus::StateError);
- });
+ let (rebase_todo_file, _file_path) = create_todo_file();
+ let mut process = create_process(rebase_todo_file, &[]);
+ let mut modules = create_modules();
+ let sender = process.view_sender.clone();
+ let mut test_module = TestModule::new();
+ test_module.view_data_callback = Box::new(move |_| while sender.end().is_ok() {});
+ modules.register_module(State::List, test_module);
+ assert_eq!(process.run(modules).unwrap(), ExitStatus::StateError);
}
#[test]
fn view_sender_is_poisoned() {
- module_test(&["pick aaa comment"], &[Event::from(MetaEvent::Exit)], |test_context| {
- let crossterm = create_crossterm();
- let display = Display::new(crossterm, &Theme::new());
- let view = View::new(display, "~", "?");
- let mut process = Process::new(
- test_context.rebase_todo_file,
- test_context.event_handler_context.event_handler,
- view,
- );
- let mut modules = create_modules();
- let test_module = TestModule::new();
- process.view_sender.clone_poisoned().store(true, Ordering::Release);
- modules.register_module(State::List, test_module);
- assert_eq!(process.run(modules).unwrap(), ExitStatus::StateError);
- });
+ let (rebase_todo_file, _file_path) = create_todo_file();
+ let mut process = create_process(rebase_todo_file, &[Event::from(MetaEvent::Exit)]);
+ let modules = create_modules();
+ process.view_sender.clone_poisoned().store(true, Ordering::Release);
+ assert_eq!(process.run(modules).unwrap(), ExitStatus::StateError);
}
#[test]
fn stop_error() {
- module_test(&["pick aaa comment"], &[Event::from(MetaEvent::Exit)], |test_context| {
- let crossterm = create_crossterm();
- let display = Display::new(crossterm, &Theme::new());
- let view = View::new(display, "~", "?");
- let mut process = Process::new(
- test_context.rebase_todo_file,
- test_context.event_handler_context.event_handler,
- view,
- );
- let mut modules = create_modules();
- let mut test_module = TestModule::new();
- let sender = process.view_sender.clone();
- test_module.event_callback = Box::new(move |_, _, _| {
- while sender.end().is_ok() {}
- ProcessResult::new().event(Event::from(MetaEvent::Exit))
- });
- modules.register_module(State::List, test_module);
- assert_eq!(process.run(modules).unwrap(), ExitStatus::StateError);
+ let (rebase_todo_file, _file_path) = create_todo_file();
+ let mut process = create_process(rebase_todo_file, &[Event::from(MetaEvent::Exit)]);
+ let mut modules = create_modules();
+ let mut test_module = TestModule::new();
+ let sender = process.view_sender.clone();
+ test_module.event_callback = Box::new(move |event, _, _| {
+ while sender.end().is_ok() {}
+ ProcessResult::from(event)
});
+ modules.register_module(State::List, test_module);
+ assert_eq!(process.run(modules).unwrap(), ExitStatus::StateError);
}
#[test]
fn handle_exit_event_that_is_not_kill() {
- module_test(&["pick aaa comment"], &[], |mut test_context| {
- test_context.rebase_todo_file.write_file().unwrap();
- test_context.rebase_todo_file.set_lines(vec![]);
- let mut shadow_rebase_file = test_context.new_todo_file();
- let crossterm = create_crossterm();
- let display = Display::new(crossterm, &Theme::new());
- let view = View::new(display, "~", "?");
- let mut process = Process::new(
- test_context.rebase_todo_file,
- test_context.event_handler_context.event_handler,
- view,
- );
- let mut modules = create_modules();
- let mut test_module = TestModule::new();
- test_module.event_callback = Box::new(|_, _, _| {
- ProcessResult::new()
- .event(Event::from(MetaEvent::Rebase))
- .exit_status(ExitStatus::Good)
- });
- modules.register_module(State::List, test_module);
- assert_eq!(process.run(modules).unwrap(), ExitStatus::Good);
- shadow_rebase_file.load_file().unwrap();
- assert!(shadow_rebase_file.is_empty());
+ let (mut rebase_todo_file, _file_path) = create_todo_file();
+ rebase_todo_file.set_lines(vec![]);
+ let mut shadow_rebase_file = create_shadow_todo_file(&rebase_todo_file);
+ let mut process = create_process(rebase_todo_file, &[Event::from(MetaEvent::Exit)]);
+ let mut modules = create_modules();
+ let mut test_module = TestModule::new();
+ test_module.event_callback = Box::new(|_, _, _| {
+ ProcessResult::new()
+ .event(Event::from(MetaEvent::Rebase))
+ .exit_status(ExitStatus::Good)
});
+ modules.register_module(State::List, test_module);
+ assert_eq!(process.run(modules).unwrap(), ExitStatus::Good);
+ shadow_rebase_file.load_file().unwrap();
+ assert!(shadow_rebase_file.is_empty());
}
#[test]
fn handle_exit_event_that_is_kill() {
- module_test(&["pick aaa comment"], &[], |mut test_context| {
- test_context.rebase_todo_file.write_file().unwrap();
- test_context.rebase_todo_file.set_lines(vec![]);
- let mut shadow_rebase_file = test_context.new_todo_file();
- let crossterm = create_crossterm();
- let display = Display::new(crossterm, &Theme::new());
- let view = View::new(display, "~", "?");
- let mut process = Process::new(
- test_context.rebase_todo_file,
- test_context.event_handler_context.event_handler,
- view,
- );
- let mut modules = create_modules();
- let mut test_module = TestModule::new();
- test_module.event_callback = Box::new(|_, _, _| {
- ProcessResult::new()
- .event(Event::from(MetaEvent::Kill))
- .exit_status(ExitStatus::Kill)
- });
- modules.register_module(State::List, test_module);
- assert_eq!(process.run(modules).unwrap(), ExitStatus::Kill);
- shadow_rebase_file.load_file().unwrap();
- assert!(!shadow_rebase_file.is_empty());
+ let (mut rebase_todo_file, _file_path) = create_todo_file();
+ rebase_todo_file.set_lines(vec![]);
+ let mut shadow_rebase_file = create_shadow_todo_file(&rebase_todo_file);
+ let mut process = create_process(rebase_todo_file, &[]);
+ let mut modules = create_modules();
+ let mut test_module = TestModule::new();
+ test_module.event_callback = Box::new(|_, _, _| {
+ ProcessResult::new()
+ .event(Event::from(MetaEvent::Kill))
+ .exit_status(ExitStatus::Kill)
});
+ modules.register_module(State::List, test_module);
+ assert_eq!(process.run(modules).unwrap(), ExitStatus::Kill);
+ shadow_rebase_file.load_file().unwrap();
+ assert!(!shadow_rebase_file.is_empty());
}
#[test]
fn handle_process_result_error() {
- module_test(&["pick aaa comment"], &[], |test_context| {
- let crossterm = create_crossterm();
- let display = Display::new(crossterm, &Theme::new());
- let view = View::new(display, "~", "?");
- let mut process = Process::new(
- test_context.rebase_todo_file,
- test_context.event_handler_context.event_handler,
- view,
- );
- let mut modules = create_modules();
- let result = ProcessResult::new().error(anyhow!("Test error"));
- process.handle_process_result(&mut modules, &result);
- assert_eq!(process.state, State::Error);
- });
+ let (rebase_todo_file, _file_path) = create_todo_file();
+ let mut process = create_process(rebase_todo_file, &[]);
+ let mut modules = create_modules();
+ let result = ProcessResult::new().error(anyhow!("Test error"));
+ process.handle_process_result(&mut modules, &result);
+ assert_eq!(process.state, State::Error);
}
#[test]
fn handle_process_result_new_state() {
- module_test(&["pick aaa comment"], &[], |test_context| {
- let crossterm = create_crossterm();
- let display = Display::new(crossterm, &Theme::new());
- let view = View::new(display, "~", "?");
- let mut process = Process::new(
- test_context.rebase_todo_file,
- test_context.event_handler_context.event_handler,
- view,
- );
- let mut modules = create_modules();
- modules.register_module(State::List, TestModule::new());
- let result = ProcessResult::new().state(State::Error);
- process.handle_process_result(&mut modules, &result);
- assert_eq!(process.state, State::Error);
- });
+ let (rebase_todo_file, _file_path) = create_todo_file();
+ let mut process = create_process(rebase_todo_file, &[]);
+ let mut modules = create_modules();
+ let result = ProcessResult::new().state(State::Error);
+ process.handle_process_result(&mut modules, &result);
+ assert_eq!(process.state, State::Error);
}
#[test]
fn handle_process_result_state_same() {
- module_test(&["pick aaa comment"], &[], |test_context| {
- let crossterm = create_crossterm();
- let display = Display::new(crossterm, &Theme::new());
- let view = View::new(display, "~", "?");
- let mut process = Process::new(
- test_context.rebase_todo_file,
- test_context.event_handler_context.event_handler,
- view,
- );
- let mut modules = create_modules();
- modules.register_module(State::List, TestModule::new());
- let result = ProcessResult::new().state(State::List);
- process.handle_process_result(&mut modules, &result);
- assert_eq!(process.state, State::List);
- });
+ let (rebase_todo_file, _file_path) = create_todo_file();
+ let mut process = create_process(rebase_todo_file, &[]);
+ let mut modules = create_modules();
+ let result = ProcessResult::new().state(State::List);
+ process.handle_process_result(&mut modules, &result);
+ assert_e