From fb63779507c21b5f0a73fef2dbaa10480b02b126 Mon Sep 17 00:00:00 2001 From: Jonas Maier <> Date: Tue, 17 Mar 2026 16:37:44 +0100 Subject: better parsing --- src/parse/test.rs | 94 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 57 insertions(+), 37 deletions(-) (limited to 'src/parse/test.rs') diff --git a/src/parse/test.rs b/src/parse/test.rs index ecd5c8e..b3d9440 100644 --- a/src/parse/test.rs +++ b/src/parse/test.rs @@ -4,23 +4,43 @@ fn parse(x: &[u8]) -> Ast { do_parse(x).unwrap() } -fn parse_test(l: Ast, r: Ast) { - if l != r { - let mut left = Vec::new(); - l.cdisplay(&mut left).unwrap(); - let mut right = Vec::new(); - r.cdisplay(&mut right).unwrap(); - let left = String::from_utf8_lossy(&left); - let right = String::from_utf8_lossy(&right); - if left != right { - panic!("parse equality error\nleft: {left}\nright: {right}") +const TIMEOUT_MS: u64 = 100; + +macro_rules! parse_test { + ($l:expr, $r:expr $(,)?) => {{ + let (tx, rx) = std::sync::mpsc::channel(); + + std::thread::spawn(move || { + #[allow(unreachable_code, unused_variables)] + let result = std::panic::catch_unwind(|| { + let l = $l; + let r = $r; + if l != r { + let mut left = Vec::new(); + l.cdisplay(&mut left).unwrap(); + let mut right = Vec::new(); + r.cdisplay(&mut right).unwrap(); + let left = String::from_utf8_lossy(&left); + let right = String::from_utf8_lossy(&right); + if left != right { + panic!("parse equality error\nleft: {left}\nright: {right}") + } + } + }); + let _ = tx.send(result); + }); + + match rx.recv_timeout(std::time::Duration::from_millis(TIMEOUT_MS)) { + Ok(Ok(())) => (), + Ok(Err(e)) => std::panic::resume_unwind(e), + Err(_) => panic!("test timed out after {TIMEOUT_MS} ms"), } - } + }}; } #[test] fn command_interp() { - parse_test( + parse_test!( parse(br#""$(echo echo)""#), pipes([cmd([str([cmdp(pipes([cmd([ estr(b"echo"), @@ -31,7 +51,7 @@ fn command_interp() { #[test] fn string_concat() { - parse_test( + parse_test!( parse(br#" foo'bar'"baz" "#), pipes([cmd([estr(b"foobarbaz")])]), ); @@ -39,17 +59,17 @@ fn string_concat() { #[test] fn simple_string() { - parse_test(parse(b"foo"), pipes([cmd([estr(b"foo")])])); + parse_test!(parse(b"foo"), pipes([cmd([estr(b"foo")])])); } #[test] fn simple_var() { - parse_test(parse(b"$foo"), pipes([cmd([str([var(b"foo")])])])); + parse_test!(parse(b"$foo"), pipes([cmd([str([var(b"foo")])])])); } #[test] fn ls_pipe_cat() { - parse_test( + parse_test!( parse(b"ls | cat"), pipes([cmd([estr(b"ls")]), cmd([estr(b"cat")])]), ); @@ -57,7 +77,7 @@ fn ls_pipe_cat() { #[test] fn ls_pipe_cat_nospace() { - parse_test( + parse_test!( parse(b"ls|cat"), pipes([cmd([estr(b"ls")]), cmd([estr(b"cat")])]), ); @@ -75,7 +95,7 @@ fn unclosed_double_quote() { #[test] fn tilde() { - parse_test( + parse_test!( parse(b"echo ~"), pipes([cmd([estr(b"echo"), str([var(b"HOME")])])]), ); @@ -83,7 +103,7 @@ fn tilde() { #[test] fn tilde2() { - parse_test( + parse_test!( parse(b"echo ~/foo/bar"), pipes([cmd([ estr(b"echo"), @@ -94,7 +114,7 @@ fn tilde2() { #[test] fn tilde3() { - parse_test( + parse_test!( parse(b"echo ~ "), pipes([cmd([estr(b"echo"), str([var(b"HOME")])])]), ); @@ -102,7 +122,7 @@ fn tilde3() { #[test] fn tilde4() { - parse_test( + parse_test!( parse(b"echo ~'x'"), pipes([cmd([estr(b"echo"), estr(b"~x")])]), ); @@ -110,7 +130,7 @@ fn tilde4() { #[test] fn tilde5() { - parse_test( + parse_test!( parse(b"echo ~$FOO"), pipes([cmd([estr(b"echo"), str([plain(b"~"), var(b"FOO")])])]), ); @@ -118,7 +138,7 @@ fn tilde5() { #[test] fn tilde6() { - parse_test( + parse_test!( parse(b"git rebase -i HEAD~10"), pipes([cmd([ estr(b"git"), @@ -131,7 +151,7 @@ fn tilde6() { #[test] fn set_variable_in_fun() { - parse_test( + parse_test!( parse(b"fun setter { set x = 1 }"), decl(estr(b"setter"), block([assign(estr(b"x"), estr(b"1"))])), ); @@ -139,7 +159,7 @@ fn set_variable_in_fun() { #[test] fn variable_with_defaults() { - parse_test( + parse_test!( parse(b"${x:-y}"), pipes([cmd([str([var_default(b"x", estr(b"y"))])])]), ); @@ -147,32 +167,32 @@ fn variable_with_defaults() { #[test] fn escape_newline() { - parse_test(parse(b"\"\\n\""), pipes([cmd([estr(b"\n")])])); + parse_test!(parse(b"\"\\n\""), pipes([cmd([estr(b"\n")])])); } #[test] fn escape_carriage_return() { - parse_test(parse(b"\"\\r\""), pipes([cmd([estr(b"\r")])])); + parse_test!(parse(b"\"\\r\""), pipes([cmd([estr(b"\r")])])); } #[test] fn escape_tab() { - parse_test(parse(b"\"\\t\""), pipes([cmd([estr(b"\t")])])); + parse_test!(parse(b"\"\\t\""), pipes([cmd([estr(b"\t")])])); } #[test] fn escape_hex_1() { - parse_test(parse(b"\\x41"), pipes([cmd([estr(b"A")])])); + parse_test!(parse(b"\\x41"), pipes([cmd([estr(b"A")])])); } #[test] fn escape_hex_2() { - parse_test(parse(b"\\x0a"), pipes([cmd([estr(b"\n")])])); + parse_test!(parse(b"\\x0a"), pipes([cmd([estr(b"\n")])])); } #[test] fn pipe_on_new_line() { - parse_test( + parse_test!( parse(b"cat file \n | cat"), pipes([cmd([estr(b"cat"), estr(b"file")]), cmd([estr(b"cat")])]), ); @@ -180,7 +200,7 @@ fn pipe_on_new_line() { #[test] fn semicolon() { - parse_test( + parse_test!( parse(b"fun f { x ; y }"), decl( estr(b"f"), @@ -191,7 +211,7 @@ fn semicolon() { #[test] fn newline_separates_commands() { - parse_test( + parse_test!( parse(b"fun f { x \n y }"), decl( estr(b"f"), @@ -202,7 +222,7 @@ fn newline_separates_commands() { #[test] fn newline_does_not_separate_pipes() { - parse_test( + parse_test!( parse(b"fun f { x \n| y }"), decl( estr(b"f"), @@ -213,15 +233,15 @@ fn newline_does_not_separate_pipes() { #[test] fn simple_if() { - parse_test(parse(b"if cond { x }"), todo!()); + parse_test!(parse(b"if cond { x }"), todo!()); } #[test] fn if_else() { - parse_test(parse(b"if cond { x } else { y }"), todo!()); + parse_test!(parse(b"if cond { x } else { y }"), todo!()); } #[test] fn simple_while() { - parse_test(parse(b"while cond { x }"), todo!()); + parse_test!(parse(b"while cond { x }"), todo!()); } -- cgit v1.2.3