extern crate conch_parser; use conch_parser::ast::builder::*; use conch_parser::parse::ParseError::*; use conch_parser::token::Token; mod parse_support; use parse_support::*; #[test] fn test_for_command_valid_with_words() { let mut p = make_parser("\ for var #var comment #prew1 #prew2 in one two three #word comment #precmd1 #precmd2 do echo; #body_comment done "); assert_eq!(p.for_command(), Ok(ForFragments { var: "var".into(), var_comment: Some(Newline(Some("#var comment".into()))), words: Some(( vec!( Newline(Some("#prew1".into())), Newline(Some("#prew2".into())), ), vec!( word("one"), word("two"), word("three"), ), Some(Newline(Some("#word comment".into()))) )), pre_body_comments: vec!( Newline(Some("#precmd1".into())), Newline(Some("#precmd2".into())), ), body: CommandGroup { commands: vec!(cmd("echo")), trailing_comments: vec!(Newline(Some("#body_comment".into()))), }, })); } #[test] fn test_for_command_valid_without_words() { let mut p = make_parser("\ for var #var comment #w1 #w2 do echo; #body_comment done "); assert_eq!(p.for_command(), Ok(ForFragments { var: "var".into(), var_comment: Some(Newline(Some("#var comment".into()))), words: None, pre_body_comments: vec!( Newline(Some("#w1".into())), Newline(Some("#w2".into())), ), body: CommandGroup { commands: vec!(cmd("echo")), trailing_comments: vec!(Newline(Some("#body_comment".into()))), }, })); } #[test] fn test_for_command_valid_separators() { let cases = vec!( "for var do body; done", "for var ; do body; done", "for var ;\n do body; done", "for var\n do body; done", "for var\n in ; do body; done", "for var\n in ;\n do body; done", "for var\n in \n do body; done", "for var in ; do body; done", "for var in ;\n do body; done", "for var in \n do body; done", "for var\n in one two; do body; done", "for var\n in one two;\n do body; done", "for var\n in one two \n do body; done", "for var in one two; do body; done", "for var in one two;\n do body; done", "for var in one two \n do body; done", ); for src in cases { match make_parser(src).for_command() { Ok(_) => {}, e@Err(_) => panic!("expected `{}` to parse successfully, but got: {:?}", src, e), } } } #[test] fn test_for_command_valid_with_separator() { let mut p = make_parser("for var in one two three\ndo echo $var; done"); p.for_command().unwrap(); let mut p = make_parser("for var in one two three;do echo $var; done"); p.for_command().unwrap(); } #[test] fn test_for_command_invalid_with_in_no_words_no_with_separator() { let mut p = make_parser("for var in do echo $var; done"); assert_eq!(Err(IncompleteCmd("for", src(0,1,1), "do", src(25,1,26))), p.for_command()); } #[test] fn test_for_command_invalid_missing_separator() { let mut p = make_parser("for var in one two three do echo $var; done"); assert_eq!(Err(IncompleteCmd("for", src(0,1,1), "do", src(39,1,40))), p.for_command()); } #[test] fn test_for_command_invalid_amp_not_valid_separator() { let mut p = make_parser("for var in one two three& do echo $var; done"); assert_eq!(Err(Unexpected(Token::Amp, src(24, 1, 25))), p.for_command()); } #[test] fn test_for_command_invalid_missing_keyword() { let mut p = make_parser("var in one two three\ndo echo $var; done"); assert_eq!(Err(Unexpected(Token::Name(String::from("var")), src(0,1,1))), p.for_command()); } #[test] fn test_for_command_invalid_missing_var() { let mut p = make_parser("for in one two three\ndo echo $var; done"); assert_eq!(Err(IncompleteCmd("for", src(0,1,1), "in", src(7,1,8))), p.for_command()); } #[test] fn test_for_command_invalid_missing_body() { let mut p = make_parser("for var in one two three\n"); assert_eq!(Err(IncompleteCmd("for", src(0,1,1), "do", src(25,2,1))), p.for_command()); } #[test] fn test_for_command_invalid_quoted() { let cmds = [ ("'for' var in one two three\ndo echo $var; done", Unexpected(Token::SingleQuote, src(0,1,1))), ("for var 'in' one two three\ndo echo $var; done", IncompleteCmd("for", src(0,1,1), "in", src(8,1,9))), ("\"for\" var in one two three\ndo echo $var; done", Unexpected(Token::DoubleQuote, src(0,1,1))), ("for var \"in\" one two three\ndo echo $var; done", IncompleteCmd("for", src(0,1,1), "in", src(8,1,9))), ]; for &(c, ref e) in cmds.into_iter() { match make_parser(c).for_command() { Ok(result) => panic!("Unexpectedly parsed \"{}\" as\n{:#?}", c, result), Err(ref err) => if err != e { panic!("Expected the source \"{}\" to return the error `{:?}`, but got `{:?}`", c, e, err); }, } } } #[test] fn test_for_command_invalid_var_must_be_name() { let mut p = make_parser("for 123var in one two three\ndo echo $var; done"); assert_eq!(Err(BadIdent(String::from("123var"), src(4, 1, 5))), p.for_command()); let mut p = make_parser("for 'var' in one two three\ndo echo $var; done"); assert_eq!(Err(Unexpected(Token::SingleQuote, src(4, 1, 5))), p.for_command()); let mut p = make_parser("for \"var\" in one two three\ndo echo $var; done"); assert_eq!(Err(Unexpected(Token::DoubleQuote, src(4, 1, 5))), p.for_command()); let mut p = make_parser("for var*% in one two three\ndo echo $var; done"); assert_eq!(Err(IncompleteCmd("for", src(0, 1, 1), "in", src(7, 1, 8))), p.for_command()); } #[test] fn test_for_command_invalid_concat() { let mut p = make_parser_from_tokens(vec!( Token::Literal(String::from("fo")), Token::Literal(String::from("r")), Token::Whitespace(String::from(" ")), Token::Name(String::from("var")), Token::Whitespace(String::from(" ")), Token::Literal(String::from("in")), Token::Literal(String::from("one")), Token::Whitespace(String::from(" ")), Token::Literal(String::from("two")), Token::Whitespace(String::from(" ")), Token::Literal(String::from("three")), Token::Whitespace(String::from(" ")), Token::Newline, Token::Literal(String::from("do")), Token::Whitespace(String::from(" ")), Token::Literal(String::from("echo")), Token::Whitespace(String::from(" ")), Token::Dollar, Token::Literal(String::from("var")), Token::Newline, Token::Literal(String::from("done")), )); assert_eq!(Err(Unexpected(Token::Literal(String::from("fo")), src(0, 1, 1))), p.for_command()); let mut p = make_parser_from_tokens(vec!( Token::Literal(String::from("for")), Token::Whitespace(String::from(" ")), Token::Name(String::from("var")), Token::Whitespace(String::from(" ")), Token::Literal(String::from("i")), Token::Literal(String::from("n")), Token::Literal(String::from("one")), Token::Whitespace(String::from(" ")), Token::Literal(String::from("two")), Token::Whitespace(String::from(" ")), Token::Literal(String::from("three")), Token::Whitespace(String::from(" ")), Token::Newline, Token::Literal(String::from("do")), Token::Whitespace(String::from(" ")), Token::Literal(String::from("echo")), Token::Whitespace(String::from(" ")), Token::Dollar, Token::Literal(String::from("var")), Token::Newline, Token::Literal(String::from("done")), )); assert_eq!(Err(IncompleteCmd("for", src(0,1,1), "in", src(8,1,9))), p.for_command()); } #[test] fn test_for_command_should_recognize_literals_and_names() { for for_tok in vec!(Token::Literal(String::from("for")), Token::Name(String::from("for"))) { for in_tok in vec!(Token::Literal(String::from("in")), Token::Name(String::from("in"))) { let mut p = make_parser_from_tokens(vec!( for_tok.clone(), Token::Whitespace(String::from(" ")), Token::Name(String::from("var")), Token::Whitespace(String::from(" ")), in_tok.clone(), Token::Whitespace(String::from(" ")), Token::Literal(String::from("one")), Token::Whitespace(String::from(" ")), Token::Literal(String::from("two")), Token::Whitespace(String::from(" ")), Token::Literal(String::from("three")), Token::Whitespace(String::from(" ")), Token::Newline, Token::Literal(String::from("do")), Token::Whitespace(String::from(" ")), Token::Literal(String::from("echo")), Token::Whitespace(String::from(" ")), Token::Dollar, Token::Name(String::from("var")), Token::Newline, Token::Literal(String::from("done")), )); p.for_command().unwrap(); } } }