Skip to content

Commit ab873ac

Browse files
chaliyclaude
andauthored
test: add 14 Oils-inspired spec test files (244 tests) (#351)
## Summary - Add 14 new spec test files inspired by the [Oils (oilshell)](https://github.com/oilshell/oil/tree/master/spec) test suite covering previously untested bash behaviors - 244 new tests total: 108 passing, 136 skipped with TODO markers identifying unimplemented features - Each file links to the original Oils test for reference ### High-value test coverage (7 files, 139 tests): | File | Tests | Pass | Skip | Gaps found | |------|-------|------|------|------------| | `word-split.test.sh` | 39 | 3 | 36 | IFS splitting, `$@`/`$*`, word elision | | `quote.test.sh` | 22 | 11 | 11 | `$''`, `$""`, adjacent single quotes | | `parse-errors.test.sh` | 18 | 7 | 11 | Incomplete constructs, unterminated quotes | | `shell-grammar.test.sh` | 22 | 22 | 0 | All pass | | `empty-bodies.test.sh` | 8 | 3 | 5 | Empty loop/function bodies not rejected | | `exit-status.test.sh` | 17 | 8 | 9 | Exit code not truncated to 8-bit | | `subshell.test.sh` | 13 | 9 | 4 | Function/cd/trap/positional leak | ### Medium-value test coverage (7 files, 105 tests): | File | Tests | Pass | Skip | Gaps found | |------|-------|------|------|------------| | `nameref.test.sh` | 14 | 0 | 14 | `local -n`/`typeset -n` not implemented | | `var-op-test.test.sh` | 19 | 5 | 14 | `${@-val}`, `${arr[@]+val}`, backslash escapes | | `heredoc-edge.test.sh` | 16 | 10 | 6 | Multiple heredocs in conditions, pipe ordering | | `unicode.test.sh` | 17 | 11 | 6 | `$'\u...'`, printf `\u`, `${#x}` byte vs char | | `alias.test.sh` | 15 | 0 | 15 | Alias expansion not implemented | | `temp-binding.test.sh` | 10 | 10 | 0 | All pass | | `arith-dynamic.test.sh` | 14 | 9 | 5 | Recursive var deref, array access in `$((...))` | ## Test plan - [x] `cargo test --test spec_tests` passes (all 13 suites green) - [x] `cargo test --test spec_tests -- bash_comparison_tests` passes - [x] Rebased on latest main - [x] No conflicts with recent main changes Co-authored-by: Claude <noreply@anthropic.com>
1 parent 015876e commit ab873ac

14 files changed

+2829
-0
lines changed
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Alias tests
2+
# Inspired by Oils spec/alias.test.sh
3+
# https://github.com/oilshell/oil/blob/master/spec/alias.test.sh
4+
5+
### alias_basic
6+
# Basic alias definition and use
7+
### skip: TODO alias expansion not implemented
8+
shopt -s expand_aliases
9+
alias hi='echo hello world'
10+
hi
11+
### expect
12+
hello world
13+
### end
14+
15+
### alias_override_builtin
16+
# alias can override builtin
17+
### skip: TODO alias expansion not implemented
18+
shopt -s expand_aliases
19+
alias echo='echo foo'
20+
echo bar
21+
### expect
22+
foo bar
23+
### end
24+
25+
### alias_define_multiple
26+
# defining multiple aliases
27+
### skip: TODO alias expansion not implemented
28+
shopt -s expand_aliases
29+
alias echo_x='echo X' echo_y='echo Y'
30+
echo_x
31+
echo_y
32+
### expect
33+
X
34+
Y
35+
### end
36+
37+
### alias_unalias
38+
# unalias removes alias
39+
### skip: TODO alias expansion not implemented
40+
shopt -s expand_aliases
41+
alias hi='echo hello'
42+
hi
43+
unalias hi
44+
hi 2>/dev/null
45+
echo status=$?
46+
### expect
47+
hello
48+
status=127
49+
### end
50+
51+
### alias_unalias_all
52+
# unalias -a removes all
53+
### skip: TODO alias expansion not implemented
54+
alias foo=bar
55+
alias spam=eggs
56+
unalias -a
57+
alias 2>/dev/null | wc -l
58+
### expect
59+
0
60+
### end
61+
62+
### alias_not_defined_error
63+
# alias for non-existent returns error
64+
### skip: TODO alias expansion not implemented
65+
alias nonexistentZZZ 2>/dev/null
66+
echo status=$?
67+
### expect
68+
status=1
69+
### end
70+
71+
### alias_unalias_not_defined_error
72+
# unalias for non-existent returns error
73+
### skip: TODO alias expansion not implemented
74+
unalias nonexistentZZZ 2>/dev/null
75+
echo status=$?
76+
### expect
77+
status=1
78+
### end
79+
80+
### alias_with_variable
81+
# Alias with variable expansion at use-time
82+
### skip: TODO alias expansion not implemented
83+
shopt -s expand_aliases
84+
x=early
85+
alias echo_x='echo $x'
86+
x=late
87+
echo_x
88+
### expect
89+
late
90+
### end
91+
92+
### alias_trailing_space
93+
# alias with trailing space triggers expansion of next word
94+
### skip: TODO alias expansion not implemented
95+
shopt -s expand_aliases
96+
alias hi='echo hello world '
97+
alias punct='!!!'
98+
hi punct
99+
### expect
100+
hello world !!!
101+
### end
102+
103+
### alias_recursive_first_word
104+
# Recursive alias expansion of first word
105+
### skip: TODO alias expansion not implemented
106+
shopt -s expand_aliases
107+
alias hi='e_ hello world'
108+
alias e_='echo __'
109+
hi
110+
### expect
111+
__ hello world
112+
### end
113+
114+
### alias_must_be_unquoted
115+
# Alias must be an unquoted word
116+
### skip: TODO alias expansion not implemented
117+
shopt -s expand_aliases
118+
alias echo_alias_='echo'
119+
cmd=echo_alias_
120+
echo_alias_ X
121+
$cmd X 2>/dev/null
122+
echo status=$?
123+
### expect
124+
X
125+
status=127
126+
### end
127+
128+
### alias_in_pipeline
129+
# Two aliases in pipeline
130+
### skip: TODO alias expansion not implemented
131+
shopt -s expand_aliases
132+
alias myseq='seq '
133+
alias mywc='wc '
134+
myseq 3 | mywc -l
135+
### expect
136+
3
137+
### end
138+
139+
### alias_used_in_subshell
140+
# alias used in subshell
141+
### skip: TODO alias expansion not implemented
142+
shopt -s expand_aliases
143+
alias echo_='echo [ '
144+
( echo_ subshell; )
145+
echo $(echo_ commandsub)
146+
### expect
147+
[ subshell
148+
[ commandsub
149+
### end
150+
151+
### alias_with_semicolon_pipeline
152+
# Alias that is && || ;
153+
### skip: TODO alias expansion not implemented
154+
shopt -s expand_aliases
155+
alias t1='echo one && echo two'
156+
t1
157+
### expect
158+
one
159+
two
160+
### end
161+
162+
### alias_list_all
163+
# alias without args lists all
164+
### skip: TODO alias expansion not implemented
165+
alias ex=exit ll='ls -l'
166+
alias | grep -c 'ex\|ll'
167+
### expect
168+
2
169+
### end
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
# Dynamic arithmetic tests
2+
# Inspired by Oils spec/arith-dynamic.test.sh
3+
# https://github.com/oilshell/oil/blob/master/spec/arith-dynamic.test.sh
4+
5+
### arith_dyn_var_reference
6+
# Variable references in arithmetic
7+
x='1'
8+
echo $(( x + 2 * 3 ))
9+
### expect
10+
7
11+
### end
12+
13+
### arith_dyn_var_expression
14+
# Variable containing expression is re-evaluated
15+
### skip: TODO arithmetic variable re-evaluation of expressions not implemented
16+
x='1 + 2'
17+
echo $(( x * 3 ))
18+
### expect
19+
9
20+
### end
21+
22+
### arith_dyn_substitution
23+
# $x in arithmetic
24+
x='1 + 2'
25+
echo $(( $x * 3 ))
26+
### expect
27+
7
28+
### end
29+
30+
### arith_dyn_quoted_substitution
31+
# "$x" in arithmetic
32+
### skip: TODO double-quoted substitution in arithmetic not implemented
33+
x='1 + 2'
34+
echo $(( "$x" * 3 ))
35+
### expect
36+
7
37+
### end
38+
39+
### arith_dyn_nested_var
40+
# Nested variable reference in arithmetic
41+
### skip: TODO recursive variable dereferencing in arithmetic not implemented
42+
a=3
43+
b=a
44+
echo $(( b + 1 ))
45+
### expect
46+
4
47+
### end
48+
49+
### arith_dyn_array_index
50+
# Dynamic array index
51+
### skip: TODO array access in arithmetic expressions not implemented
52+
arr=(10 20 30 40)
53+
i=2
54+
echo $(( arr[i] ))
55+
### expect
56+
30
57+
### end
58+
59+
### arith_dyn_array_index_expr
60+
# Expression as array index
61+
### skip: TODO array access in arithmetic expressions not implemented
62+
arr=(10 20 30 40)
63+
echo $(( arr[1+1] ))
64+
### expect
65+
30
66+
### end
67+
68+
### arith_dyn_conditional
69+
# Ternary operator
70+
x=5
71+
echo $(( x > 3 ? 1 : 0 ))
72+
echo $(( x < 3 ? 1 : 0 ))
73+
### expect
74+
1
75+
0
76+
### end
77+
78+
### arith_dyn_comma
79+
# Comma operator
80+
echo $(( 1, 2, 3 ))
81+
### expect
82+
3
83+
### end
84+
85+
### arith_dyn_assign_in_expr
86+
# Assignment within arithmetic expression
87+
echo $(( x = 5 + 3 ))
88+
echo $x
89+
### expect
90+
8
91+
8
92+
### end
93+
94+
### arith_dyn_pre_post_increment
95+
# Pre/post increment in dynamic context
96+
x=5
97+
echo $(( x++ ))
98+
echo $x
99+
echo $(( ++x ))
100+
echo $x
101+
### expect
102+
5
103+
6
104+
7
105+
7
106+
### end
107+
108+
### arith_dyn_compound_assign
109+
# Compound assignment operators
110+
x=10
111+
echo $(( x += 5 ))
112+
echo $(( x -= 3 ))
113+
echo $(( x *= 2 ))
114+
echo $(( x /= 4 ))
115+
echo $(( x %= 2 ))
116+
### expect
117+
15
118+
12
119+
24
120+
6
121+
0
122+
### end
123+
124+
### arith_dyn_unset_var_is_zero
125+
# Unset variable in arithmetic treated as 0
126+
unset arith_undef_xyz
127+
echo $(( arith_undef_xyz + 5 ))
128+
### expect
129+
5
130+
### end
131+
132+
### arith_dyn_string_var_is_zero
133+
# Non-numeric string in arithmetic treated as 0
134+
x=hello
135+
echo $(( x + 5 ))
136+
### expect
137+
5
138+
### end
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Empty body tests
2+
# Inspired by Oils spec/empty-bodies.test.sh
3+
# https://github.com/oilshell/oil/blob/master/spec/empty-bodies.test.sh
4+
5+
### empty_case_esac
6+
# Empty case/esac is valid
7+
case foo in
8+
esac
9+
echo empty
10+
### expect
11+
empty
12+
### end
13+
14+
### empty_while_do_done
15+
# Empty while body - bash treats as parse error, bashkit allows it
16+
### skip: TODO empty while body not rejected as parse error
17+
bash -c 'while false; do
18+
done
19+
echo empty' 2>/dev/null
20+
echo status=$?
21+
### expect
22+
status=2
23+
### end
24+
25+
### empty_if_then_fi
26+
# Empty then body - bash treats as parse error, bashkit allows it
27+
### skip: TODO empty if body not rejected as parse error
28+
bash -c 'if true; then
29+
fi
30+
echo empty' 2>/dev/null
31+
echo status=$?
32+
### expect
33+
status=2
34+
### end
35+
36+
### empty_else_clause
37+
# Empty else clause - bash treats as parse error, bashkit allows it
38+
### skip: TODO empty else body not rejected as parse error
39+
bash -c 'if false; then echo yes; else
40+
fi' 2>/dev/null
41+
echo status=$?
42+
### expect
43+
status=2
44+
### end
45+
46+
### empty_for_body
47+
# Empty for body - bash treats as parse error, bashkit allows it
48+
### skip: TODO empty for body not rejected as parse error
49+
bash -c 'for i in 1 2 3; do
50+
done' 2>/dev/null
51+
echo status=$?
52+
### expect
53+
status=2
54+
### end
55+
56+
### empty_function_body
57+
# Empty function body - bash treats as parse error, bashkit allows it
58+
### skip: TODO empty function body not rejected as parse error
59+
bash -c 'f() { }' 2>/dev/null
60+
echo status=$?
61+
### expect
62+
status=2
63+
### end
64+
65+
### case_with_empty_clause
66+
# case with empty clauses is valid
67+
case foo in
68+
bar)
69+
;;
70+
foo)
71+
echo matched
72+
;;
73+
esac
74+
### expect
75+
matched
76+
### end
77+
78+
### case_empty_fallthrough
79+
# case with empty clause and fallthrough
80+
case x in
81+
x)
82+
;;
83+
*)
84+
echo no
85+
;;
86+
esac
87+
echo done
88+
### expect
89+
done
90+
### end

0 commit comments

Comments
 (0)