OILS / spec / builtin-bracket.test.sh View on Github | oilshell.org

767 lines, 432 significant
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[ = ]
10echo status=$?
11[ ] ]
12echo status=$?
13[ '!' ]
14echo status=$?
15[ '(' ]
16echo status=$?
17## STDOUT:
18status=0
19status=0
20status=0
21status=0
22## END
23
24#### one arg: empty string is false. Equivalent to -n.
25test 'a' && echo true
26test '' || echo false
27## STDOUT:
28true
29false
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 / ]
35echo status=$?
36[ -a /nonexistent ]
37echo status=$?
38## STDOUT:
39status=0
40status=1
41## END
42## N-I dash STDOUT:
43status=2
44status=2
45## END
46
47#### two args: -z with = ! ( ]
48[ -z = ]
49echo status=$?
50[ -z ] ]
51echo status=$?
52[ -z '!' ]
53echo status=$?
54[ -z '(' ]
55echo status=$?
56## STDOUT:
57status=1
58status=1
59status=1
60status=1
61## END
62
63#### three args
64[ foo = '' ]
65echo status=$?
66[ foo -a '' ]
67echo status=$?
68[ foo -o '' ]
69echo status=$?
70[ ! -z foo ]
71echo status=$?
72[ \( foo \) ]
73echo status=$?
74## STDOUT:
75status=1
76status=1
77status=0
78status=0
79status=0
80## END
81
82#### four args
83[ ! foo = foo ]
84echo status=$?
85[ \( -z foo \) ]
86echo status=$?
87## STDOUT:
88status=1
89status=1
90## END
91
92#### test with extra args is syntax error
93test -n x ]
94echo status=$?
95test -n x y
96echo status=$?
97## STDOUT:
98status=2
99status=2
100## END
101
102#### ] syntax errors
103[
104echo status=$?
105test # not a syntax error
106echo status=$?
107[ -n x # missing ]
108echo status=$?
109[ -n x ] y # extra arg after ]
110echo status=$?
111[ -n x y # extra arg
112echo status=$?
113## STDOUT:
114status=2
115status=1
116status=2
117status=2
118status=2
119## END
120
121#### -n
122test -n 'a' && echo true
123test -n '' || echo false
124## STDOUT:
125true
126false
127## END
128
129#### ! -a
130[ -z '' -a ! -z x ]
131echo status=$?
132## stdout: status=0
133
134#### -o
135[ -z x -o ! -z x ]
136echo status=$?
137## stdout: status=0
138
139#### ( )
140[ -z '' -a '(' ! -z x ')' ]
141echo status=$?
142## stdout: status=0
143
144#### ( ) ! -a -o with system version of [
145command [ --version
146command [ -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:
153true
154true
155## END
156## BUG dash STDOUT:
157true
158## END
159## BUG dash status: 2
160
161#### == and = does not do glob
162[ abc = 'a*' ]
163echo status=$?
164[ abc == 'a*' ]
165echo status=$?
166## STDOUT:
167status=1
168status=1
169## END
170## N-I dash STDOUT:
171status=1
172status=2
173## END
174
175#### [ with op variable
176# OK -- parsed AFTER evaluation of vars
177op='='
178[ a $op a ] && echo true
179[ a $op b ] || echo false
180## status: 0
181## STDOUT:
182true
183false
184## END
185
186#### [ with unquoted empty var
187empty=''
188[ $empty = '' ] && echo true
189## status: 2
190
191#### [ compare with literal -f
192# Hm this is the same
193var=-f
194[ $var = -f ] && echo true
195[ '-f' = $var ] && echo true
196## STDOUT:
197true
198true
199## END
200
201#### [ '(' foo ] is runtime syntax error
202[ '(' foo ]
203echo 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:
211true
212false
213true
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 ] ]
220echo 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 ]
229echo status=$?
230## stdout: status=0
231## OK mksh stdout: status=2
232## OK dash stdout: status=1
233
234#### -d
235test -d $TMP
236echo status=$?
237test -d $TMP/__nonexistent_Z_Z__
238echo status=$?
239## STDOUT:
240status=0
241status=1
242## END
243
244#### -x
245rm -f $TMP/x
246echo 'echo hi' > $TMP/x
247test -x $TMP/x || echo 'no'
248chmod +x $TMP/x
249test -x $TMP/x && echo 'yes'
250test -x $TMP/__nonexistent__ || echo 'bad'
251## STDOUT:
252no
253yes
254bad
255## END
256
257#### -r
258echo '1' > $TMP/testr_yes
259echo '2' > $TMP/testr_no
260chmod -r $TMP/testr_no # remove read permission
261test -r $TMP/testr_yes && echo 'yes'
262test -r $TMP/testr_no || echo 'no'
263## STDOUT:
264yes
265no
266## END
267
268#### -w
269rm -f $TMP/testw_*
270echo '1' > $TMP/testw_yes
271echo '2' > $TMP/testw_no
272chmod -w $TMP/testw_no # remove write permission
273test -w $TMP/testw_yes && echo 'yes'
274test -w $TMP/testw_no || echo 'no'
275## STDOUT:
276yes
277no
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
284test -k /tmp
285echo status=$?
286
287test -k /bin
288echo status=$?
289## STDOUT:
290status=0
291status=1
292## END
293
294#### -h and -L test for symlink
295tmp=$TMP/builtin-test-1
296mkdir -p $tmp
297touch $tmp/zz
298ln -s -f $tmp/zz $tmp/symlink
299ln -s -f $tmp/__nonexistent_ZZ__ $tmp/dangling
300test -L $tmp/zz || echo no
301test -h $tmp/zz || echo no
302test -f $tmp/symlink && echo is-file
303test -L $tmp/symlink && echo symlink
304test -h $tmp/symlink && echo symlink
305test -L $tmp/dangling && echo dangling
306test -h $tmp/dangling && echo dangling
307test -f $tmp/dangling || echo 'dangling is not file'
308## STDOUT:
309no
310no
311is-file
312symlink
313symlink
314dangling
315dangling
316dangling 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 ]
322echo status=$?
323## stdout: status=1
324
325#### [ -t invalid ]
326[ -t invalid ]
327echo status=$?
328## stdout: status=2
329## BUG bash stdout: status=1
330
331#### -ot and -nt
332touch -d 2017/12/31 $TMP/x
333touch -d 2018/01/01 > $TMP/y
334test $TMP/x -ot $TMP/y && echo 'older'
335test $TMP/x -nt $TMP/y || echo 'not newer'
336test $TMP/x -ot $TMP/x || echo 'not older than itself'
337test $TMP/x -nt $TMP/x || echo 'not newer than itself'
338## STDOUT:
339older
340not newer
341not older than itself
342not newer than itself
343## END
344
345#### [ a -eq b ]
346[ a -eq a ]
347echo status=$?
348## STDOUT:
349status=2
350## END
351## BUG mksh STDOUT:
352status=0
353## END
354
355#### test -s
356test -s __nonexistent
357echo status=$?
358touch $TMP/empty
359test -s $TMP/empty
360echo status=$?
361echo nonempty > $TMP/nonempty
362test -s $TMP/nonempty
363echo status=$?
364## STDOUT:
365status=1
366status=1
367status=0
368## END
369
370#### test -b -c -S (block, character, socket)
371# NOTE: we do not have the "true" case
372
373echo -b
374test -b nonexistent
375echo status=$?
376test -b testdata
377echo status=$?
378
379echo -c
380test -c nonexistent
381echo status=$?
382test -c testdata
383echo status=$?
384
385echo -S
386test -S nonexistent
387echo status=$?
388test -S testdata
389echo status=$?
390
391## STDOUT:
392-b
393status=1
394status=1
395-c
396status=1
397status=1
398-S
399status=1
400status=1
401## END
402
403
404#### test -p named pipe
405mkfifo $TMP/fifo
406test -p $TMP/fifo
407echo status=$?
408
409test -p testdata
410echo status=$?
411
412## STDOUT:
413status=0
414status=1
415## END
416
417#### -G and -O for effective user ID and group ID
418
419mkdir -p $TMP/bin
420
421test -O $TMP/bin
422echo status=$?
423test -O __nonexistent__
424echo status=$?
425
426test -G $TMP/bin
427echo status=$?
428test -G __nonexistent__
429echo status=$?
430
431## STDOUT:
432status=0
433status=1
434status=0
435status=1
436## END
437
438#### -u for setuid, -g too
439
440touch $TMP/setuid $TMP/setgid
441chmod u+s $TMP/setuid
442chmod g+s $TMP/setgid
443
444test -u $TMP/setuid
445echo status=$?
446
447test -u $TMP/setgid
448echo status=$?
449
450test -g $TMP/setuid
451echo status=$?
452
453test -g $TMP/setgid
454echo status=$?
455
456
457## STDOUT:
458status=0
459status=1
460status=1
461status=0
462## END
463
464#### -v to test variable (bash)
465test -v nonexistent
466echo global=$?
467
468g=1
469test -v g
470echo global=$?
471
472f() {
473 local f_var=0
474 g
475}
476
477g() {
478 test -v f_var
479 echo dynamic=$?
480 test -v g
481 echo dynamic=$?
482 test -v nonexistent
483 echo dynamic=$?
484}
485f
486
487## STDOUT:
488global=1
489global=0
490dynamic=0
491dynamic=0
492dynamic=1
493## END
494## N-I dash/mksh STDOUT:
495global=2
496global=2
497dynamic=2
498dynamic=2
499dynamic=2
500## END
501
502
503#### test -o for options
504# note: it's lame that the 'false' case is confused with the 'typo' case.
505# but checking for error code 2 is unlikely anyway.
506test -o nounset
507echo status=$?
508
509set -o nounset
510test -o nounset
511echo status=$?
512
513test -o _bad_name_
514echo status=$?
515## STDOUT:
516status=1
517status=0
518status=1
519## END
520## N-I dash STDOUT:
521status=2
522status=2
523status=2
524## END
525
526#### -nt -ot
527[ present -nt absent ] || exit 1
528[ absent -ot present ] || exit 2
529## status: 1
530
531#### -ef
532left=$TMP/left
533right=$TMP/right
534touch $left $right
535
536ln -f $TMP/left $TMP/hardlink
537
538test $left -ef $left && echo same
539test $left -ef $TMP/hardlink && echo same
540test $left -ef $right || echo different
541
542test $TMP/__nonexistent -ef $right || echo different
543
544## STDOUT:
545same
546same
547different
548different
549## END
550
551#### Overflow error
552test -t 12345678910
553echo status=$?
554## STDOUT:
555status=2
556## END
557## OK dash/bash STDOUT:
558status=1
559## END
560
561#### Bug regression
562test "$ipv6" = "yes" -a "$ipv6lib" != "none"
563echo status=$?
564## STDOUT:
565status=1
566## END
567
568
569#### test -c
570test -c /dev/zero
571echo status=$?
572## STDOUT:
573status=0
574## END
575
576#### test -S
577test -S /dev/zero
578echo status=$?
579## STDOUT:
580status=1
581## END
582
583#### bug from pnut: negative number $((-1))
584
585# https://lobste.rs/s/lplim1/design_self_compiling_c_transpiler#c_km2ywc
586
587[ $((-42)) -le 0 ]
588echo status=$?
589
590[ $((-1)) -le 0 ]
591echo status=$?
592
593echo
594
595[ -1 -le 0 ]
596echo status=$?
597
598[ -42 -le 0 ]
599echo status=$?
600
601echo
602
603test -1 -le 0
604echo status=$?
605
606test -42 -le 0
607echo status=$?
608
609## STDOUT:
610status=0
611status=0
612
613status=0
614status=0
615
616status=0
617status=0
618## END
619
620#### negative octal numbers, etc.
621
622# zero
623[ -0 -eq 0 ]
624echo zero=$?
625
626# octal numbers can be negative
627[ -0123 -eq -83 ]
628echo octal=$?
629
630# hex doesn't have negative numbers?
631[ -0xff -eq -255 ]
632echo hex=$?
633
634# base N doesn't either
635[ -64#a -eq -10 ]
636echo baseN=$?
637
638## STDOUT:
639zero=0
640octal=1
641hex=2
642baseN=2
643## END
644
645#### More negative numbers
646case $SH in dash) exit ;; esac
647
648[[ -1 -le 0 ]]
649echo status=$?
650
651[[ $((-1)) -le 0 ]]
652echo status=$?
653
654## STDOUT:
655status=0
656status=0
657## END
658
659## N-I dash STDOUT:
660## END
661
662#### No octal, hex, base N conversion - leading 0 is a regular decimal
663
664# arithmetic has octal conversion
665echo $(( 073 ))
666echo $(( -073 ))
667
668echo
669
670# Bracket does NOT have octal conversion! That is annoying.
671[ 073 -eq 73 ]
672echo status=$?
673
674[ -073 -eq -73 ]
675echo status=$?
676
677echo
678
679[ 0xff -eq 255 ]
680echo hex=$?
681[ 64#a -eq 10 ]
682echo baseN=$?
683
684## STDOUT:
68559
686-59
687
688status=0
689status=0
690
691hex=2
692baseN=2
693## END
694
695## BUG mksh STDOUT:
69673
697-73
698
699status=0
700status=0
701
702hex=2
703baseN=2
704## END
705
706#### Looks like octal, but digit is too big
707
708# arithmetic has octal conversion
709echo $(( 083 ))
710echo status=$?
711
712echo $(( -083 ))
713echo status=$?
714
715echo
716
717# Bracket does NOT have octal conversion! That is annoying.
718[ 083 -eq 83 ]
719echo status=$?
720
721[ -083 -eq -83 ]
722echo status=$?
723
724## status: 1
725## STDOUT:
726## END
727
728## OK dash status: 2
729
730## OK bash status: 0
731## OK bash STDOUT:
732status=1
733status=1
734
735status=0
736status=0
737## END
738
739## OK mksh status: 0
740## OK mksh STDOUT:
74183
742status=0
743-83
744status=0
745
746status=0
747status=0
748## END
749
750#### no recursive arith [ 1+2 -eq 3 ]
751
752[ 1+2 -eq 3 ]
753echo status=$?
754
755s='1+2'
756[ "$s" -eq 3 ]
757echo status=$?
758
759## STDOUT:
760status=2
761status=2
762## END
763
764## BUG mksh STDOUT:
765status=0
766status=0
767## END