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:
11 true
12 false
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:
24 true
25 false
26 ## END
27
28 #### [[ glob matching with unquoted var
29 pat=*.py
30 [[ foo.py == $pat ]] && echo true
31 [[ foo.p == $pat ]] || echo false
32 ## STDOUT:
33 true
34 false
35 ## END
36
37 #### [[ regex matching
38 # mksh doesn't have this syntax of regex matching. I guess it comes from perl?
39 regex='.*\.py'
40 [[ foo.py =~ $regex ]] && echo true
41 [[ foo.p =~ $regex ]] || echo false
42 ## STDOUT:
43 true
44 false
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
56 var='one two'
57 [[ 'one two' == $var ]] && echo true
58 ## stdout: true
59
60 #### [[ has quote joining
61 var='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:
69 true
70 false
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
99 if test True || test '' && test ''; then
100 echo YES
101 else
102 echo "NO precedence"
103 fi
104 ## stdout: NO precedence
105
106 # http://tldp.org/LDP/abs/html/testconstructs.html#DBLBRACKETS
107
108 #### Octal literals with -eq
109 shopt -u strict_arith || true
110 decimal=15
111 octal=017 # = 15 (decimal)
112 [[ $decimal -eq $octal ]] && echo true
113 [[ $decimal -eq ZZZ$octal ]] || echo false
114 ## STDOUT:
115 true
116 false
117 ## END
118 ## N-I mksh stdout: false
119 # mksh doesn't implement this syntax for literals.
120
121 #### Hex literals with -eq
122 shopt -u strict_arith || true
123 decimal=15
124 hex=0x0f # = 15 (decimal)
125 [[ $decimal -eq $hex ]] && echo true
126 [[ $decimal -eq ZZZ$hex ]] || echo false
127 ## STDOUT:
128 true
129 false
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:
143 true
144 false
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:
152 true
153 false
154 ## END
155
156 #### -eq on strings
157 # This is lame behavior: it does a conversion to 0 first for any string
158 shopt -u strict_arith || true
159 [[ a -eq a ]] && echo true
160 [[ a -eq b ]] && echo true
161 ## STDOUT:
162 true
163 true
164 ## END
165
166 #### [[ compare with literal -f (compare with test-builtin.test.sh)
167 var=-f
168 [[ $var == -f ]] && echo true
169 [[ '-f' == $var ]] && echo true
170 ## STDOUT:
171 true
172 true
173 ## END
174
175 #### [[ with op variable (compare with test-builtin.test.sh)
176 # Parse error -- parsed BEFORE evaluation of vars
177 op='=='
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)
184 empty=''
185 [[ $empty == '' ]] && echo true
186 ## stdout: true
187
188 #### [[ at runtime doesn't work
189 dbracket=[[
190 $dbracket foo == foo ]]
191 ## status: 127
192
193 #### [[ with env prefix doesn't work
194 FOO=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:
204 true
205 ## END
206
207 #### Argument that looks like a command word operator
208 [[ -f -f ]] || echo false
209 [[ -f == ]] || echo false
210 ## STDOUT:
211 false
212 false
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
223 a=('1 3' 5)
224 b=(1 2 3)
225 set -- 1 '3 5'
226 [[ "$@" = "${a[@]}" ]] && echo true
227 [[ "$@" = "${b[@]}" ]] || echo false
228 ## STDOUT:
229 true
230 false
231 ## END
232
233 #### Array coerces to string (shopt -s strict_array to disallow)
234 a=('1 3' 5)
235 [[ '1 3 5' = "${a[@]}" ]] && echo true
236 [[ '1 3 4' = "${a[@]}" ]] || echo false
237 ## STDOUT:
238 true
239 false
240 ## END
241
242 #### (( array1 == array2 )) doesn't work
243 a=('1 3' 5)
244 b=('1 3' 5)
245 c=('1' '3 5')
246 d=('1' '3 6')
247
248 # shells EXPAND a and b first
249 (( a == b ))
250 echo status=$?
251
252 (( a == c ))
253 echo status=$?
254
255 (( a == d ))
256 echo status=$?
257
258 ## stdout-json: ""
259 ## status: 1
260 ## BUG bash STDOUT:
261 status=1
262 status=1
263 status=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:
271 true
272 true
273 ## END
274
275 #### -eq does dynamic arithmetic parsing (not supported in OSH)
276 [[ 1+2 -eq 3 ]] && echo true
277 expr='1+2'
278 [[ $expr -eq 3 ]] && echo true # must be dynamically parsed
279 ## STDOUT:
280 true
281 true
282 ## END
283
284 #### -eq coercion produces weird results
285 shopt -u strict_arith || true
286 [[ '' -eq 0 ]] && echo true
287 ## stdout: true
288
289 #### [[ '(' ]] is treated as literal
290 [[ '(' ]]
291 echo status=$?
292 ## stdout: status=0
293
294 #### [[ '(' foo ]] is syntax error
295 [[ '(' foo ]]
296 echo status=$?
297 ## status: 2
298 ## OK mksh status: 1
299
300 #### empty ! is treated as literal
301 [[ '!' ]]
302 echo status=$?
303 ## stdout: status=0
304
305 #### [[ -z ]] is syntax error
306 [[ -z ]]
307 echo 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 '>' -- ]]
317 echo status=$?
318 ## status: 2
319 ## OK mksh status: 1
320
321 #### test whether ']]' is empty
322 [[ ']]' ]]
323 echo status=$?
324 ## status: 0
325
326 #### [[ ]] is syntax error
327 [[ ]]
328 echo status=$?
329 ## stdout-json: ""
330 ## status: 2
331 ## OK mksh status: 1
332
333 #### [[ && ]] is syntax error
334 [[ && ]]
335 echo 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 ]]
342 echo status=$?
343 [[ a 3> b ]]
344 echo 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:
351 status=0
352 status=1
353 ## END
354
355 #### tilde expansion in [[
356 HOME=/home/bob
357 [[ ~ == /home/bob ]]
358 echo status=$?
359
360 [[ ~ == */bob ]]
361 echo status=$?
362
363 [[ ~ == */z ]]
364 echo status=$?
365
366 ## STDOUT:
367 status=0
368 status=0
369 status=1
370 ## END
371
372 #### more tilde expansion
373 [[ ~ ]]
374 echo status=$?
375 HOME=''
376 [[ ~ ]]
377 echo status=$?
378 [[ -n ~ ]]
379 echo unary=$?
380
381 [[ ~ == ~ ]]
382 echo status=$?
383
384 [[ $HOME == ~ ]]
385 echo fnmatch=$?
386 [[ ~ == $HOME ]]
387 echo fnmatch=$?
388
389 ## STDOUT:
390 status=0
391 status=1
392 unary=1
393 status=0
394 fnmatch=0
395 fnmatch=0
396 ## END
397
398 #### tilde expansion with =~ (confusing)
399 case $SH in (mksh) exit ;; esac
400
401 HOME=foo
402 [[ ~ =~ $HOME ]]
403 echo regex=$?
404 [[ $HOME =~ ~ ]]
405 echo regex=$?
406
407 HOME='^a$' # looks like regex
408 [[ ~ =~ $HOME ]]
409 echo regex=$?
410 [[ $HOME =~ ~ ]]
411 echo regex=$?
412
413 ## STDOUT:
414 regex=0
415 regex=0
416 regex=1
417 regex=0
418 ## END
419 ## OK zsh STDOUT:
420 regex=0
421 regex=0
422 regex=1
423 regex=1
424 ## END
425 ## N-I mksh stdout-json: ""
426
427 #### [[ ]] with redirect
428 [[ $(stdout_stderr.py) == STDOUT ]] 2>$TMP/x.txt
429 echo $?
430 echo --
431 cat $TMP/x.txt
432 ## STDOUT:
433 0
434 --
435 STDERR
436 ## END
437
438 #### special chars
439 [[ ^ == ^ ]]
440 echo caret $?
441 [[ '!' == ! ]]
442 echo bang $?
443 ## STDOUT:
444 caret 0
445 bang 0
446 ## END
447
448
449 #### \(\) in pattern (regression)
450 if [[ 'foo()' == *\(\) ]]; then echo match1; fi
451 if [[ 'foo()' == *'()' ]]; then echo match2; fi
452 if [[ 'foo()' == '*()' ]]; then echo match3; fi
453
454 shopt -s extglob
455
456 if [[ 'foo()' == *\(\) ]]; then echo match1; fi
457 if [[ 'foo()' == *'()' ]]; then echo match2; fi
458 if [[ 'foo()' == '*()' ]]; then echo match3; fi
459
460 ## STDOUT:
461 match1
462 match2
463 match1
464 match2
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:
481 zero=0
482 decimal=0
483 octal=0
484 hex=0
485 baseN=0
486 ## END
487
488 ## BUG mksh STDOUT:
489 zero=0
490 decimal=0
491 octal=1
492 hex=2
493 baseN=2
494 ## END