aboutsummaryrefslogtreecommitdiff
path: root/helix-term
diff options
context:
space:
mode:
Diffstat (limited to 'helix-term')
-rw-r--r--helix-term/Cargo.toml5
-rw-r--r--helix-term/src/application.rs20
-rw-r--r--helix-term/tests/integration.rs163
3 files changed, 165 insertions, 23 deletions
diff --git a/helix-term/Cargo.toml b/helix-term/Cargo.toml
index 0f80c416..05f8eed4 100644
--- a/helix-term/Cargo.toml
+++ b/helix-term/Cargo.toml
@@ -17,6 +17,7 @@ app = true
[features]
unicode-lines = ["helix-core/unicode-lines"]
+integration = []
[[bin]]
name = "hx"
@@ -73,3 +74,7 @@ signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] }
[build-dependencies]
helix-loader = { version = "0.6", path = "../helix-loader" }
+
+[dev-dependencies]
+smallvec = "1.8"
+indoc = "1.0.3"
diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs
index 09b7836f..21595eae 100644
--- a/helix-term/src/application.rs
+++ b/helix-term/src/application.rs
@@ -187,13 +187,21 @@ impl Application {
}
fn render(&mut self) {
- let mut cx = crate::compositor::Context {
- editor: &mut self.editor,
- jobs: &mut self.jobs,
- scroll: None,
- };
+ #[cfg(feature = "integration")]
+ return;
+
+ #[allow(unreachable_code)]
+ {
+ let compositor = &mut self.compositor;
- // self.compositor.render(&mut cx);
+ let mut cx = crate::compositor::Context {
+ editor: &mut self.editor,
+ jobs: &mut self.jobs,
+ scroll: None,
+ };
+
+ compositor.render(&mut cx);
+ }
}
pub async fn event_loop(&mut self) {
diff --git a/helix-term/tests/integration.rs b/helix-term/tests/integration.rs
index 1ef618f7..31a0d218 100644
--- a/helix-term/tests/integration.rs
+++ b/helix-term/tests/integration.rs
@@ -1,24 +1,153 @@
-use helix_term::{application::Application, args::Args, config::Config};
-use helix_view::current;
+#[cfg(feature = "integration")]
+mod integration {
+ use std::path::PathBuf;
-use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
+ use helix_core::{syntax::AutoPairConfig, Position, Selection, Tendril, Transaction};
+ use helix_term::{application::Application, args::Args, config::Config};
+ use helix_view::{current, doc, input::parse_macro};
-#[tokio::test]
-async fn it_works() {
- let args = Args::default();
- let config = Config::default();
- let mut app = Application::new(args, config).unwrap();
+ use crossterm::event::{Event, KeyEvent};
+ use indoc::indoc;
- let inputs = &['i', 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'];
+ pub struct TestCase {
+ pub in_text: String,
+ pub in_selection: Selection,
+ pub in_keys: String,
+ pub out_text: String,
+ pub out_selection: Selection,
+ }
+
+ fn test_key_sequence(
+ app: Option<Application>,
+ test_case: &TestCase,
+ test_fn: &dyn Fn(&mut Application),
+ ) -> anyhow::Result<()> {
+ let mut app =
+ app.unwrap_or_else(|| Application::new(Args::default(), Config::default()).unwrap());
+
+ let (view, doc) = current!(app.editor);
+
+ doc.apply(
+ &Transaction::insert(
+ doc.text(),
+ &Selection::single(1, 0),
+ Tendril::from(&test_case.in_text),
+ )
+ .with_selection(test_case.in_selection.clone()),
+ view.id,
+ );
+
+ let input_keys = parse_macro(&test_case.in_keys)?
+ .into_iter()
+ .map(|key_event| Event::Key(KeyEvent::from(key_event)));
+
+ for key in input_keys {
+ app.handle_terminal_events(Ok(key));
+ }
+
+ test_fn(&mut app);
+
+ Ok(())
+ }
+
+ /// Use this for very simple test cases where there is one input
+ /// document, selection, and sequence of key presses, and you just
+ /// want to verify the resulting document and selection.
+ fn test_key_sequence_text_result(
+ args: Args,
+ config: Config,
+ test_case: TestCase,
+ ) -> anyhow::Result<()> {
+ let app = Application::new(args, config).unwrap();
+
+ test_key_sequence(Some(app), &test_case, &|app| {
+ let doc = doc!(app.editor);
+ assert_eq!(&test_case.out_text, doc.text());
- for input in inputs {
- // TODO: use input.parse::<KeyEvent>
- app.handle_terminal_events(Ok(Event::Key(KeyEvent {
- code: KeyCode::Char(*input),
- modifiers: KeyModifiers::NONE,
- })));
+ let mut selections: Vec<_> = doc.selections().values().cloned().collect();
+ assert_eq!(1, selections.len());
+
+ let sel = selections.pop().unwrap();
+ assert_eq!(test_case.out_selection, sel);
+ })?;
+
+ Ok(())
+ }
+
+ #[tokio::test]
+ async fn hello_world() -> anyhow::Result<()> {
+ test_key_sequence_text_result(
+ Args::default(),
+ Config::default(),
+ TestCase {
+ in_text: String::new(),
+ in_selection: Selection::single(0, 1),
+ // TODO: fix incorrect selection on new doc
+ in_keys: String::from("ihello world<esc>hl"),
+ out_text: String::from("hello world\n"),
+ out_selection: Selection::single(11, 12),
+ },
+ )?;
+
+ Ok(())
}
- let (_, doc) = current!(app.editor);
- assert_eq!(doc.text(), "hello world\n");
+ #[tokio::test]
+ async fn auto_pairs_basic() -> anyhow::Result<()> {
+ test_key_sequence_text_result(
+ Args::default(),
+ Config::default(),
+ TestCase {
+ in_text: String::new(),
+ in_selection: Selection::single(0, 1),
+ in_keys: String::from("i(<esc>hl"),
+ out_text: String::from("()\n"),
+ out_selection: Selection::single(1, 2),
+ },
+ )?;
+
+ test_key_sequence_text_result(
+ Args::default(),
+ Config {
+ editor: helix_view::editor::Config {
+ auto_pairs: AutoPairConfig::Enable(false),
+ ..Default::default()
+ },
+ ..Default::default()
+ },
+ TestCase {
+ in_text: String::new(),
+ in_selection: Selection::single(0, 1),
+ in_keys: String::from("i(<esc>hl"),
+ out_text: String::from("(\n"),
+ out_selection: Selection::single(1, 2),
+ },
+ )?;
+
+ Ok(())
+ }
+
+ #[tokio::test]
+ async fn auto_indent_rs() -> anyhow::Result<()> {
+ test_key_sequence_text_result(
+ Args {
+ files: vec![(PathBuf::from("foo.c"), Position::default())],
+ ..Default::default()
+ },
+ Config::default(),
+ TestCase {
+ in_text: String::from("void foo() {}"),
+ in_selection: Selection::single(12, 13),
+ in_keys: String::from("i<ret><esc>"),
+ out_text: String::from(indoc! {r#"
+ void foo() {
+
+ }
+ "#}),
+ out_selection: Selection::single(15, 16),
+ },
+ )?;
+
+ Ok(())
+ }
}