@@ -5,7 +5,6 @@ use crossterm::event::{Event, KeyEvent};
5use helix_core::{test, Selection, Transaction};
5use helix_core::{test, Selection, Transaction};
6use helix_term::{application::Application, args::Args, config::Config};
6use helix_term::{application::Application, args::Args, config::Config};
7use helix_view::{doc, input::parse_macro};
7use helix_view::{doc, input::parse_macro};
8−use tokio::time::timeout;
9use tokio_stream::wrappers::UnboundedReceiverStream;
8use tokio_stream::wrappers::UnboundedReceiverStream;
11#[derive(Clone, Debug)]
10#[derive(Clone, Debug)]
@@ -32,35 +31,48 @@ impl<S: Into<String>> From<(S, S, S)> for TestCase {
35pub async fn test_key_sequence(
35pub async fn test_key_sequence(
36 app: &mut Application,
36 app: &mut Application,
37 in_keys: &str,
37 in_keys: &str,
38 test_fn: Option<&dyn Fn(&Application)>,
38 test_fn: Option<&dyn Fn(&Application)>,
39+ timeout: Option<Duration>,
39) -> anyhow::Result<()> {
40) -> anyhow::Result<()> {
41+ test_key_sequences(app, vec![(in_keys, test_fn)], timeout).await
44+pub async fn test_key_sequences(
45+ app: &mut Application,
46+ inputs: Vec<(&str, Option<&dyn Fn(&Application)>)>,
47+ timeout: Option<Duration>,
48+) -> anyhow::Result<()> {
49+ let timeout = timeout.unwrap_or(Duration::from_millis(500));
40 let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
50 let (tx, rx) = tokio::sync::mpsc::unbounded_channel();
51+ let mut rx_stream = UnboundedReceiverStream::new(rx);
53+ for (in_keys, test_fn) in inputs {
42− for key_event in parse_macro(&in_keys)?.into_iter() {
54+ for key_event in parse_macro(&in_keys)?.into_iter() {
43− tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?;
55+ tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?;
46− let mut rx_stream = UnboundedReceiverStream::new(rx);
47− let event_loop = app.event_loop(&mut rx_stream);
58+ let event_loop = app.event_loop(&mut rx_stream);
48− let result = timeout(Duration::from_millis(500), event_loop).await;
59+ let result = tokio::time::timeout(timeout, event_loop).await;
50− if result.is_ok() {
61+ if result.is_ok() {
51− bail!("application exited before test function could run");
62+ bail!("application exited before test function could run");
54− if let Some(test) = test_fn {
65+ if let Some(test) = test_fn {
55− test(app);
66+ test(app);
58 for key_event in parse_macro("<esc>:q!<ret>")?.into_iter() {
70 for key_event in parse_macro("<esc>:q!<ret>")?.into_iter() {
59 tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?;
71 tx.send(Ok(Event::Key(KeyEvent::from(key_event))))?;
62 let event_loop = app.event_loop(&mut rx_stream);
74 let event_loop = app.event_loop(&mut rx_stream);
63− timeout(Duration::from_millis(5000), event_loop).await?;
75+ tokio::time::timeout(timeout, event_loop).await?;
64 app.close().await?;
76 app.close().await?;
@@ -70,6 +82,7 @@ pub async fn test_key_sequence_with_input_text<T: Into<TestCase>>(
70 app: Option<Application>,
82 app: Option<Application>,
71 test_case: T,
83 test_case: T,
72 test_fn: &dyn Fn(&Application),
84 test_fn: &dyn Fn(&Application),
85+ timeout: Option<Duration>,
73) -> anyhow::Result<()> {
86) -> anyhow::Result<()> {
74 let test_case = test_case.into();
87 let test_case = test_case.into();
75 let mut app =
88 let mut app =
@@ -87,7 +100,7 @@ pub async fn test_key_sequence_with_input_text<T: Into<TestCase>>(
90− test_key_sequence(&mut app, &test_case.in_keys, Some(test_fn)).await
103+ test_key_sequence(&mut app, &test_case.in_keys, Some(test_fn), timeout).await
93/// Use this for very simple test cases where there is one input
106/// Use this for very simple test cases where there is one input
@@ -97,20 +110,26 @@ pub async fn test_key_sequence_text_result<T: Into<TestCase>>(
97 args: Args,
110 args: Args,
98 config: Config,
111 config: Config,
99 test_case: T,
112 test_case: T,
113+ timeout: Option<Duration>,
100) -> anyhow::Result<()> {
114) -> anyhow::Result<()> {
101 let test_case = test_case.into();
115 let test_case = test_case.into();
102 let app = Application::new(args, config).unwrap();
116 let app = Application::new(args, config).unwrap();
104− test_key_sequence_with_input_text(Some(app), test_case.clone(), &|app| {
118+ test_key_sequence_with_input_text(
105− let doc = doc!(app.editor);
122+ let doc = doc!(app.editor);
106− assert_eq!(&test_case.out_text, doc.text());
123+ assert_eq!(&test_case.out_text, doc.text());
108− let mut selections: Vec<_> = doc.selections().values().cloned().collect();
125+ let mut selections: Vec<_> = doc.selections().values().cloned().collect();
109− assert_eq!(1, selections.len());
126+ assert_eq!(1, selections.len());
111− let sel = selections.pop().unwrap();
128+ let sel = selections.pop().unwrap();
112− assert_eq!(test_case.out_selection, sel);
129+ assert_eq!(test_case.out_selection, sel);