OILS / spec / dbracket.test.sh View on Github | oilshell.org

586 lines, 287 significant
1## oils_failures_allowed: 3
2## compare_shells: bash-4.4 mksh
3
4# NOTE: zsh passes about half, and fails about half. It supports a subset of
5# [[ I guess.
6
7#### [[ glob matching, [[ has no glob expansion
8[[ foo.py == *.py ]] && echo true
9[[ foo.p == *.py ]] || echo false
10## stdout-json: "true\nfalse\n"
11
12#### [[ glob matching with escapes
13[[ 'foo.*' == *."*" ]] && echo true
14# note that the pattern arg to fnmatch should be '*.\*'
15## stdout: true
16
17#### equality
18[[ '*.py' == '*.py' ]] && echo true
19[[ foo.py == '*.py' ]] || echo false
20## stdout-json: "true\nfalse\n"
21
22#### [[ glob matching with unquoted var
23pat=*.py
24[[ foo.py == $pat ]] && echo true
25[[ foo.p == $pat ]] || echo false
26## stdout-json: "true\nfalse\n"
27
28#### [[ regex matching
29# mksh doesn't have this syntax of regex matching. I guess it comes from perl?
30regex='.*\.py'
31[[ foo.py =~ $regex ]] && echo true
32[[ foo.p =~ $regex ]] || echo false
33## stdout-json: "true\nfalse\n"
34## N-I mksh stdout-json: ""
35## N-I mksh status: 1
36
37#### [[ regex syntax error
38# hm, it doesn't show any error, but it exits 2.
39[[ foo.py =~ * ]] && echo true
40## status: 2
41## N-I mksh status: 1
42
43#### [[ has no word splitting
44var='one two'
45[[ 'one two' == $var ]] && echo true
46## stdout: true
47
48#### [[ has quote joining
49var='one two'
50[[ 'one 'tw"o" == $var ]] && echo true
51## stdout: true
52
53#### [[ empty string is false
54[[ 'a' ]] && echo true
55[[ '' ]] || echo false
56## stdout-json: "true\nfalse\n"
57
58#### && chain
59[[ t && t && '' ]] || echo false
60## stdout: false
61
62#### || chain
63[[ '' || '' || t ]] && echo true
64## stdout: true
65
66#### [[ compound expressions
67# Notes on whitespace:
68# - 1 and == need space seprating them, but ! and ( don't.
69# - [[ needs whitesapce after it, but ]] doesn't need whitespace before it!
70[[ ''||! (1 == 2)&&(2 == 2)]] && echo true
71## stdout: true
72
73# NOTE on the two cases below. We're comparing
74# (a || b) && c vs. a || (b && c)
75#
76# a = true, b = false, c = false is an example where they are different.
77# && and || have precedence inside
78
79#### precedence of && and || inside [[
80[[ True || '' && '' ]] && echo true
81## stdout: true
82
83#### precedence of && and || in a command context
84if test True || test '' && test ''; then
85 echo YES
86else
87 echo "NO precedence"
88fi
89## stdout: NO precedence
90
91# http://tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS
92
93#### Octal literals with -eq
94shopt -u strict_arith || true
95decimal=15
96octal=017 # = 15 (decimal)
97[[ $decimal -eq $octal ]] && echo true
98[[ $decimal -eq ZZZ$octal ]] || echo false
99## STDOUT:
100true
101false
102## END
103## N-I mksh stdout: false
104# mksh doesn't implement this syntax for literals.
105
106#### Hex literals with -eq
107shopt -u strict_arith || true
108decimal=15
109hex=0x0f # = 15 (decimal)
110[[ $decimal -eq $hex ]] && echo true
111[[ $decimal -eq ZZZ$hex ]] || echo false
112## stdout-json: "true\nfalse\n"
113## N-I mksh stdout: false
114
115# TODO: Add tests for this
116# https://www.gnu.org/software/bash/manual/bash.html#Bash-Conditional-Expressions
117# When used with [[, the ‘<’ and ‘>’ operators sort lexicographically using the
118# current locale. The test command uses ASCII ordering.
119
120#### > on strings
121# NOTE: < doesn't need space, even though == does? That's silly.
122[[ b>a ]] && echo true
123[[ b<a ]] || echo false
124## stdout-json: "true\nfalse\n"
125
126#### != on strings
127# NOTE: b!=a does NOT work
128[[ b != a ]] && echo true
129[[ a != a ]] || echo false
130## stdout-json: "true\nfalse\n"
131
132#### -eq on strings
133# This is lame behavior: it does a conversion to 0 first for any string
134shopt -u strict_arith || true
135[[ a -eq a ]] && echo true
136[[ a -eq b ]] && echo true
137## STDOUT:
138true
139true
140## END
141
142#### [[ compare with literal -f (compare with test-builtin.test.sh)
143var=-f
144[[ $var == -f ]] && echo true
145[[ '-f' == $var ]] && echo true
146## stdout-json: "true\ntrue\n"
147
148#### [[ with op variable (compare with test-builtin.test.sh)
149# Parse error -- parsed BEFORE evaluation of vars
150op='=='
151[[ a $op a ]] && echo true
152[[ a $op b ]] || echo false
153## status: 2
154## OK mksh status: 1
155
156#### [[ with unquoted empty var (compare with test-builtin.test.sh)
157empty=''
158[[ $empty == '' ]] && echo true
159## stdout: true
160
161#### [[ at runtime doesn't work
162dbracket=[[
163$dbracket foo == foo ]]
164## status: 127
165
166#### [[ with env prefix doesn't work
167FOO=bar [[ foo == foo ]]
168## status: 127
169
170#### [[ over multiple lines is OK
171# Hm it seems you can't split anywhere?
172[[ foo == foo
173&& bar == bar
174]] && echo true
175## status: 0
176## STDOUT:
177true
178## END
179
180#### Argument that looks like a command word operator
181[[ -f -f ]] || echo false
182[[ -f == ]] || echo false
183## STDOUT:
184false
185false
186## END
187
188#### Argument that looks like a real operator
189[[ -f < ]] && echo 'should be parse error'
190## status: 2
191## OK mksh status: 1
192
193#### User array compared to "$@" (broken unless shopt -s strict_array)
194# Both are coerced to string! It treats it more like an UNQUOTED ${a[@]}.
195
196a=('1 3' 5)
197b=(1 2 3)
198set -- 1 '3 5'
199[[ "$@" = "${a[@]}" ]] && echo true
200[[ "$@" = "${b[@]}" ]] || echo false
201## STDOUT:
202true
203false
204## END
205
206#### Array coerces to string (shopt -s strict_array to disallow)
207a=('1 3' 5)
208[[ '1 3 5' = "${a[@]}" ]] && echo true
209[[ '1 3 4' = "${a[@]}" ]] || echo false
210## STDOUT:
211true
212false
213## END
214
215#### (( array1 == array2 )) doesn't work
216a=('1 3' 5)
217b=('1 3' 5)
218c=('1' '3 5')
219d=('1' '3 6')
220
221# shells EXPAND a and b first
222(( a == b ))
223echo status=$?
224
225(( a == c ))
226echo status=$?
227
228(( a == d ))
229echo status=$?
230
231## stdout-json: ""
232## status: 1
233## BUG bash STDOUT:
234status=1
235status=1
236status=1
237## END
238## BUG bash status: 0
239
240#### Quotes don't matter in comparison
241[[ '3' = 3 ]] && echo true
242[[ '3' -eq 3 ]] && echo true
243## STDOUT:
244true
245true
246## END
247
248#### -eq does dynamic arithmetic parsing (not supported in OSH)
249[[ 1+2 -eq 3 ]] && echo true
250expr='1+2'
251[[ $expr -eq 3 ]] && echo true # must be dynamically parsed
252## STDOUT:
253true
254true
255## END
256
257#### -eq coercion produces weird results
258shopt -u strict_arith || true
259[[ '' -eq 0 ]] && echo true
260## stdout: true
261
262#### [[ '(' ]] is treated as literal
263[[ '(' ]]
264echo status=$?
265## stdout: status=0
266
267#### [[ '(' foo ]] is syntax error
268[[ '(' foo ]]
269echo status=$?
270## status: 2
271## OK mksh status: 1
272
273#### empty ! is treated as literal
274[[ '!' ]]
275echo status=$?
276## stdout: status=0
277
278#### [[ -z ]] is syntax error
279[[ -z ]]
280echo status=$?
281## status: 2
282## OK mksh status: 1
283
284#### [[ -z '>' ]]
285[[ -z '>' ]] || echo false # -z is operator
286## stdout: false
287
288#### [[ -z '>' a ]] is syntax error
289[[ -z '>' -- ]]
290echo status=$?
291## status: 2
292## OK mksh status: 1
293
294#### test whether ']]' is empty
295[[ ']]' ]]
296echo status=$?
297## status: 0
298
299#### [[ ]] is syntax error
300[[ ]]
301echo status=$?
302## stdout-json: ""
303## status: 2
304## OK mksh status: 1
305
306#### [[ && ]] is syntax error
307[[ && ]]
308echo status=$?
309## stdout-json: ""
310## status: 2
311## OK mksh status: 1
312
313#### [[ a 3< b ]] doesn't work (bug regression)
314[[ a 3< b ]]
315echo status=$?
316[[ a 3> b ]]
317echo status=$?
318## status: 2
319
320# Hm these shells use the same redirect trick that OSH used to!
321
322## BUG mksh/zsh status: 0
323## BUG mksh/zsh STDOUT:
324status=0
325status=1
326## END
327
328#### tilde expansion in [[
329HOME=/home/bob
330[[ ~ == /home/bob ]]
331echo status=$?
332
333[[ ~ == */bob ]]
334echo status=$?
335
336[[ ~ == */z ]]
337echo status=$?
338
339## STDOUT:
340status=0
341status=0
342status=1
343## END
344
345#### more tilde expansion
346[[ ~ ]]
347echo status=$?
348HOME=''
349[[ ~ ]]
350echo status=$?
351[[ -n ~ ]]
352echo unary=$?
353
354[[ ~ == ~ ]]
355echo status=$?
356
357[[ $HOME == ~ ]]
358echo fnmatch=$?
359[[ ~ == $HOME ]]
360echo fnmatch=$?
361
362## STDOUT:
363status=0
364status=1
365unary=1
366status=0
367fnmatch=0
368fnmatch=0
369## END
370
371#### tilde expansion with =~ (confusing)
372case $SH in (mksh) exit ;; esac
373
374HOME=foo
375[[ ~ =~ $HOME ]]
376echo regex=$?
377[[ $HOME =~ ~ ]]
378echo regex=$?
379
380HOME='^a$' # looks like regex
381[[ ~ =~ $HOME ]]
382echo regex=$?
383[[ $HOME =~ ~ ]]
384echo regex=$?
385
386## STDOUT:
387regex=0
388regex=0
389regex=1
390regex=0
391## END
392## OK zsh STDOUT:
393regex=0
394regex=0
395regex=1
396regex=1
397## END
398## N-I mksh stdout-json: ""
399
400#### [[ ]] with redirect
401[[ $(stdout_stderr.py) == STDOUT ]] 2>$TMP/x.txt
402echo $?
403echo --
404cat $TMP/x.txt
405## STDOUT:
4060
407--
408STDERR
409## END
410
411#### special chars
412[[ ^ == ^ ]]
413echo caret $?
414[[ '!' == ! ]]
415echo bang $?
416## STDOUT:
417caret 0
418bang 0
419## END
420
421
422#### \(\) in pattern (regression)
423if [[ 'foo()' == *\(\) ]]; then echo match1; fi
424if [[ 'foo()' == *'()' ]]; then echo match2; fi
425if [[ 'foo()' == '*()' ]]; then echo match3; fi
426
427shopt -s extglob
428
429if [[ 'foo()' == *\(\) ]]; then echo match1; fi
430if [[ 'foo()' == *'()' ]]; then echo match2; fi
431if [[ 'foo()' == '*()' ]]; then echo match3; fi
432
433## STDOUT:
434match1
435match2
436match1
437match2
438## END
439
440
441#### [[ -v array[i] ]]
442
443typeset -a array
444array=('' nonempty)
445
446[[ -v array[0] ]]
447echo zero=$?
448
449[[ -v array[1] ]]
450echo one=$?
451
452[[ -v array[2] ]]
453echo two=$?
454
455## STDOUT:
456zero=0
457one=0
458two=1
459## END
460
461## N-I mksh status: 1
462## N-I mksh STDOUT:
463## END
464
465#### [[ -v array[expr]] ]] does arith expression evaluation
466
467typeset -a array
468array=('' nonempty)
469
470# This feels inconsistent with the rest of bash?
471zero=0
472
473[[ -v array[zero+0] ]]
474echo zero=$?
475
476[[ -v array[zero+1] ]]
477echo one=$?
478
479[[ -v array[zero+2] ]]
480echo two=$?
481
482echo ---
483
484i='0+0'
485[[ -v array[i] ]]
486echo zero=$?
487
488i='0+1'
489[[ -v array[i] ]]
490echo one=$?
491
492i='0+2'
493[[ -v array[i] ]]
494echo two=$?
495
496echo ---
497
498i='0+0'
499[[ -v array[$i] ]]
500echo zero=$?
501
502i='0+1'
503[[ -v array[$i] ]]
504echo one=$?
505
506i='0+2'
507[[ -v array[$i] ]]
508echo two=$?
509
510
511## STDOUT:
512zero=0
513one=0
514two=1
515---
516zero=0
517one=0
518two=1
519---
520zero=0
521one=0
522two=1
523## END
524
525## N-I mksh status: 1
526## N-I mksh STDOUT:
527## END
528
529#### [[ -v assoc[key] ]]
530
531typeset -A assoc
532assoc=([empty]='' [k]=v)
533
534[[ -v assoc[empty] ]]
535echo empty=$?
536
537[[ -v assoc[k] ]]
538echo k=$?
539
540[[ -v assoc[nonexistent] ]]
541echo nonexistent=$?
542
543echo ---
544# Now with quotes
545
546[[ -v assoc["empty"] ]]
547echo empty=$?
548
549[[ -v assoc['k'] ]]
550echo k=$?
551
552[[ -v assoc['nonexistent'] ]]
553echo nonexistent=$?
554
555echo ---
556# Now with var expansion
557
558key=empty
559[[ -v assoc[$key] ]]
560echo empty=$?
561
562key=k
563[[ -v assoc[$key] ]]
564echo k=$?
565
566key=nonexistent
567[[ -v assoc[$key] ]]
568echo nonexistent=$?
569
570## STDOUT:
571empty=0
572k=0
573nonexistent=1
574---
575empty=0
576k=0
577nonexistent=1
578---
579empty=0
580k=0
581nonexistent=1
582## END
583
584## N-I mksh status: 1
585## N-I mksh STDOUT:
586## END