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

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