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

798 lines, 458 significant
1## compare_shells: bash-4.4
2## oils_failures_allowed: 6
3
4
5# NOTE:
6# -declare -A is required.
7#
8# Simply doing:
9# a=([aa]=b [foo]=bar ['a+1']=c)
10# gets utterly bizarre behavior.
11#
12# Associtative Arrays are COMPLETELY bash-specific. mksh doesn't even come
13# close. So I will probably not implement them, or implement something
14# slightly different, because the semantics are just weird.
15
16# http://www.gnu.org/software/bash/manual/html_node/Arrays.html
17# TODO: Need a SETUP section.
18
19#### Literal syntax ([x]=y)
20declare -A a
21a=([aa]=b [foo]=bar ['a+1']=c)
22echo ${a["aa"]}
23echo ${a["foo"]}
24echo ${a["a+1"]}
25## STDOUT:
26b
27bar
28c
29## END
30
31#### set associative array to indexed array literal (very surprising bash behavior)
32declare -A assoc=([k1]=foo [k2]='spam eggs')
33for v in "${assoc[@]}"; do echo $v; done | sort
34for v in "${!assoc[@]}"; do echo $v; done | sort
35
36# disallow this in OSH? Changing type?
37
38assoc=(foo 'spam eggs')
39argv.py "${assoc[@]}"
40argv.py "${!assoc[@]}"
41
42## STDOUT:
43foo
44spam eggs
45k1
46k2
47['foo', 'spam eggs']
48['0', '1']
49## END
50## BUG bash STDOUT:
51foo
52spam eggs
53k1
54k2
55[]
56[]
57## END
58
59#### Can't initialize assoc array with indexed array
60declare -A A=(1 2 3)
61echo status=$?
62## STDOUT:
63status=2
64## END
65
66# bash prints warnings to stderr but gives no indication of the problem
67## BUG bash STDOUT:
68status=0
69## END
70
71
72#### Initializing indexed array with assoc array
73declare -a a=([xx]=1 [yy]=2 [zz]=3)
74echo status=$?
75argv.py "${a[@]}"
76## STDOUT:
77status=2
78[]
79## END
80## BUG bash STDOUT:
81status=0
82['3']
83## END
84
85#### create empty assoc array, put, then get
86declare -A A # still undefined
87argv.py "${A[@]}"
88argv.py "${!A[@]}"
89A['foo']=bar
90echo ${A['foo']}
91## STDOUT:
92[]
93[]
94bar
95## END
96
97#### Empty value (doesn't use EmptyWord?)
98declare -A A=(["k"]= )
99argv.py "${A["k"]}"
100## STDOUT:
101['']
102## END
103
104#### retrieve keys with !
105declare -A a
106var='x'
107a["$var"]=b
108a['foo']=bar
109a['a+1']=c
110for key in "${!a[@]}"; do
111 echo $key
112done | sort
113## STDOUT:
114a+1
115foo
116x
117## END
118
119#### retrieve values with ${A[@]}
120declare -A A
121var='x'
122A["$var"]=b
123A['foo']=bar
124A['a+1']=c
125for val in "${A[@]}"; do
126 echo $val
127done | sort
128## STDOUT:
129b
130bar
131c
132## END
133
134#### coerce to string with ${A[*]}, etc.
135declare -A A
136A['X X']=xx
137A['Y Y']=yy
138argv.py "${A[*]}"
139argv.py "${!A[*]}"
140
141argv.py ${A[@]}
142argv.py ${!A[@]}
143## STDOUT:
144['xx yy']
145['X X Y Y']
146['xx', 'yy']
147['X', 'X', 'Y', 'Y']
148## END
149
150#### ${A[@]/b/B}
151# but ${!A[@]/b/B} doesn't work
152declare -A A
153A['aa']=bbb
154A['bb']=ccc
155A['cc']=ddd
156for val in "${A[@]//b/B}"; do
157 echo $val
158done | sort
159## STDOUT:
160BBB
161ccc
162ddd
163## END
164
165#### ${A[@]#prefix}
166declare -A A
167A['aa']=one
168A['bb']=two
169A['cc']=three
170for val in "${A[@]#t}"; do
171 echo $val
172done | sort
173## STDOUT:
174hree
175one
176wo
177## END
178
179#### ${assoc} is like ${assoc[0]}
180declare -A a
181
182a=([aa]=b [foo]=bar ['a+1']=c)
183echo a="${a}"
184
185a=([0]=zzz)
186echo a="${a}"
187
188a=(['0']=yyy)
189echo a="${a}"
190
191## STDOUT:
192a=
193a=zzz
194a=yyy
195## END
196
197#### length ${#a[@]}
198declare -A a
199a["x"]=1
200a["y"]=2
201a["z"]=3
202echo "${#a[@]}"
203## stdout: 3
204
205#### lookup with ${a[0]} -- "0" is a string
206declare -A a
207a["0"]=a
208a["1"]=b
209a["2"]=c
210echo 0 "${a[0]}" 1 "${a[1]}" 2 "${a[2]}"
211## STDOUT:
2120 a 1 b 2 c
213## END
214
215#### lookup with double quoted strings "mykey"
216declare -A a
217a["aa"]=b
218a["foo"]=bar
219a['a+1']=c
220echo "${a["aa"]}" "${a["foo"]}" "${a["a+1"]}"
221## STDOUT:
222b bar c
223## END
224
225#### lookup with single quoted string
226declare -A a
227a["aa"]=b
228a["foo"]=bar
229a['a+1']=c
230echo "${a['a+1']}"
231## stdout: c
232
233#### lookup with unquoted $key and quoted "$i$i"
234declare -A A
235A["aa"]=b
236A["foo"]=bar
237
238key=foo
239echo ${A[$key]}
240i=a
241echo ${A["$i$i"]} # note: ${A[$i$i]} doesn't work in OSH
242## STDOUT:
243bar
244b
245## END
246
247#### lookup by unquoted string doesn't work in OSH because it's a variable
248declare -A a
249a["aa"]=b
250a["foo"]=bar
251a['a+1']=c
252echo "${a[a+1]}"
253## stdout-json: ""
254## status: 1
255## BUG bash stdout: c
256## BUG bash status: 0
257
258#### bash bug: "i+1" and i+1 are the same key
259
260i=1
261array=(5 6 7)
262echo array[i]="${array[i]}"
263echo array[i+1]="${array[i+1]}"
264
265# arithmetic does NOT work here in bash. These are unquoted strings!
266declare -A assoc
267assoc[i]=$i
268assoc[i+1]=$i+1
269
270assoc["i"]=string
271assoc["i+1"]=string+1
272
273echo assoc[i]="${assoc[i]}"
274echo assoc[i+1]="${assoc[i+1]}"
275
276echo assoc[i]="${assoc["i"]}"
277echo assoc[i+1]="${assoc["i+1"]}"
278
279## status: 1
280## STDOUT:
281array[i]=6
282array[i+1]=7
283## END
284## BUG bash status: 0
285## BUG bash STDOUT:
286array[i]=6
287array[i+1]=7
288assoc[i]=string
289assoc[i+1]=string+1
290assoc[i]=string
291assoc[i+1]=string+1
292## END
293
294#### Array stored in associative array gets converted to string (without strict_array)
295
296array=('1 2' 3)
297declare -A d
298d['key']="${array[@]}"
299argv.py "${d['key']}"
300## stdout: ['1 2 3']
301
302#### Indexed array as key of associative array coerces to string (without shopt -s strict_array)
303
304declare -a array=(1 2 3)
305declare -A assoc
306assoc[42]=43
307assoc["${array[@]}"]=foo
308
309echo "${assoc["${array[@]}"]}"
310for entry in "${!assoc[@]}"; do
311 echo $entry
312done | sort
313
314## STDOUT:
315foo
3161 2 3
31742
318## END
319
320#### Append to associative array value A['x']+='suffix'
321declare -A A
322A['x']='foo'
323A['x']+='bar'
324A['x']+='bar'
325argv.py "${A["x"]}"
326## STDOUT:
327['foobarbar']
328## END
329
330#### Slice of associative array doesn't make sense in bash
331declare -A a
332a[xx]=1
333a[yy]=2
334a[zz]=3
335a[aa]=4
336a[bb]=5
337#argv.py ${a["xx"]}
338argv.py ${a[@]: 0: 3}
339argv.py ${a[@]: 1: 3}
340argv.py ${a[@]: 2: 3}
341argv.py ${a[@]: 3: 3}
342argv.py ${a[@]: 4: 3}
343argv.py ${a[@]: 5: 3}
344## stdout-json: ""
345## status: 1
346## BUG bash STDOUT:
347['2', '1', '5']
348['2', '1', '5']
349['1', '5', '4']
350['5', '4', '3']
351['4', '3']
352['3']
353## END
354## BUG bash status: 0
355
356#### bash variable can have an associative array part and a string part
357
358# and $assoc is equivalent to ${assoc[0]}, just like regular arrays
359declare -A assoc
360assoc[1]=1
361assoc[2]=2
362echo ${assoc[1]} ${assoc[2]} ${assoc}
363assoc[0]=zero
364echo ${assoc[1]} ${assoc[2]} ${assoc}
365assoc=string
366echo ${assoc[1]} ${assoc[2]} ${assoc}
367## STDOUT:
3681 2
3691 2 zero
3701 2 string
371## END
372## N-I osh status: 1
373## N-I osh STDOUT:
3741 2
3751 2 zero
376## END
377
378#### Associative array expressions inside (( )) with keys that look like numbers
379declare -A assoc
380assoc[0]=42
381(( var = ${assoc[0]} ))
382echo $var
383(( var = assoc[0] ))
384echo $var
385## STDOUT:
38642
38742
388## END
389
390#### (( A[5] += 42 ))
391declare -A A
392(( A[5] = 10 ))
393(( A[5] += 6 ))
394echo ${A[5]}
395## STDOUT:
39616
397## END
398
399#### (( A[5] += 42 )) with empty cell
400shopt -u strict_arith # default zero cell
401declare -A A
402(( A[5] += 6 ))
403echo ${A[5]}
404## STDOUT:
4056
406## END
407
408#### setting key to itself (from bash-bug mailing list)
409declare -A foo
410foo=(["key"]="value1")
411echo ${foo["key"]}
412foo=(["key"]="${foo["key"]} value2")
413echo ${foo["key"]}
414## STDOUT:
415value1
416value1 value2
417## END
418## BUG bash STDOUT:
419value1
420value2
421## END
422
423#### readonly associative array can't be modified
424declare -Ar A
425A['x']=1
426echo status=$?
427## OK osh status: 1
428## OK osh stdout-json: ""
429## STDOUT:
430status=1
431## END
432
433#### associative array and brace expansion
434declare -A A=([k1]=v [k2]=-{a,b}-)
435echo ${A["k1"]}
436echo ${A["k2"]}
437## STDOUT:
438v
439-{a,b}-
440## END
441
442#### bash mangles array #1
443a=([k1]=v1 [k2]=v2)
444echo ${a["k1"]}
445echo ${a["k2"]}
446## STDOUT:
447v1
448v2
449## END
450## BUG bash STDOUT:
451v2
452v2
453## END
454
455#### bash mangles array and brace #2
456a=([k2]=-{a,b}-)
457echo ${a["k2"]}
458## STDOUT:
459-{a,b}-
460## END
461## BUG bash STDOUT:
462[k2]=-a-
463## END
464
465#### declare -A A=() allowed
466set -o nounset
467shopt -s strict_arith || true
468
469declare -A ASSOC=()
470echo len=${#ASSOC[@]}
471
472# Check that it really can be used like an associative array
473ASSOC['k']='32'
474echo len=${#ASSOC[@]}
475
476# bash allows a variable to be an associative array AND unset, while OSH
477# doesn't
478set +o nounset
479declare -A u
480echo unset len=${#u[@]}
481## STDOUT:
482len=0
483len=1
484unset len=0
485## END
486
487#### unset -v and assoc array
488shopt -s eval_unsafe_arith || true
489
490show-len() {
491 echo len=${#assoc[@]}
492}
493
494declare -A assoc=(['K']=val)
495show-len
496
497unset -v 'assoc["K"]'
498show-len
499
500declare -A assoc=(['K']=val)
501show-len
502key=K
503unset -v 'assoc[$key]'
504show-len
505
506declare -A assoc=(['K']=val)
507show-len
508unset -v 'assoc[$(echo K)]'
509show-len
510
511# ${prefix} doesn't work here, even though it does in arithmetic
512#declare -A assoc=(['K']=val)
513#show-len
514#prefix=as
515#unset -v '${prefix}soc[$key]'
516#show-len
517
518## STDOUT:
519len=1
520len=0
521len=1
522len=0
523len=1
524len=0
525## END
526
527#### nameref and assoc array
528show-values() {
529 echo values: ${A[@]}
530}
531
532declare -A A=(['K']=val)
533show-values
534
535declare -n ref='A["K"]'
536echo before $ref
537ref='val2'
538echo after $ref
539show-values
540
541echo ---
542
543key=K
544declare -n ref='A[$key]'
545echo before $ref
546ref='val3'
547echo after $ref
548show-values
549
550## STDOUT:
551values: val
552before val
553after val2
554values: val2
555---
556before val2
557after val3
558values: val3
559## END
560
561#### ${!ref} and assoc array
562
563show-values() {
564 echo values: ${A[@]}
565}
566
567declare -A A=(['K']=val)
568show-values
569
570declare ref='A["K"]'
571echo ref ${!ref}
572
573key=K
574declare ref='A[$key]'
575echo ref ${!ref}
576
577## STDOUT:
578values: val
579ref val
580ref val
581## END
582
583#### printf -v and assoc array
584
585show-values() {
586 echo values: ${assoc[@]}
587}
588
589declare -A assoc=(['K']=val)
590show-values
591
592printf -v 'assoc["K"]' '/%s/' val2
593show-values
594
595key=K
596printf -v 'assoc[$key]' '/%s/' val3
597show-values
598
599# Somehow bash doesn't allow this
600#prefix=as
601#printf -v '${prefix}soc[$key]' '/%s/' val4
602#show-values
603
604## STDOUT:
605values: val
606values: /val2/
607values: /val3/
608## END
609
610#### bash bug: (( A["$key"] = 1 )) doesn't work
611key='\'
612declare -A A
613#A["$key"]=1
614
615# Works in both
616#A["$key"]=42
617
618# Works in bash only
619#(( A[\$key] = 42 ))
620
621(( A["$key"] = 42 ))
622
623argv.py "${!A[@]}"
624argv.py "${A[@]}"
625## STDOUT:
626['\\']
627['42']
628## END
629## BUG bash STDOUT:
630[]
631[]
632## END
633
634
635#### Implicit increment of keys
636declare -a arr=( [30]=a b [40]=x y)
637argv.py "${!arr[@]}"
638argv.py "${arr[@]}"
639
640# osh says "expected associative array pair"
641
642## STDOUT:
643['30', '31', '40', '41']
644['a', 'b', 'x', 'y']
645## END
646
647#### test -v assoc[key]
648
649typeset -A assoc
650assoc=([empty]='' [k]=v)
651
652echo 'no quotes'
653
654test -v assoc[empty]
655echo empty=$?
656
657test -v assoc[k]
658echo k=$?
659
660test -v assoc[nonexistent]
661echo nonexistent=$?
662
663echo
664
665# Now with quotes
666echo 'quotes'
667
668test -v assoc["empty"]
669echo empty=$?
670
671test -v assoc['k']
672echo k=$?
673
674test -v assoc['nonexistent']
675echo nonexistent=$?
676
677echo
678
679# dynamic parsing, this is gross
680echo 'vars'
681
682key=empty
683test -v 'assoc[$key]'
684echo empty=$?
685
686key=k
687test -v 'assoc[$key]'
688echo k=$?
689
690key=nonexistent
691test -v 'assoc[$key]'
692echo nonexistent=$?
693
694
695## STDOUT:
696no quotes
697empty=0
698k=0
699nonexistent=1
700
701quotes
702empty=0
703k=0
704nonexistent=1
705
706vars
707empty=0
708k=0
709nonexistent=1
710## END
711
712
713#### [[ -v assoc[key] ]]
714
715typeset -A assoc
716assoc=([empty]='' [k]=v)
717
718echo 'no quotes'
719
720[[ -v assoc[empty] ]]
721echo empty=$?
722
723[[ -v assoc[k] ]]
724echo k=$?
725
726[[ -v assoc[nonexistent] ]]
727echo nonexistent=$?
728
729echo
730
731# Now with quotes
732echo 'quotes'
733
734[[ -v assoc["empty"] ]]
735echo empty=$?
736
737[[ -v assoc['k'] ]]
738echo k=$?
739
740[[ -v assoc['nonexistent'] ]]
741echo nonexistent=$?
742
743echo
744
745echo 'vars'
746
747key=empty
748[[ -v assoc[$key] ]]
749echo empty=$?
750
751key=k
752[[ -v assoc[$key] ]]
753echo k=$?
754
755key=nonexistent
756[[ -v assoc[$key] ]]
757echo nonexistent=$?
758
759## STDOUT:
760no quotes
761empty=0
762k=0
763nonexistent=1
764
765quotes
766empty=0
767k=0
768nonexistent=1
769
770vars
771empty=0
772k=0
773nonexistent=1
774## END
775
776## N-I mksh status: 1
777## N-I mksh STDOUT:
778## END
779
780#### [[ -v assoc[key] ]] syntax errors
781
782typeset -A assoc
783assoc=([empty]='' [k]=v)
784
785[[ -v assoc[empty] ]]
786echo empty=$?
787
788[[ -v assoc[k] ]]
789echo k=$?
790
791[[ -v assoc[k]z ]]
792echo typo=$?
793
794## STDOUT:
795empty=0
796k=0
797typo=1
798## END