OILS / spec / builtin-bracket.test.sh View on Github | oils.pub

817 lines, 457 significant
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[ = ]
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=$?
378test -b /
379echo status=$?
380
381echo -c
382test -c nonexistent
383echo status=$?
384test -c testdata
385echo status=$?
386
387echo -S
388test -S nonexistent
389echo status=$?
390test -S testdata
391echo status=$?
392
393## STDOUT:
394-b
395status=1
396status=1
397status=1
398-c
399status=1
400status=1
401-S
402status=1
403status=1
404## END
405
406
407#### test -p named pipe
408mkfifo $TMP/fifo
409test -p $TMP/fifo
410echo status=$?
411
412test -p testdata
413echo status=$?
414
415## STDOUT:
416status=0
417status=1
418## END
419
420#### -G and -O for effective user ID and group ID
421
422mkdir -p $TMP/bin
423
424test -O $TMP/bin
425echo status=$?
426test -O __nonexistent__
427echo status=$?
428
429test -G $TMP/bin
430echo status=$?
431test -G __nonexistent__
432echo status=$?
433
434## STDOUT:
435status=0
436status=1
437status=0
438status=1
439## END
440
441#### -u for setuid, -g too
442
443touch $TMP/setuid $TMP/setgid
444chmod u+s $TMP/setuid
445chmod g+s $TMP/setgid
446
447test -u $TMP/setuid
448echo status=$?
449
450test -u $TMP/setgid
451echo status=$?
452
453test -g $TMP/setuid
454echo status=$?
455
456test -g $TMP/setgid
457echo status=$?
458
459
460## STDOUT:
461status=0
462status=1
463status=1
464status=0
465## END
466
467#### -v to test variable (bash)
468test -v nonexistent
469echo global=$?
470
471g=1
472test -v g
473echo global=$?
474
475f() {
476 local f_var=0
477 g
478}
479
480g() {
481 test -v f_var
482 echo dynamic=$?
483 test -v g
484 echo dynamic=$?
485 test -v nonexistent
486 echo dynamic=$?
487}
488f
489
490## STDOUT:
491global=1
492global=0
493dynamic=0
494dynamic=0
495dynamic=1
496## END
497## N-I dash/mksh STDOUT:
498global=2
499global=2
500dynamic=2
501dynamic=2
502dynamic=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.
509test -o nounset
510echo status=$?
511
512set -o nounset
513test -o nounset
514echo status=$?
515
516test -o _bad_name_
517echo status=$?
518## STDOUT:
519status=1
520status=0
521status=1
522## END
523## N-I dash STDOUT:
524status=2
525status=2
526status=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
535left=$TMP/left
536right=$TMP/right
537touch $left $right
538
539ln -f $TMP/left $TMP/hardlink
540
541test $left -ef $left && echo same
542test $left -ef $TMP/hardlink && echo same
543test $left -ef $right || echo different
544
545test $TMP/__nonexistent -ef $right || echo different
546
547## STDOUT:
548same
549same
550different
551different
552## END
553
554#### Overflow error
555test -t 12345678910
556echo status=$?
557## STDOUT:
558status=2
559## END
560## OK dash/bash STDOUT:
561status=1
562## END
563
564#### Bug regression
565test "$ipv6" = "yes" -a "$ipv6lib" != "none"
566echo status=$?
567## STDOUT:
568status=1
569## END
570
571
572#### test -c
573test -c /dev/zero
574echo status=$?
575## STDOUT:
576status=0
577## END
578
579#### test -S
580test -S /dev/zero
581echo status=$?
582## STDOUT:
583status=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 ]
591echo status=$?
592
593[ $((-1)) -le 0 ]
594echo status=$?
595
596echo
597
598[ -1 -le 0 ]
599echo status=$?
600
601[ -42 -le 0 ]
602echo status=$?
603
604echo
605
606test -1 -le 0
607echo status=$?
608
609test -42 -le 0
610echo status=$?
611
612## STDOUT:
613status=0
614status=0
615
616status=0
617status=0
618
619status=0
620status=0
621## END
622
623#### negative octal numbers, etc.
624
625# zero
626[ -0 -eq 0 ]
627echo zero=$?
628
629# octal numbers can be negative
630[ -0123 -eq -83 ]
631echo octal=$?
632
633# hex doesn't have negative numbers?
634[ -0xff -eq -255 ]
635echo hex=$?
636
637# base N doesn't either
638[ -64#a -eq -10 ]
639echo baseN=$?
640
641## STDOUT:
642zero=0
643octal=1
644hex=2
645baseN=2
646## END
647
648#### More negative numbers
649case $SH in dash) exit ;; esac
650
651[[ -1 -le 0 ]]
652echo status=$?
653
654[[ $((-1)) -le 0 ]]
655echo status=$?
656
657## STDOUT:
658status=0
659status=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
668echo $(( 073 ))
669echo $(( -073 ))
670
671echo
672
673# Bracket does NOT have octal conversion! That is annoying.
674[ 073 -eq 73 ]
675echo status=$?
676
677[ -073 -eq -73 ]
678echo status=$?
679
680echo
681
682[ 0xff -eq 255 ]
683echo hex=$?
684[ 64#a -eq 10 ]
685echo baseN=$?
686
687## STDOUT:
68859
689-59
690
691status=0
692status=0
693
694hex=2
695baseN=2
696## END
697
698## BUG mksh STDOUT:
69973
700-73
701
702status=0
703status=0
704
705hex=2
706baseN=2
707## END
708
709#### Looks like octal, but digit is too big
710
711# arithmetic has octal conversion
712echo $(( 083 ))
713echo status=$?
714
715echo $(( -083 ))
716echo status=$?
717
718echo
719
720# Bracket does NOT have octal conversion! That is annoying.
721[ 083 -eq 83 ]
722echo status=$?
723
724[ -083 -eq -83 ]
725echo 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:
735status=1
736status=1
737
738status=0
739status=0
740## END
741
742## OK mksh status: 0
743## OK mksh STDOUT:
74483
745status=0
746-83
747status=0
748
749status=0
750status=0
751## END
752
753#### no recursive arith [ 1+2 -eq 3 ]
754
755[ 1+2 -eq 3 ]
756echo status=$?
757
758s='1+2'
759[ "$s" -eq 3 ]
760echo status=$?
761
762## STDOUT:
763status=2
764status=2
765## END
766
767## BUG mksh STDOUT:
768status=0
769status=0
770## END
771
772#### unary operator treated as a word in front of a binary operator
773
774# Minimal repro of sqsh build error (#2409)
775set -- -o; test $# -ne 0 -a "$1" != "--"
776echo status=$?
777
778# Now hardcode $1
779test $# -ne 0 -a "-o" != "--"
780echo status=$?
781
782# Remove quotes around -o
783test $# -ne 0 -a -o != "--"
784echo status=$?
785
786# How about a different flag?
787set -- -z; test $# -ne 0 -a "$1" != "--"
788echo status=$?
789
790# A non-flag?
791set -- z; test $# -ne 0 -a "$1" != "--"
792echo status=$?
793
794# (
795test $# -ne 0 -a "(" != ")"
796echo status=$?
797
798## STDOUT:
799status=0
800status=0
801status=0
802status=0
803status=0
804status=0
805## END
806
807#### paren is treated as a word in front of a binary operator
808
809test $# -eq 0 -a "(" == ")"
810echo status=$?
811
812## STDOUT:
813status=1
814## END
815## BUG mksh/bash/dash STDOUT:
816status=0
817## END