1 #!/usr/bin/env bash
2
3 ### zero args: [ ]
4 [ ] || echo false
5 # stdout: false
6
7 ### one arg: [ x ] where x is one of '=' '!' '(' ']'
8 [ = ]
9 echo status=$?
10 [ ] ]
11 echo status=$?
12 [ '!' ]
13 echo status=$?
14 [ '(' ]
15 echo status=$?
16 # stdout-json: "status=0\nstatus=0\nstatus=0\nstatus=0\n"
17
18 ### one arg: empty string is false. Equivalent to -n.
19 test 'a' && echo true
20 test '' || echo false
21 # stdout-json: "true\nfalse\n"
22
23 ### -a as unary operator (alias of -e)
24 # NOT IMPLEMENTED FOR OSH, but could be later. See comment in core/id_kind.py.
25 [ -a / ]
26 echo status=$?
27 [ -a /nonexistent ]
28 echo status=$?
29 # stdout-json: "status=0\nstatus=1\n"
30 # N-I dash stdout-json: "status=2\nstatus=2\n"
31
32 ### two args: -z with = ! ( ]
33 [ -z = ]
34 echo status=$?
35 [ -z ] ]
36 echo status=$?
37 [ -z '!' ]
38 echo status=$?
39 [ -z '(' ]
40 echo status=$?
41 # stdout-json: "status=1\nstatus=1\nstatus=1\nstatus=1\n"
42
43 ### three args
44 [ foo = '' ]
45 echo status=$?
46 [ foo -a '' ]
47 echo status=$?
48 [ foo -o '' ]
49 echo status=$?
50 [ ! -z foo ]
51 echo status=$?
52 [ \( foo \) ]
53 echo status=$?
54 # stdout-json: "status=1\nstatus=1\nstatus=0\nstatus=0\nstatus=0\n"
55
56 ### four args
57 [ ! foo = foo ]
58 echo status=$?
59 [ \( -z foo \) ]
60 echo status=$?
61 # stdout-json: "status=1\nstatus=1\n"
62
63 ### test with extra args is syntax error
64 test -n x ]
65 echo status=$?
66 test -n x y
67 echo status=$?
68 # stdout-json: "status=2\nstatus=2\n"
69
70 ### ] syntax errors
71 [ -n x # missing ]
72 echo status=$?
73 [ -n x ] y # extra arg after ]
74 echo status=$?
75 [ -n x y # extra arg
76 echo status=$?
77 # stdout-json: "status=2\nstatus=2\nstatus=2\n"
78
79 ### -n
80 test -n 'a' && echo true
81 test -n '' || echo false
82 # stdout-json: "true\nfalse\n"
83
84 ### ! -a
85 [ -z '' -a ! -z x ]
86 echo status=$?
87 # stdout: status=0
88
89 ### -o
90 [ -z x -o ! -z x ]
91 echo status=$?
92 # stdout: status=0
93
94 ### ( )
95 [ -z '' -a '(' ! -z x ')' ]
96 echo status=$?
97 # stdout: status=0
98
99 ### ( ) ! -a -o with system version of [
100 command [ --version
101 command [ -z '' -a '(' ! -z x ')' ] && echo true
102 # stdout: true
103
104 ### == is alias for =
105 [ a = a ] && echo true
106 [ a == a ] && echo true
107 # stdout-json: "true\ntrue\n"
108 # BUG dash stdout-json: "true\n"
109 # BUG dash status: 2
110
111 ### == and = does not do glob
112 [ abc = 'a*' ]
113 echo status=$?
114 [ abc == 'a*' ]
115 echo status=$?
116 # stdout-json: "status=1\nstatus=1\n"
117 # N-I dash stdout-json: "status=1\nstatus=2\n"
118
119 ### [ with op variable
120 # OK -- parsed AFTER evaluation of vars
121 op='='
122 [ a $op a ] && echo true
123 [ a $op b ] || echo false
124 # status: 0
125 # stdout-json: "true\nfalse\n"
126
127 ### [ with unquoted empty var
128 empty=''
129 [ $empty = '' ] && echo true
130 # status: 2
131
132 ### [ compare with literal -f
133 # Hm this is the same
134 var=-f
135 [ $var = -f ] && echo true
136 [ '-f' = $var ] && echo true
137 # stdout-json: "true\ntrue\n"
138
139 ### [ '(' foo ] is runtime syntax error
140 [ '(' foo ]
141 echo status=$?
142 # stdout: status=2
143
144 ### -z '>' implies two token lookahead
145 [ -z ] && echo true # -z is operand
146 [ -z '>' ] || echo false # -z is operator
147 [ -z '>' -- ] && echo true # -z is operand
148 # stdout-json: "true\nfalse\ntrue\n"
149
150 ### operator/operand ambiguity with ]
151 # bash parses this as '-z' AND ']', which is true. It's a syntax error in
152 # dash/mksh.
153 [ -z -a ] ]
154 echo status=$?
155 # stdout: status=0
156 # OK mksh stdout: status=2
157 # OK dash stdout: status=2
158
159 ### operator/operand ambiguity with -a
160 # bash parses it as '-z' AND '-a'. It's a syntax error in mksh but somehow a
161 # runtime error in dash.
162 [ -z -a -a ]
163 echo status=$?
164 # stdout: status=0
165 # OK mksh stdout: status=2
166 # OK dash stdout: status=1
167
168 ### -d
169 test -d $TMP
170 echo status=$?
171 test -d $TMP/__nonexistent_Z_Z__
172 echo status=$?
173 # stdout-json: "status=0\nstatus=1\n"
174
175 ### -x
176 rm -f $TMP/x
177 echo 'echo hi' > $TMP/x
178 test -x $TMP/x || echo 'no'
179 chmod +x $TMP/x
180 test -x $TMP/x && echo 'yes'
181 test -x $TMP/__nonexistent__ || echo 'bad'
182 # stdout-json: "no\nyes\nbad\n"
183
184 ### -r
185 echo '1' > $TMP/testr_yes
186 echo '2' > $TMP/testr_no
187 chmod -r $TMP/testr_no # remove read permission
188 test -r $TMP/testr_yes && echo 'yes'
189 test -r $TMP/testr_no || echo 'no'
190 # stdout-json: "yes\nno\n"
191
192 ### -w
193 rm -f $TMP/testw_*
194 echo '1' > $TMP/testw_yes
195 echo '2' > $TMP/testw_no
196 chmod -w $TMP/testw_no # remove write permission
197 test -w $TMP/testw_yes && echo 'yes'
198 test -w $TMP/testw_no || echo 'no'
199 # stdout-json: "yes\nno\n"
200
201 ### -h and -L test for symlink
202 touch $TMP/zz
203 ln -s -f $TMP/zz $TMP/symlink
204 ln -s -f $TMP/__nonexistent_ZZ__ $TMP/dangling
205 test -L $TMP/zz || echo no
206 test -h $TMP/zz || echo no
207 test -f $TMP/symlink && echo is-file
208 test -L $TMP/symlink && echo symlink
209 test -h $TMP/symlink && echo symlink
210 test -L $TMP/dangling && echo dangling
211 test -h $TMP/dangling && echo dangling
212 test -f $TMP/dangling || echo 'dangling is not file'
213 ## STDOUT:
214 no
215 no
216 is-file
217 symlink
218 symlink
219 dangling
220 dangling
221 dangling is not file
222 ## END
223
224 ### -t 1 for stdout
225 # There isn't way to get a terminal in the test environment?
226 [ -t 1 ]
227 echo status=$?
228 ## stdout: status=1
229
230 ### [ -t invalid ]
231 [ -t invalid ]
232 echo status=$?
233 ## stdout: status=2
234 ## BUG bash stdout: status=1
235
236 ### -ot and -nt
237 touch -d 2017/12/31 $TMP/x
238 touch -d 2018/01/01 > $TMP/y
239 test $TMP/x -ot $TMP/y && echo 'older'
240 test $TMP/x -nt $TMP/y || echo 'not newer'
241 test $TMP/x -ot $TMP/x || echo 'not older than itself'
242 test $TMP/x -nt $TMP/x || echo 'not newer than itself'
243 ## STDOUT:
244 older
245 not newer
246 not older than itself
247 not newer than itself
248 ## END