fn test_format_parse_diagnostic_unexpected_token() {
use super::parser::format_parse_diagnostic;
let source = "if true; echo hi; fi";
let err = ParseError::UnexpectedToken {
expected: "'then' keyword".to_string(),
found: "'echo'".to_string(),
line: 1,
};
let diag = format_parse_diagnostic(&err, source, Some("test.sh"));
assert!(diag.error.contains("expected") || diag.error.contains("then"));
}
#[test]
fn test_format_parse_diagnostic_unexpected_eof() {
use super::parser::format_parse_diagnostic;
let source = "if true; then\n echo hi\n";
let err = ParseError::UnexpectedEof;
let diag = format_parse_diagnostic(&err, source, None);
assert!(diag.error.contains("end of file") || diag.error.contains("unexpected"));
}
#[test]
fn test_format_parse_diagnostic_invalid_syntax() {
use super::parser::format_parse_diagnostic;
let source = "echo test";
let err = ParseError::InvalidSyntax("something went wrong".to_string());
let diag = format_parse_diagnostic(&err, source, None);
assert!(diag.error.contains("something went wrong"));
}
#[test]
fn test_build_snippet_line_context() {
use super::parser_error_display::build_snippet;
let source = "line1\nline2\nline3\nline4";
let snippet = build_snippet(source, 2, Some(3), 4);
assert!(snippet.contains("line2"));
}
#[test]
fn test_build_snippet_first_line() {
use super::parser_error_display::build_snippet;
let source = "only_one_line";
let snippet = build_snippet(source, 1, None, 1);
assert!(snippet.contains("only_one_line"));
}
#[test]
fn test_skip_newlines_between_statements() {
let input = "\n\n\necho hello\n\n\necho world\n\n";
let mut parser = BashParser::new(input).unwrap();
let ast = parser.parse().unwrap();
assert_eq!(ast.statements.len(), 2);
}
#[test]
fn test_syntax_error_in_pipeline_without_rhs() {
let input = "echo hello |";
let result = BashParser::new(input).and_then(|mut p| p.parse());
let _ = result;
}
#[test]
fn test_parse_empty_input() {
let input = "";
let mut parser = BashParser::new(input).unwrap();
let ast = parser.parse().unwrap();
assert!(ast.statements.is_empty());
}
#[test]
fn test_parser_source_accessor() {
let input = "echo hello";
let parser = BashParser::new(input).unwrap();
assert_eq!(parser.source(), input);
}
#[test]
fn test_parse_until_loop() {
let input = "until false; do\n echo waiting\ndone";
let result = BashParser::new(input).and_then(|mut p| p.parse());
let _ = result;
}
#[test]
fn test_parse_brace_group() {
let input = "{ echo a; echo b; }";
let mut parser = BashParser::new(input).unwrap();
let ast = parser.parse().unwrap();
assert!(!ast.statements.is_empty());
}
#[test]
fn test_parse_subshell() {
let input = "(echo hello; echo world)";
let mut parser = BashParser::new(input).unwrap();
let ast = parser.parse().unwrap();
assert!(!ast.statements.is_empty());
}
#[test]
fn test_parse_if_elif_else() {
let input = r#"if [ $x = 1 ]; then
echo one
elif [ $x = 2 ]; then
echo two
else
echo other
fi"#;
let mut parser = BashParser::new(input).unwrap();
let ast = parser.parse().unwrap();
assert!(ast
.statements
.iter()
.any(|s| matches!(s, BashStmt::If { .. })));
}
#[test]
fn test_parse_arithmetic_expansion_assignment() {
let input = "RESULT=$((1 + 2))";
let mut parser = BashParser::new(input).unwrap();
let ast = parser.parse().unwrap();
assert!(!ast.statements.is_empty());
}
#[test]
fn test_parse_command_substitution_assignment() {
let input = "PWD=$(pwd)";
let mut parser = BashParser::new(input).unwrap();
let ast = parser.parse().unwrap();
assert!(!ast.statements.is_empty());
}
#[test]
fn test_parse_multiple_redirects_on_command() {
let input = "cmd 2>/dev/null 1>/tmp/out";
let result = BashParser::new(input).and_then(|mut p| p.parse());
let _ = result;
}
#[test]
fn test_parse_negated_pipeline() {
let input = "! grep foo bar.txt";
let result = BashParser::new(input).and_then(|mut p| p.parse());
let _ = result;
}