1 # spec/append.test.sh: Test +=
2
3 ## compare_shells: bash mksh zsh
4
5 #### Append string to string
6 s='abc'
7 s+=d
8 echo $s
9 ## stdout: abcd
10
11 #### Append array to array
12 a=(x y )
13 a+=(t 'u v')
14 argv.py "${a[@]}"
15 ## stdout: ['x', 'y', 't', 'u v']
16
17 #### Append string to undefined variable
18
19 s+=foo
20 echo s=$s
21
22 # bash and mksh agree that this does NOT respect set -u.
23 # I think that's a mistake, but += is a legacy construct, so let's copy it.
24
25 set -u
26
27 t+=foo
28 echo t=$t
29 t+=foo
30 echo t=$t
31 ## STDOUT:
32 s=foo
33 t=foo
34 t=foofoo
35 ## END
36
37 #### Append to array to undefined variable
38
39 # I wonder if Oil should have accumulators:
40 # auto y += %(c d) or something
41
42 y+=(c d)
43 argv.py "${y[@]}"
44 ## STDOUT:
45 ['c', 'd']
46 ## END
47
48 #### error: s+=(my array)
49 s='abc'
50 s+=(d e f)
51 argv.py "${s[@]}"
52 ## status: 0
53 ## STDOUT:
54 ['abc', 'd', 'e', 'f']
55 ## END
56
57 #### error: myarray+=s
58
59 # They treat this as implicit index 0. We disallow this on the LHS, so we will
60 # also disallow it on the RHS.
61 a=(x y )
62 a+=z
63 argv.py "${a[@]}"
64 ## status: 1
65 ## stdout-json: ""
66 ## OK bash/mksh status: 0
67 ## OK bash/mksh stdout: ['xz', 'y']
68 ## OK zsh status: 0
69 ## OK zsh stdout: ['x', 'y', 'z']
70
71 #### typeset s+=(my array)
72 typeset s='abc'
73 echo $s
74
75 typeset s+=(d e f)
76 echo status=$?
77 argv.py "${s[@]}"
78
79 ## status: 0
80 ## STDOUT:
81 abc
82 status=0
83 ['abc', 'd', 'e', 'f']
84 ## END
85 ## N-I mksh/zsh status: 1
86 ## N-I mksh/zsh stdout: abc
87 ## N-I mksh stderr: mksh: <stdin>[4]: syntax error: '(' unexpected
88 ## N-I zsh stderr: typeset: not valid in this context: s+
89
90 #### error: typeset myarray+=s
91 typeset a=(x y)
92 argv.py "${a[@]}"
93 typeset a+=s
94 argv.py "${a[@]}"
95
96 ## status: 1
97 ## STDOUT:
98 ['x', 'y']
99 ## END
100 ## BUG bash status: 0
101 ## BUG bash STDOUT:
102 ['x', 'y']
103 ['xs', 'y']
104 ## END
105 ## N-I mksh STDOUT:
106 ## END
107
108 #### error: append used like env prefix
109 # This should be an error in other shells but it's not.
110 A=a
111 A+=a printenv.py A
112 ## status: 2
113 ## BUG bash/zsh status: 0
114 ## BUG bash/zsh stdout: aa
115 ## BUG mksh status: 0
116 ## BUG mksh stdout: a
117
118 #### myarray[1]+=s - Append to element
119 # They treat this as implicit index 0. We disallow this on the LHS, so we will
120 # also disallow it on the RHS.
121 a=(x y )
122 a[1]+=z
123 argv.py "${a[@]}"
124 ## status: 0
125 ## stdout: ['x', 'yz']
126 ## BUG zsh stdout: ['xz', 'y']
127
128 #### myarray[-1]+=s - Append to last element
129 # Works in bash, but not mksh. It seems like bash is doing the right thing.
130 # a[-1] is allowed on the LHS. mksh doesn't have negative indexing?
131 a=(1 '2 3')
132 a[-1]+=' 4'
133 argv.py "${a[@]}"
134 ## stdout: ['1', '2 3 4']
135 ## BUG mksh stdout: ['1', '2 3', ' 4']
136
137 #### Try to append list to element
138 # bash - runtime error: cannot assign list to array number
139 # mksh - a[-1]+: is not an identifier
140 # osh - parse error -- could be better!
141 a=(1 '2 3')
142 a[-1]+=(4 5)
143 argv.py "${a[@]}"
144
145 ## stdout-json: ""
146 ## status: 2
147
148 ## OK bash status: 0
149 ## OK bash STDOUT:
150 ['1', '2 3']
151 ## END
152
153 ## OK zsh status: 0
154 ## OK zsh STDOUT:
155 ['1', '2 3', '4', '5']
156 ## END
157
158 ## N-I mksh status: 1
159
160 #### Strings have value semantics, not reference semantics
161 s1='abc'
162 s2=$s1
163 s1+='d'
164 echo $s1 $s2
165 ## stdout: abcd abc
166
167 #### typeset s+=
168
169 typeset s+=foo
170 echo s=$s
171
172 # bash and mksh agree that this does NOT respect set -u.
173 # I think that's a mistake, but += is a legacy construct, so let's copy it.
174
175 set -u
176
177 typeset t+=foo
178 echo t=$t
179 typeset t+=foo
180 echo t=$t
181 ## STDOUT:
182 s=foo
183 t=foo
184 t=foofoo
185 ## END
186 ## N-I zsh status: 1
187 ## N-I zsh stdout-json: ""
188
189 #### typeset s${dyn}+=
190
191 dyn=x
192
193 typeset s${dyn}+=foo
194 echo sx=$sx
195
196 # bash and mksh agree that this does NOT respect set -u.
197 # I think that's a mistake, but += is a legacy construct, so let's copy it.
198
199 set -u
200
201 typeset t${dyn}+=foo
202 echo tx=$tx
203 typeset t${dyn}+=foo
204 echo tx=$tx
205 ## STDOUT:
206 sx=foo
207 tx=foo
208 tx=foofoo
209 ## END
210 ## N-I zsh status: 1
211 ## N-I zsh stdout-json: ""
212
213 #### export readonly +=
214
215 export e+=foo
216 echo e=$e
217
218 readonly r+=bar
219 echo r=$r
220
221 set -u
222
223 export e+=foo
224 echo e=$e
225
226 #readonly r+=foo
227 #echo r=$e
228
229 ## STDOUT:
230 e=foo
231 r=bar
232 e=foofoo
233 ## END
234 ## N-I zsh status: 1
235 ## N-I zsh stdout-json: ""
236
237 #### local +=
238
239 f() {
240 local s+=foo
241 echo s=$s
242
243 set -u
244 local s+=foo
245 echo s=$s
246 }
247
248 f
249 ## STDOUT:
250 s=foo
251 s=foofoo
252 ## END
253 ## N-I zsh status: 1
254 ## N-I zsh stdout-json: ""
255
256 #### assign builtin appending array: declare d+=(d e)
257
258 declare d+=(d e)
259 echo "${d[@]}"
260 declare d+=(c l)
261 echo "${d[@]}"
262
263 readonly r+=(r e)
264 echo "${r[@]}"
265 # can't do this again
266
267 f() {
268 local l+=(l o)
269 echo "${l[@]}"
270
271 local l+=(c a)
272 echo "${l[@]}"
273 }
274
275 f
276
277 ## STDOUT:
278 d e
279 d e c l
280 r e
281 l o
282 l o c a
283 ## END
284 ## N-I mksh status: 1
285 ## N-I mksh stdout-json: ""
286 ## N-I zsh status: 1
287 ## N-I zsh stdout-json: ""
288
289 #### export+=array disallowed (strict_array)
290 shopt -s strict_array
291
292 export e+=(e x)
293 echo "${e[@]}"
294
295 ## status: 1
296 ## STDOUT:
297 ## END
298 ## N-I bash status: 0
299 ## N-I bash STDOUT:
300 e x
301 ## END
302
303
304 #### Type mismatching of lhs+=rhs should not cause a crash
305 case $SH in mksh|zsh) exit ;; esac
306 s=
307 a=()
308 declare -A d=([lemon]=yellow)
309
310 s+=(1)
311 s+=([melon]=green)
312
313 a+=lime
314 a+=([1]=banana)
315
316 d+=orange
317 d+=(0)
318
319 true
320
321 ## STDOUT:
322 ## END
323
324 ## OK osh status: 1
325
326 ## N-I mksh/zsh STDOUT:
327 ## END