1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//! Tests for `parse_assignment` in `parser_decl.rs`.
//!
//! Covers normal assignments, keyword-as-variable names, array element
//! assignments, the append (`+=`) operator, empty assignments, exported
//! assignments, and error cases.
#![allow(clippy::unwrap_used)]
#![allow(clippy::expect_used)]
use super::ast::{BashExpr, BashStmt};
use super::parser::BashParser;
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
/// Parse a single bash statement from `input` and return it.
#[test]
fn test_parse_assignment_variable_value() {
let stmt = parse_first("x=$HOME");
match stmt {
BashStmt::Assignment { name, value, .. } => {
assert_eq!(name, "x");
match &value {
BashExpr::Variable(v) => assert_eq!(v, "HOME"),
BashExpr::Concat(parts) => {
// Some parsers wrap in Concat; accept either
assert!(!parts.is_empty());
}
other => panic!("expected Variable or Concat value, got {other:?}"),
}
}
other => panic!("expected Assignment, got {other:?}"),
}
}
// ===========================================================================
// Not-exported flag is false for regular assignments
// ===========================================================================
#[test]
fn test_parse_assignment_not_exported() {
let stmt = parse_first("y=42");
match stmt {
BashStmt::Assignment { exported, .. } => {
assert!(!exported, "regular assignment should have exported=false");
}
other => panic!("expected Assignment, got {other:?}"),
}
}
// ===========================================================================
// Error cases
// ===========================================================================
#[test]
fn test_parse_assignment_unterminated_string() {
// Unterminated string should be a lexer error
parse_err(r#"x="unclosed"#);
}
#[test]
fn test_parse_assignment_unterminated_string_single_quote() {
// Unterminated single-quoted string should be a lexer error
parse_err("x='unclosed");
}
#[test]
fn test_parse_assignment_missing_bracket_not_array() {
// Without closing bracket, the parser does NOT treat this as an array
// assignment -- `arr` becomes a command and `[0=val` becomes arguments.
// Verify it does not produce an Assignment with an index.
let stmt = parse_first("arr[0=val");
match &stmt {
BashStmt::Assignment { index, .. } => {
// If it somehow parses as assignment, index should be None
// (the `[` would not have been consumed as array syntax)
assert!(index.is_none(), "should not have an array index");
}
// More likely parsed as a Command
BashStmt::Command { .. } => {
// This is acceptable -- the parser saw no `=` after identifier
}
_ => {
// Any other parse is fine as long as it's not an array assignment
}
}
}