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

494 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 mksh status: 1
219
220#### User array compared to "$@" (broken unless shopt -s strict_array)
221# Both are coerced to string! It treats it more like an UNQUOTED ${a[@]}.
222
223a=('1 3' 5)
224b=(1 2 3)
225set -- 1 '3 5'
226[[ "$@" = "${a[@]}" ]] && echo true
227[[ "$@" = "${b[@]}" ]] || echo false
228## STDOUT:
229true
230false
231## END
232
233#### Array coerces to string (shopt -s strict_array to disallow)
234a=('1 3' 5)
235[[ '1 3 5' = "${a[@]}" ]] && echo true
236[[ '1 3 4' = "${a[@]}" ]] || echo false
237## STDOUT:
238true
239false
240## END
241
242#### (( array1 == array2 )) doesn't work
243a=('1 3' 5)
244b=('1 3' 5)
245c=('1' '3 5')
246d=('1' '3 6')
247
248# shells EXPAND a and b first
249(( a == b ))
250echo status=$?
251
252(( a == c ))
253echo status=$?
254
255(( a == d ))
256echo status=$?
257
258## stdout-json: ""
259## status: 1
260## BUG bash STDOUT:
261status=1
262status=1
263status=1
264## END
265## BUG bash status: 0
266
267#### Quotes don't matter in comparison
268[[ '3' = 3 ]] && echo true
269[[ '3' -eq 3 ]] && echo true
270## STDOUT:
271true
272true
273## END
274
275#### -eq does dynamic arithmetic parsing (not supported in OSH)
276[[ 1+2 -eq 3 ]] && echo true
277expr='1+2'
278[[ $expr -eq 3 ]] && echo true # must be dynamically parsed
279## STDOUT:
280true
281true
282## END
283
284#### -eq coercion produces weird results
285shopt -u strict_arith || true
286[[ '' -eq 0 ]] && echo true
287## stdout: true
288
289#### [[ '(' ]] is treated as literal
290[[ '(' ]]
291echo status=$?
292## stdout: status=0
293
294#### [[ '(' foo ]] is syntax error
295[[ '(' foo ]]
296echo status=$?
297## status: 2
298## OK mksh status: 1
299
300#### empty ! is treated as literal
301[[ '!' ]]
302echo status=$?
303## stdout: status=0
304
305#### [[ -z ]] is syntax error
306[[ -z ]]
307echo status=$?
308## status: 2
309## OK mksh status: 1
310
311#### [[ -z '>' ]]
312[[ -z '>' ]] || echo false # -z is operator
313## stdout: false
314
315#### [[ -z '>' a ]] is syntax error
316[[ -z '>' -- ]]
317echo status=$?
318## status: 2
319## OK mksh status: 1
320
321#### test whether ']]' is empty
322[[ ']]' ]]
323echo status=$?
324## status: 0
325
326#### [[ ]] is syntax error
327[[ ]]
328echo status=$?
329## stdout-json: ""
330## status: 2
331## OK mksh status: 1
332
333#### [[ && ]] is syntax error
334[[ && ]]
335echo status=$?
336## stdout-json: ""
337## status: 2
338## OK mksh status: 1
339
340#### [[ a 3< b ]] doesn't work (bug regression)
341[[ a 3< b ]]
342echo status=$?
343[[ a 3> b ]]
344echo status=$?
345## status: 2
346
347# Hm these shells use the same redirect trick that OSH used to!
348
349## BUG mksh/zsh status: 0
350## BUG mksh/zsh STDOUT:
351status=0
352status=1
353## END
354
355#### tilde expansion in [[
356HOME=/home/bob
357[[ ~ == /home/bob ]]
358echo status=$?
359
360[[ ~ == */bob ]]
361echo status=$?
362
363[[ ~ == */z ]]
364echo status=$?
365
366## STDOUT:
367status=0
368status=0
369status=1
370## END
371
372#### more tilde expansion
373[[ ~ ]]
374echo status=$?
375HOME=''
376[[ ~ ]]
377echo status=$?
378[[ -n ~ ]]
379echo unary=$?
380
381[[ ~ == ~ ]]
382echo status=$?
383
384[[ $HOME == ~ ]]
385echo fnmatch=$?
386[[ ~ == $HOME ]]
387echo fnmatch=$?
388
389## STDOUT:
390status=0
391status=1
392unary=1
393status=0
394fnmatch=0
395fnmatch=0
396## END
397
398#### tilde expansion with =~ (confusing)
399case $SH in (mksh) exit ;; esac
400
401HOME=foo
402[[ ~ =~ $HOME ]]
403echo regex=$?
404[[ $HOME =~ ~ ]]
405echo regex=$?
406
407HOME='^a$' # looks like regex
408[[ ~ =~ $HOME ]]
409echo regex=$?
410[[ $HOME =~ ~ ]]
411echo regex=$?
412
413## STDOUT:
414regex=0
415regex=0
416regex=1
417regex=0
418## END
419## OK zsh STDOUT:
420regex=0
421regex=0
422regex=1
423regex=1
424## END
425## N-I mksh stdout-json: ""
426
427#### [[ ]] with redirect
428[[ $(stdout_stderr.py) == STDOUT ]] 2>$TMP/x.txt
429echo $?
430echo --
431cat $TMP/x.txt
432## STDOUT:
4330
434--
435STDERR
436## END
437
438#### special chars
439[[ ^ == ^ ]]
440echo caret $?
441[[ '!' == ! ]]
442echo bang $?
443## STDOUT:
444caret 0
445bang 0
446## END
447
448
449#### \(\) in pattern (regression)
450if [[ 'foo()' == *\(\) ]]; then echo match1; fi
451if [[ 'foo()' == *'()' ]]; then echo match2; fi
452if [[ 'foo()' == '*()' ]]; then echo match3; fi
453
454shopt -s extglob
455
456if [[ 'foo()' == *\(\) ]]; then echo match1; fi
457if [[ 'foo()' == *'()' ]]; then echo match2; fi
458if [[ 'foo()' == '*()' ]]; then echo match3; fi
459
460## STDOUT:
461match1
462match2
463match1
464match2
465## END
466
467#### negative numbers - zero, decimal, octal, hex, base N
468
469[[ -0 -eq 0 ]]; echo zero=$?
470
471[[ -42 -eq -42 ]]; echo decimal=$?
472
473# note: mksh doesn't do octal conversion
474[[ -0123 -eq -83 ]]; echo octal=$?
475
476[[ -0xff -eq -255 ]]; echo hex=$?
477
478[[ -64#a -eq -10 ]]; echo baseN=$?
479
480## STDOUT:
481zero=0
482decimal=0
483octal=0
484hex=0
485baseN=0
486## END
487
488## BUG mksh STDOUT:
489zero=0
490decimal=0
491octal=1
492hex=2
493baseN=2
494## END