use expect_test::{expect, Expect}; use oyster_parser::Parser; fn check(s: &str, expect: Expect) { let actual = Parser::new(s).collect::>(); expect.assert_debug_eq(&actual); } #[test] fn empty() { check( "", expect![[r#" [] "#]], ); } #[test] fn word() { check( "word", expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 4, ), EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn word_with_escape() { check( "hello\\world", expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 5, ), NewLeaf( EscapedChar, 2, ), NewLeaf( PlainText, 4, ), EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn unicode() { check( "谚语", expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 6, ), EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn simple_command() { check( "echo hi", expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 4, ), EndNode, NewLeaf( Whitespace, 1, ), StartNode( Word, ), NewLeaf( PlainText, 2, ), EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn semicolon() { check( "hello; hi", expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 5, ), EndNode, EndNode, NewLeaf( Semicolon, 1, ), EndNode, NewLeaf( Whitespace, 1, ), StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 2, ), EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn comment() { let source = r"# a # b"; check( source, expect![[r#" [ NewLeaf( Comment, 3, ), NewLeaf( Newlines, 1, ), NewLeaf( Comment, 3, ), ] "#]], ); } #[test] fn inline_comment() { check( "whoami # hello", expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 6, ), EndNode, NewLeaf( Whitespace, 1, ), NewLeaf( Comment, 7, ), EndNode, EndNode, ] "#]], ); } #[test] fn pipeline() { check( "whoami | cat", expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 6, ), EndNode, NewLeaf( Whitespace, 1, ), EndNode, NewLeaf( Pipe, 1, ), NewLeaf( Whitespace, 1, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 3, ), EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn multiline_pipeline() { let source = r"whoami | wc -l"; check( source, expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 6, ), EndNode, NewLeaf( Whitespace, 1, ), EndNode, NewLeaf( Pipe, 1, ), NewLeaf( Newlines, 1, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 2, ), EndNode, NewLeaf( Whitespace, 1, ), StartNode( Word, ), NewLeaf( PlainText, 2, ), EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn comment_in_pipeline() { let source = r"whoami | # comment wc -l"; check( source, expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 6, ), EndNode, NewLeaf( Whitespace, 1, ), EndNode, NewLeaf( Pipe, 1, ), NewLeaf( Whitespace, 1, ), NewLeaf( Comment, 9, ), NewLeaf( Newlines, 1, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 2, ), EndNode, NewLeaf( Whitespace, 1, ), StartNode( Word, ), NewLeaf( PlainText, 2, ), EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn reject_leading_pipe() { let source = r"whoami | cat"; check( source, expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 6, ), EndNode, EndNode, EndNode, NewLeaf( Newlines, 1, ), Error( UnexpectedPipe, 1, ), NewLeaf( Whitespace, 1, ), StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 3, ), EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn reject_trailing_pipe() { check( "whoami |", expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 6, ), EndNode, NewLeaf( Whitespace, 1, ), EndNode, NewLeaf( Pipe, 1, ), Error( UnexpectedEof, 0, ), EndNode, ] "#]], ); } #[test] fn reject_pipe_semicolon() { check( "whoami | ; cat", expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 6, ), EndNode, NewLeaf( Whitespace, 1, ), EndNode, NewLeaf( Pipe, 1, ), NewLeaf( Whitespace, 1, ), Error( UnexpectedSemicolon, 1, ), EndNode, NewLeaf( Whitespace, 1, ), StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 3, ), EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn reject_double_pipe() { check( "whoami | | cat", expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 6, ), EndNode, NewLeaf( Whitespace, 1, ), EndNode, NewLeaf( Pipe, 1, ), NewLeaf( Whitespace, 1, ), Error( UnexpectedPipe, 1, ), NewLeaf( Whitespace, 1, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 3, ), EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn double_quote_string() { check( r#""hello world""#, expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), StartNode( DQuotedString, ), NewLeaf( DoubleQuote, 1, ), NewLeaf( PlainText, 11, ), NewLeaf( DoubleQuote, 1, ), EndNode, EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn escaped_char_in_double_quotes() { check( r#""hello \" world""#, expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), StartNode( DQuotedString, ), NewLeaf( DoubleQuote, 1, ), NewLeaf( PlainText, 6, ), NewLeaf( EscapedChar, 2, ), NewLeaf( PlainText, 6, ), NewLeaf( DoubleQuote, 1, ), EndNode, EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn unterminated_double_quotes() { check( r#""hello world"#, expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), StartNode( DQuotedString, ), NewLeaf( DoubleQuote, 1, ), NewLeaf( PlainText, 11, ), Error( UnexpectedEof, 0, ), EndNode, EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn command_substitution() { check( r#"echo (whoami)"#, expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 4, ), EndNode, NewLeaf( Whitespace, 1, ), StartNode( Word, ), StartNode( CommandSubstitution, ), NewLeaf( OpeningParenthesis, 1, ), StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 6, ), EndNode, EndNode, EndNode, NewLeaf( ClosingParenthesis, 1, ), EndNode, EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn quoted_command_substitution() { let source = r#"echo "(whoami) ""#; check( source, expect![[r#" [ StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 4, ), EndNode, NewLeaf( Whitespace, 1, ), StartNode( Word, ), StartNode( DQuotedString, ), NewLeaf( DoubleQuote, 1, ), StartNode( CommandSubstitution, ), NewLeaf( OpeningParenthesis, 1, ), StartNode( Pipeline, ), StartNode( Command, ), StartNode( Word, ), NewLeaf( PlainText, 6, ), EndNode, EndNode, EndNode, NewLeaf( ClosingParenthesis, 1, ), EndNode, NewLeaf( PlainText, 9, ), NewLeaf( DoubleQuote, 1, ), EndNode, EndNode, EndNode, EndNode, ] "#]], ); } #[test] fn empty_pipeline() { check( ";", expect![[r#" [ NewLeaf( Semicolon, 1, ), ] "#]], ); }