OILS / spec / dbracket.test.sh View on Github | oils.pub

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