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:
17 status=0
18 status=0
19 status=0
20 status=0
21 ## END
22
23 #### one arg: empty string is false. Equivalent to -n.
24 test 'a' && echo true
25 test '' || echo false
26 ## STDOUT:
27 true
28 false
29 ## END
30
31 #### -a as unary operator (alias of -e)
32 # NOT IMPLEMENTED FOR OSH, but could be later. See comment in core/id_kind.py.
33 [ -a / ]
34 echo status=$?
35 [ -a /nonexistent ]
36 echo status=$?
37 ## STDOUT:
38 status=0
39 status=1
40 ## END
41 ## N-I dash STDOUT:
42 status=2
43 status=2
44 ## END
45
46 #### two args: -z with = ! ( ]
47 [ -z = ]
48 echo status=$?
49 [ -z ] ]
50 echo status=$?
51 [ -z '!' ]
52 echo status=$?
53 [ -z '(' ]
54 echo status=$?
55 ## STDOUT:
56 status=1
57 status=1
58 status=1
59 status=1
60 ## END
61
62 #### three args
63 [ foo = '' ]
64 echo status=$?
65 [ foo -a '' ]
66 echo status=$?
67 [ foo -o '' ]
68 echo status=$?
69 [ ! -z foo ]
70 echo status=$?
71 [ \( foo \) ]
72 echo status=$?
73 ## STDOUT:
74 status=1
75 status=1
76 status=0
77 status=0
78 status=0
79 ## END
80
81 #### four args
82 [ ! foo = foo ]
83 echo status=$?
84 [ \( -z foo \) ]
85 echo status=$?
86 ## STDOUT:
87 status=1
88 status=1
89 ## END
90
91 #### test with extra args is syntax error
92 test -n x ]
93 echo status=$?
94 test -n x y
95 echo status=$?
96 ## STDOUT:
97 status=2
98 status=2
99 ## END
100
101 #### ] syntax errors
102 [
103 echo status=$?
104 test # not a syntax error
105 echo status=$?
106 [ -n x # missing ]
107 echo status=$?
108 [ -n x ] y # extra arg after ]
109 echo status=$?
110 [ -n x y # extra arg
111 echo status=$?
112 ## STDOUT:
113 status=2
114 status=1
115 status=2
116 status=2
117 status=2
118 ## END
119
120 #### -n
121 test -n 'a' && echo true
122 test -n '' || echo false
123 ## STDOUT:
124 true
125 false
126 ## END
127
128 #### ! -a
129 [ -z '' -a ! -z x ]
130 echo status=$?
131 ## stdout: status=0
132
133 #### -o
134 [ -z x -o ! -z x ]
135 echo status=$?
136 ## stdout: status=0
137
138 #### ( )
139 [ -z '' -a '(' ! -z x ')' ]
140 echo status=$?
141 ## stdout: status=0
142
143 #### ( ) ! -a -o with system version of [
144 command [ --version
145 command [ -z '' -a '(' ! -z x ')' ] && echo true
146 ## stdout: true
147
148 #### == is alias for =
149 [ a = a ] && echo true
150 [ a == a ] && echo true
151 ## STDOUT:
152 true
153 true
154 ## END
155 ## BUG dash STDOUT:
156 true
157 ## END
158 ## BUG dash status: 2
159
160 #### == and = does not do glob
161 [ abc = 'a*' ]
162 echo status=$?
163 [ abc == 'a*' ]
164 echo status=$?
165 ## STDOUT:
166 status=1
167 status=1
168 ## END
169 ## N-I dash STDOUT:
170 status=1
171 status=2
172 ## END
173
174 #### [ with op variable
175 # OK -- parsed AFTER evaluation of vars
176 op='='
177 [ a $op a ] && echo true
178 [ a $op b ] || echo false
179 ## status: 0
180 ## STDOUT:
181 true
182 false
183 ## END
184
185 #### [ with unquoted empty var
186 empty=''
187 [ $empty = '' ] && echo true
188 ## status: 2
189
190 #### [ compare with literal -f
191 # Hm this is the same
192 var=-f
193 [ $var = -f ] && echo true
194 [ '-f' = $var ] && echo true
195 ## STDOUT:
196 true
197 true
198 ## END
199
200 #### [ '(' foo ] is runtime syntax error
201 [ '(' foo ]
202 echo status=$?
203 ## stdout: status=2
204
205 #### -z '>' implies two token lookahead
206 [ -z ] && echo true # -z is operand
207 [ -z '>' ] || echo false # -z is operator
208 [ -z '>' -- ] && echo true # -z is operand
209 ## STDOUT:
210 true
211 false
212 true
213 ## END
214
215 #### operator/operand ambiguity with ]
216 # bash parses this as '-z' AND ']', which is true. It's a syntax error in
217 # dash/mksh.
218 [ -z -a ] ]
219 echo status=$?
220 ## stdout: status=0
221 ## OK mksh stdout: status=2
222 ## OK dash stdout: status=2
223
224 #### operator/operand ambiguity with -a
225 # bash parses it as '-z' AND '-a'. It's a syntax error in mksh but somehow a
226 # runtime error in dash.
227 [ -z -a -a ]
228 echo status=$?
229 ## stdout: status=0
230 ## OK mksh stdout: status=2
231 ## OK dash stdout: status=1
232
233 #### -d
234 test -d $TMP
235 echo status=$?
236 test -d $TMP/__nonexistent_Z_Z__
237 echo status=$?
238 ## STDOUT:
239 status=0
240 status=1
241 ## END
242
243 #### -x
244 rm -f $TMP/x
245 echo 'echo hi' > $TMP/x
246 test -x $TMP/x || echo 'no'
247 chmod +x $TMP/x
248 test -x $TMP/x && echo 'yes'
249 test -x $TMP/__nonexistent__ || echo 'bad'
250 ## STDOUT:
251 no
252 yes
253 bad
254 ## END
255
256 #### -r
257 echo '1' > $TMP/testr_yes
258 echo '2' > $TMP/testr_no
259 chmod -r $TMP/testr_no # remove read permission
260 test -r $TMP/testr_yes && echo 'yes'
261 test -r $TMP/testr_no || echo 'no'
262 ## STDOUT:
263 yes
264 no
265 ## END
266
267 #### -w
268 rm -f $TMP/testw_*
269 echo '1' > $TMP/testw_yes
270 echo '2' > $TMP/testw_no
271 chmod -w $TMP/testw_no # remove write permission
272 test -w $TMP/testw_yes && echo 'yes'
273 test -w $TMP/testw_no || echo 'no'
274 ## STDOUT:
275 yes
276 no
277 ## END
278
279 #### -k for sticky bit
280 # not isolated: /tmp usually has sticky bit on
281 # https://en.wikipedia.org/wiki/Sticky_bit
282
283 test -k /tmp
284 echo status=$?
285
286 test -k /bin
287 echo status=$?
288 ## STDOUT:
289 status=0
290 status=1
291 ## END
292
293 #### -h and -L test for symlink
294 tmp=$TMP/builtin-test-1
295 mkdir -p $tmp
296 touch $tmp/zz
297 ln -s -f $tmp/zz $tmp/symlink
298 ln -s -f $tmp/__nonexistent_ZZ__ $tmp/dangling
299 test -L $tmp/zz || echo no
300 test -h $tmp/zz || echo no
301 test -f $tmp/symlink && echo is-file
302 test -L $tmp/symlink && echo symlink
303 test -h $tmp/symlink && echo symlink
304 test -L $tmp/dangling && echo dangling
305 test -h $tmp/dangling && echo dangling
306 test -f $tmp/dangling || echo 'dangling is not file'
307 ## STDOUT:
308 no
309 no
310 is-file
311 symlink
312 symlink
313 dangling
314 dangling
315 dangling is not file
316 ## END
317
318 #### -t 1 for stdout
319 # There is no way to get a terminal in the test environment?
320 [ -t 1 ]
321 echo status=$?
322 ## stdout: status=1
323
324 #### [ -t invalid ]
325 [ -t invalid ]
326 echo status=$?
327 ## stdout: status=2
328 ## BUG bash stdout: status=1
329
330 #### -ot and -nt
331 touch -d 2017/12/31 $TMP/x
332 touch -d 2018/01/01 > $TMP/y
333 test $TMP/x -ot $TMP/y && echo 'older'
334 test $TMP/x -nt $TMP/y || echo 'not newer'
335 test $TMP/x -ot $TMP/x || echo 'not older than itself'
336 test $TMP/x -nt $TMP/x || echo 'not newer than itself'
337 ## STDOUT:
338 older
339 not newer
340 not older than itself
341 not newer than itself
342 ## END
343
344 #### [ a -eq b ]
345 [ a -eq a ]
346 echo status=$?
347 ## STDOUT:
348 status=2
349 ## END
350 ## BUG mksh STDOUT:
351 status=0
352 ## END
353
354 #### test -s
355 test -s __nonexistent
356 echo status=$?
357 touch $TMP/empty
358 test -s $TMP/empty
359 echo status=$?
360 echo nonempty > $TMP/nonempty
361 test -s $TMP/nonempty
362 echo status=$?
363 ## STDOUT:
364 status=1
365 status=1
366 status=0
367 ## END
368
369 #### test -b -c -S (block, character, socket)
370 # NOTE: we do not have the "true" case
371
372 echo -b
373 test -b nonexistent
374 echo status=$?
375 test -b testdata
376 echo status=$?
377
378 echo -c
379 test -c nonexistent
380 echo status=$?
381 test -c testdata
382 echo status=$?
383
384 echo -S
385 test -S nonexistent
386 echo status=$?
387 test -S testdata
388 echo status=$?
389
390 ## STDOUT:
391 -b
392 status=1
393 status=1
394 -c
395 status=1
396 status=1
397 -S
398 status=1
399 status=1
400 ## END
401
402
403 #### test -p named pipe
404 mkfifo $TMP/fifo
405 test -p $TMP/fifo
406 echo status=$?
407
408 test -p testdata
409 echo status=$?
410
411 ## STDOUT:
412 status=0
413 status=1
414 ## END
415
416 #### -G and -O for effective user ID and group ID
417
418 test -O bin
419 echo status=$?
420 test -O __nonexistent__
421 echo status=$?
422
423 test -G bin
424 echo status=$?
425 test -G __nonexistent__
426 echo status=$?
427
428 ## STDOUT:
429 status=0
430 status=1
431 status=0
432 status=1
433 ## END
434
435 #### -u for setuid, -g too
436
437 # This test is not hermetic
438
439 test -u /tmp
440 echo status=$?
441
442 test -u $(which sudo)
443 echo status=$?
444
445 test -g /tmp
446 echo status=$?
447
448 test -g $(which sudo)
449 echo status=$?
450
451 ## STDOUT:
452 status=1
453 status=0
454 status=1
455 status=1
456 ## END
457
458 #### -v to test variable
459 test -v nonexistent
460 echo global=$?
461
462 g=1
463 test -v g
464 echo global=$?
465
466 f() {
467 local f_var=0
468 g
469 }
470
471 g() {
472 test -v f_var
473 echo dynamic=$?
474 test -v g
475 echo dynamic=$?
476 test -v nonexistent
477 echo dynamic=$?
478 }
479 f
480
481 ## STDOUT:
482 global=1
483 global=0
484 dynamic=0
485 dynamic=0
486 dynamic=1
487 ## END
488 ## N-I dash/mksh STDOUT:
489 global=2
490 global=2
491 dynamic=2
492 dynamic=2
493 dynamic=2
494 ## END
495
496
497 #### test -o for options
498 # note: it's lame that the 'false' case is confused with the 'typo' case.
499 # but checking for error code 2 is unlikely anyway.
500 test -o nounset
501 echo status=$?
502
503 set -o nounset
504 test -o nounset
505 echo status=$?
506
507 test -o _bad_name_
508 echo status=$?
509 ## STDOUT:
510 status=1
511 status=0
512 status=1
513 ## END
514 ## N-I dash STDOUT:
515 status=2
516 status=2
517 status=2
518 ## END
519
520 #### -nt -ot
521 [ present -nt absent ] || exit 1
522 [ absent -ot present ] || exit 2
523 ## status: 1
524
525 #### -ef
526 left=$TMP/left
527 right=$TMP/right
528 touch $left $right
529
530 ln -f $TMP/left $TMP/hardlink
531
532 test $left -ef $left && echo same
533 test $left -ef $TMP/hardlink && echo same
534 test $left -ef $right || echo different
535
536 test $TMP/__nonexistent -ef $right || echo different
537
538 ## STDOUT:
539 same
540 same
541 different
542 different
543 ## END
544
545 #### Overflow error
546 test -t 12345678910
547 echo status=$?
548 ## STDOUT:
549 status=2
550 ## END
551 ## OK dash/bash STDOUT:
552 status=1
553 ## END
554