1 ## oils_failures_allowed: 0
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 test -b /
379 echo status=$?
380
381 echo -c
382 test -c nonexistent
383 echo status=$?
384 test -c testdata
385 echo status=$?
386
387 echo -S
388 test -S nonexistent
389 echo status=$?
390 test -S testdata
391 echo status=$?
392
393 ## STDOUT:
394 -b
395 status=1
396 status=1
397 status=1
398 -c
399 status=1
400 status=1
401 -S
402 status=1
403 status=1
404 ## END
405
406
407 #### test -p named pipe
408 mkfifo $TMP/fifo
409 test -p $TMP/fifo
410 echo status=$?
411
412 test -p testdata
413 echo status=$?
414
415 ## STDOUT:
416 status=0
417 status=1
418 ## END
419
420 #### -G and -O for effective user ID and group ID
421
422 mkdir -p $TMP/bin
423
424 test -O $TMP/bin
425 echo status=$?
426 test -O __nonexistent__
427 echo status=$?
428
429 test -G $TMP/bin
430 echo status=$?
431 test -G __nonexistent__
432 echo status=$?
433
434 ## STDOUT:
435 status=0
436 status=1
437 status=0
438 status=1
439 ## END
440
441 #### -u for setuid, -g too
442
443 touch $TMP/setuid $TMP/setgid
444 chmod u+s $TMP/setuid
445 chmod g+s $TMP/setgid
446
447 test -u $TMP/setuid
448 echo status=$?
449
450 test -u $TMP/setgid
451 echo status=$?
452
453 test -g $TMP/setuid
454 echo status=$?
455
456 test -g $TMP/setgid
457 echo status=$?
458
459
460 ## STDOUT:
461 status=0
462 status=1
463 status=1
464 status=0
465 ## END
466
467 #### -v to test variable (bash)
468 test -v nonexistent
469 echo global=$?
470
471 g=1
472 test -v g
473 echo global=$?
474
475 f() {
476 local f_var=0
477 g
478 }
479
480 g() {
481 test -v f_var
482 echo dynamic=$?
483 test -v g
484 echo dynamic=$?
485 test -v nonexistent
486 echo dynamic=$?
487 }
488 f
489
490 ## STDOUT:
491 global=1
492 global=0
493 dynamic=0
494 dynamic=0
495 dynamic=1
496 ## END
497 ## N-I dash/mksh STDOUT:
498 global=2
499 global=2
500 dynamic=2
501 dynamic=2
502 dynamic=2
503 ## END
504
505
506 #### test -o for options
507 # note: it's lame that the 'false' case is confused with the 'typo' case.
508 # but checking for error code 2 is unlikely anyway.
509 test -o nounset
510 echo status=$?
511
512 set -o nounset
513 test -o nounset
514 echo status=$?
515
516 test -o _bad_name_
517 echo status=$?
518 ## STDOUT:
519 status=1
520 status=0
521 status=1
522 ## END
523 ## N-I dash STDOUT:
524 status=2
525 status=2
526 status=2
527 ## END
528
529 #### -nt -ot
530 [ present -nt absent ] || exit 1
531 [ absent -ot present ] || exit 2
532 ## status: 1
533
534 #### -ef
535 left=$TMP/left
536 right=$TMP/right
537 touch $left $right
538
539 ln -f $TMP/left $TMP/hardlink
540
541 test $left -ef $left && echo same
542 test $left -ef $TMP/hardlink && echo same
543 test $left -ef $right || echo different
544
545 test $TMP/__nonexistent -ef $right || echo different
546
547 ## STDOUT:
548 same
549 same
550 different
551 different
552 ## END
553
554 #### Overflow error
555 test -t 12345678910
556 echo status=$?
557 ## STDOUT:
558 status=2
559 ## END
560 ## OK dash/bash STDOUT:
561 status=1
562 ## END
563
564 #### Bug regression
565 test "$ipv6" = "yes" -a "$ipv6lib" != "none"
566 echo status=$?
567 ## STDOUT:
568 status=1
569 ## END
570
571
572 #### test -c
573 test -c /dev/zero
574 echo status=$?
575 ## STDOUT:
576 status=0
577 ## END
578
579 #### test -S
580 test -S /dev/zero
581 echo status=$?
582 ## STDOUT:
583 status=1
584 ## END
585
586 #### bug from pnut: negative number $((-1))
587
588 # https://lobste.rs/s/lplim1/design_self_compiling_c_transpiler#c_km2ywc
589
590 [ $((-42)) -le 0 ]
591 echo status=$?
592
593 [ $((-1)) -le 0 ]
594 echo status=$?
595
596 echo
597
598 [ -1 -le 0 ]
599 echo status=$?
600
601 [ -42 -le 0 ]
602 echo status=$?
603
604 echo
605
606 test -1 -le 0
607 echo status=$?
608
609 test -42 -le 0
610 echo status=$?
611
612 ## STDOUT:
613 status=0
614 status=0
615
616 status=0
617 status=0
618
619 status=0
620 status=0
621 ## END
622
623 #### negative octal numbers, etc.
624
625 # zero
626 [ -0 -eq 0 ]
627 echo zero=$?
628
629 # octal numbers can be negative
630 [ -0123 -eq -83 ]
631 echo octal=$?
632
633 # hex doesn't have negative numbers?
634 [ -0xff -eq -255 ]
635 echo hex=$?
636
637 # base N doesn't either
638 [ -64#a -eq -10 ]
639 echo baseN=$?
640
641 ## STDOUT:
642 zero=0
643 octal=1
644 hex=2
645 baseN=2
646 ## END
647
648 #### More negative numbers
649 case $SH in dash) exit ;; esac
650
651 [[ -1 -le 0 ]]
652 echo status=$?
653
654 [[ $((-1)) -le 0 ]]
655 echo status=$?
656
657 ## STDOUT:
658 status=0
659 status=0
660 ## END
661
662 ## N-I dash STDOUT:
663 ## END
664
665 #### No octal, hex, base N conversion - leading 0 is a regular decimal
666
667 # arithmetic has octal conversion
668 echo $(( 073 ))
669 echo $(( -073 ))
670
671 echo
672
673 # Bracket does NOT have octal conversion! That is annoying.
674 [ 073 -eq 73 ]
675 echo status=$?
676
677 [ -073 -eq -73 ]
678 echo status=$?
679
680 echo
681
682 [ 0xff -eq 255 ]
683 echo hex=$?
684 [ 64#a -eq 10 ]
685 echo baseN=$?
686
687 ## STDOUT:
688 59
689 -59
690
691 status=0
692 status=0
693
694 hex=2
695 baseN=2
696 ## END
697
698 ## BUG mksh STDOUT:
699 73
700 -73
701
702 status=0
703 status=0
704
705 hex=2
706 baseN=2
707 ## END
708
709 #### Looks like octal, but digit is too big
710
711 # arithmetic has octal conversion
712 echo $(( 083 ))
713 echo status=$?
714
715 echo $(( -083 ))
716 echo status=$?
717
718 echo
719
720 # Bracket does NOT have octal conversion! That is annoying.
721 [ 083 -eq 83 ]
722 echo status=$?
723
724 [ -083 -eq -83 ]
725 echo status=$?
726
727 ## status: 1
728 ## STDOUT:
729 ## END
730
731 ## OK dash status: 2
732
733 ## OK bash status: 0
734 ## OK bash STDOUT:
735 status=1
736 status=1
737
738 status=0
739 status=0
740 ## END
741
742 ## OK mksh status: 0
743 ## OK mksh STDOUT:
744 83
745 status=0
746 -83
747 status=0
748
749 status=0
750 status=0
751 ## END
752
753 #### no recursive arith [ 1+2 -eq 3 ]
754
755 [ 1+2 -eq 3 ]
756 echo status=$?
757
758 s='1+2'
759 [ "$s" -eq 3 ]
760 echo status=$?
761
762 ## STDOUT:
763 status=2
764 status=2
765 ## END
766
767 ## BUG mksh STDOUT:
768 status=0
769 status=0
770 ## END