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:
69 status=2
70 status=2
71 ## END
72
73 #### ] syntax errors
74 [
75 echo status=$?
76 test # not a syntax error
77 echo status=$?
78 [ -n x # missing ]
79 echo status=$?
80 [ -n x ] y # extra arg after ]
81 echo status=$?
82 [ -n x y # extra arg
83 echo status=$?
84 ## STDOUT:
85 status=2
86 status=1
87 status=2
88 status=2
89 status=2
90 ## END
91
92 #### -n
93 test -n 'a' && echo true
94 test -n '' || echo false
95 ## stdout-json: "true\nfalse\n"
96
97 #### ! -a
98 [ -z '' -a ! -z x ]
99 echo status=$?
100 ## stdout: status=0
101
102 #### -o
103 [ -z x -o ! -z x ]
104 echo status=$?
105 ## stdout: status=0
106
107 #### ( )
108 [ -z '' -a '(' ! -z x ')' ]
109 echo status=$?
110 ## stdout: status=0
111
112 #### ( ) ! -a -o with system version of [
113 command [ --version
114 command [ -z '' -a '(' ! -z x ')' ] && echo true
115 ## stdout: true
116
117 #### == is alias for =
118 [ a = a ] && echo true
119 [ a == a ] && echo true
120 ## stdout-json: "true\ntrue\n"
121 ## BUG dash stdout-json: "true\n"
122 ## BUG dash status: 2
123
124 #### == and = does not do glob
125 [ abc = 'a*' ]
126 echo status=$?
127 [ abc == 'a*' ]
128 echo status=$?
129 ## stdout-json: "status=1\nstatus=1\n"
130 ## N-I dash stdout-json: "status=1\nstatus=2\n"
131
132 #### [ with op variable
133 # OK -- parsed AFTER evaluation of vars
134 op='='
135 [ a $op a ] && echo true
136 [ a $op b ] || echo false
137 ## status: 0
138 ## stdout-json: "true\nfalse\n"
139
140 #### [ with unquoted empty var
141 empty=''
142 [ $empty = '' ] && echo true
143 ## status: 2
144
145 #### [ compare with literal -f
146 # Hm this is the same
147 var=-f
148 [ $var = -f ] && echo true
149 [ '-f' = $var ] && echo true
150 ## stdout-json: "true\ntrue\n"
151
152 #### [ '(' foo ] is runtime syntax error
153 [ '(' foo ]
154 echo status=$?
155 ## stdout: status=2
156
157 #### -z '>' implies two token lookahead
158 [ -z ] && echo true # -z is operand
159 [ -z '>' ] || echo false # -z is operator
160 [ -z '>' -- ] && echo true # -z is operand
161 ## stdout-json: "true\nfalse\ntrue\n"
162
163 #### operator/operand ambiguity with ]
164 # bash parses this as '-z' AND ']', which is true. It's a syntax error in
165 # dash/mksh.
166 [ -z -a ] ]
167 echo status=$?
168 ## stdout: status=0
169 ## OK mksh stdout: status=2
170 ## OK dash stdout: status=2
171
172 #### operator/operand ambiguity with -a
173 # bash parses it as '-z' AND '-a'. It's a syntax error in mksh but somehow a
174 # runtime error in dash.
175 [ -z -a -a ]
176 echo status=$?
177 ## stdout: status=0
178 ## OK mksh stdout: status=2
179 ## OK dash stdout: status=1
180
181 #### -d
182 test -d $TMP
183 echo status=$?
184 test -d $TMP/__nonexistent_Z_Z__
185 echo status=$?
186 ## stdout-json: "status=0\nstatus=1\n"
187
188 #### -x
189 rm -f $TMP/x
190 echo 'echo hi' > $TMP/x
191 test -x $TMP/x || echo 'no'
192 chmod +x $TMP/x
193 test -x $TMP/x && echo 'yes'
194 test -x $TMP/__nonexistent__ || echo 'bad'
195 ## stdout-json: "no\nyes\nbad\n"
196
197 #### -r
198 echo '1' > $TMP/testr_yes
199 echo '2' > $TMP/testr_no
200 chmod -r $TMP/testr_no # remove read permission
201 test -r $TMP/testr_yes && echo 'yes'
202 test -r $TMP/testr_no || echo 'no'
203 ## stdout-json: "yes\nno\n"
204
205 #### -w
206 rm -f $TMP/testw_*
207 echo '1' > $TMP/testw_yes
208 echo '2' > $TMP/testw_no
209 chmod -w $TMP/testw_no # remove write permission
210 test -w $TMP/testw_yes && echo 'yes'
211 test -w $TMP/testw_no || echo 'no'
212 ## stdout-json: "yes\nno\n"
213
214 #### -h and -L test for symlink
215 tmp=$TMP/builtin-test-1
216 mkdir -p $tmp
217 touch $tmp/zz
218 ln -s -f $tmp/zz $tmp/symlink
219 ln -s -f $tmp/__nonexistent_ZZ__ $tmp/dangling
220 test -L $tmp/zz || echo no
221 test -h $tmp/zz || echo no
222 test -f $tmp/symlink && echo is-file
223 test -L $tmp/symlink && echo symlink
224 test -h $tmp/symlink && echo symlink
225 test -L $tmp/dangling && echo dangling
226 test -h $tmp/dangling && echo dangling
227 test -f $tmp/dangling || echo 'dangling is not file'
228 ## STDOUT:
229 no
230 no
231 is-file
232 symlink
233 symlink
234 dangling
235 dangling
236 dangling is not file
237 ## END
238
239 #### -t 1 for stdout
240 # There is no way to get a terminal in the test environment?
241 [ -t 1 ]
242 echo status=$?
243 ## stdout: status=1
244
245 #### [ -t invalid ]
246 [ -t invalid ]
247 echo status=$?
248 ## stdout: status=2
249 ## BUG bash stdout: status=1
250
251 #### -ot and -nt
252 touch -d 2017/12/31 $TMP/x
253 touch -d 2018/01/01 > $TMP/y
254 test $TMP/x -ot $TMP/y && echo 'older'
255 test $TMP/x -nt $TMP/y || echo 'not newer'
256 test $TMP/x -ot $TMP/x || echo 'not older than itself'
257 test $TMP/x -nt $TMP/x || echo 'not newer than itself'
258 ## STDOUT:
259 older
260 not newer
261 not older than itself
262 not newer than itself
263 ## END
264
265 #### [ a -eq b ]
266 [ a -eq a ]
267 echo status=$?
268 ## STDOUT:
269 status=2
270 ## END
271 ## BUG mksh STDOUT:
272 status=0
273 ## END
274
275 #### test -s
276 test -s __nonexistent
277 echo status=$?
278 touch $TMP/empty
279 test -s $TMP/empty
280 echo status=$?
281 echo nonempty > $TMP/nonempty
282 test -s $TMP/nonempty
283 echo status=$?
284 ## STDOUT:
285 status=1
286 status=1
287 status=0
288 ## END
289
290 #### test -b -c -S (block, character, socket)
291 # NOTE: we do not have the "true" case
292
293 echo -b
294 test -b nonexistent
295 echo status=$?
296 test -b testdata
297 echo status=$?
298
299 echo -c
300 test -c nonexistent
301 echo status=$?
302 test -c testdata
303 echo status=$?
304
305 echo -S
306 test -S nonexistent
307 echo status=$?
308 test -S testdata
309 echo status=$?
310
311 ## STDOUT:
312 -b
313 status=1
314 status=1
315 -c
316 status=1
317 status=1
318 -S
319 status=1
320 status=1
321 ## END
322
323
324 #### test -p named pipe
325 mkfifo $TMP/fifo
326 test -p $TMP/fifo
327 echo status=$?
328
329 test -p testdata
330 echo status=$?
331
332 ## STDOUT:
333 status=0
334 status=1
335 ## END
336
337 #### -G and -O for effective user ID and group ID
338
339 test -O bin
340 echo status=$?
341 test -O __nonexistent__
342 echo status=$?
343
344 test -G bin
345 echo status=$?
346 test -G __nonexistent__
347 echo status=$?
348
349 ## STDOUT:
350 status=0
351 status=1
352 status=0
353 status=1
354 ## END
355
356 #### test -o for options
357 # note: it's lame that the 'false' case is confused with the 'typo' case.
358 # but checking for error code 2 is unlikely anyway.
359 test -o nounset
360 echo status=$?
361
362 set -o nounset
363 echo status=$?
364
365 test -o _bad_name_
366 echo status=$?
367 ## STDOUT:
368 status=1
369 status=0
370 status=1
371 ## END
372 ## N-I dash STDOUT:
373 status=2
374 status=0
375 status=2
376 ## END
377
378 #### -nt -ot
379 [ present -nt absent ] || exit 1
380 [ absent -ot present ] || exit 2
381 ## status: 1