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