OILS / spec / var-op-slice.test.sh View on Github | oilshell.org

405 lines, 218 significant
1# Test combination of var ops.
2#
3# NOTE: There are also slice tests in {array,arith-context}.test.sh.
4
5## oils_failures_allowed: 1
6## compare_shells: bash mksh zsh
7
8
9#### String slice
10foo=abcdefg
11echo ${foo:1:3}
12## STDOUT:
13bcd
14## END
15
16#### Cannot take length of substring slice
17# These are runtime errors, but we could make them parse time errors.
18v=abcde
19echo ${#v:1:3}
20## status: 1
21## OK osh status: 2
22# zsh actually implements this!
23## OK zsh stdout: 3
24## OK zsh status: 0
25
26#### Out of range string slice: begin
27# out of range begin doesn't raise error in bash, but in mksh it skips the
28# whole thing!
29foo=abcdefg
30echo _${foo:100:3}
31echo $?
32## STDOUT:
33_
340
35## END
36## BUG mksh stdout-json: "\n0\n"
37
38#### Out of range string slice: length
39# OK in both bash and mksh
40foo=abcdefg
41echo _${foo:3:100}
42echo $?
43## STDOUT:
44_defg
450
46## END
47## BUG mksh stdout-json: "_defg\n0\n"
48
49#### Negative start index
50foo=abcdefg
51echo ${foo: -4:3}
52## stdout: def
53
54#### Negative start index respects unicode
55foo=abcd-μ-
56echo ${foo: -4:3}
57## stdout: d-μ
58## BUG mksh stdout: -μ
59
60#### Negative second arg is position, not length!
61foo=abcdefg
62echo ${foo:3:-1} ${foo: 3: -2} ${foo:3 :-3 }
63## stdout: def de d
64## BUG mksh stdout: defg defg defg
65
66#### Negative start index respects unicode
67foo=abcd-μ-
68echo ${foo: -5: -3}
69## stdout: cd
70## BUG mksh stdout: d-μ-
71
72#### String slice with math
73# I think this is the $(()) language inside?
74i=1
75foo=abcdefg
76echo ${foo: i+4-2 : i + 2}
77## stdout: def
78
79#### Slice undefined
80echo -${undef:1:2}-
81set -o nounset
82echo -${undef:1:2}-
83echo -done-
84## STDOUT:
85--
86## END
87## status: 1
88# mksh doesn't respect nounset!
89## BUG mksh status: 0
90## BUG mksh STDOUT:
91--
92--
93-done-
94## END
95
96#### Slice UTF-8 String
97# mksh slices by bytes.
98foo='--μ--'
99echo ${foo:1:3}
100## stdout: -μ-
101## BUG mksh stdout: -μ
102
103#### Slice string with invalid UTF-8 results in empty string and warning
104s=$(echo -e "\xFF")bcdef
105echo -${s:1:3}-
106## status: 0
107## STDOUT:
108--
109## END
110## STDERR:
111[??? no location ???] warning: UTF-8 decode: Bad encoding at offset 0 in string of 6 bytes
112## END
113## BUG bash/mksh/zsh status: 0
114## BUG bash/mksh/zsh STDOUT:
115-bcd-
116## END
117## BUG bash/mksh/zsh stderr-json: ""
118
119
120#### Slice string with invalid UTF-8 with strict_word_eval
121shopt -s strict_word_eval || true
122echo slice
123s=$(echo -e "\xFF")bcdef
124echo -${s:1:3}-
125## status: 1
126## STDOUT:
127slice
128## END
129## N-I bash/mksh/zsh status: 0
130## N-I bash/mksh/zsh STDOUT:
131slice
132-bcd-
133## END
134
135#### Slice with an index that's an array -- silent a[0] decay
136i=(3 4 5)
137mystr=abcdefg
138echo assigned
139echo ${mystr:$i:2}
140
141## status: 0
142## STDOUT:
143assigned
144de
145## END
146## OK zsh status: 1
147## OK zsh STDOUT:
148assigned
149## END
150
151#### Slice with an assoc array
152declare -A A=(['5']=3 ['6']=4)
153mystr=abcdefg
154echo assigned
155echo ${mystr:$A:2}
156
157## status: 0
158## STDOUT:
159assigned
160ab
161## END
162
163## N-I mksh status: 1
164## N-I mksh stdout-json: ""
165
166#### Simple ${@:offset}
167
168set -- 4 5 6
169
170result=$(argv.py ${@:0})
171echo ${result//"$0"/'SHELL'}
172
173argv.py ${@:1}
174argv.py ${@:2}
175
176## STDOUT:
177['SHELL', '4', '5', '6']
178['4', '5', '6']
179['5', '6']
180## END
181## N-I mksh status: 1
182## N-I mksh stdout-json: "\n"
183
184
185#### ${@:offset} and ${*:offset}
186case $SH in (zsh) return ;; esac # zsh is very different
187
188argv.shell-name-checked () {
189 argv.py "${@//$0/SHELL}"
190}
191fun() {
192 argv.shell-name-checked -${*:0}- # include $0
193 argv.shell-name-checked -${*:1}- # from $1
194 argv.shell-name-checked -${*:3}- # last parameter $3
195 argv.shell-name-checked -${*:4}- # empty
196 argv.shell-name-checked -${*:5}- # out of boundary
197 argv.shell-name-checked -${@:0}-
198 argv.shell-name-checked -${@:1}-
199 argv.shell-name-checked -${@:3}-
200 argv.shell-name-checked -${@:4}-
201 argv.shell-name-checked -${@:5}-
202 argv.shell-name-checked "-${*:0}-"
203 argv.shell-name-checked "-${*:1}-"
204 argv.shell-name-checked "-${*:3}-"
205 argv.shell-name-checked "-${*:4}-"
206 argv.shell-name-checked "-${*:5}-"
207 argv.shell-name-checked "-${@:0}-"
208 argv.shell-name-checked "-${@:1}-"
209 argv.shell-name-checked "-${@:3}-"
210 argv.shell-name-checked "-${@:4}-"
211 argv.shell-name-checked "-${@:5}-"
212}
213fun "a 1" "b 2" "c 3"
214## STDOUT:
215['-SHELL', 'a', '1', 'b', '2', 'c', '3-']
216['-a', '1', 'b', '2', 'c', '3-']
217['-c', '3-']
218['--']
219['--']
220['-SHELL', 'a', '1', 'b', '2', 'c', '3-']
221['-a', '1', 'b', '2', 'c', '3-']
222['-c', '3-']
223['--']
224['--']
225['-SHELL a 1 b 2 c 3-']
226['-a 1 b 2 c 3-']
227['-c 3-']
228['--']
229['--']
230['-SHELL', 'a 1', 'b 2', 'c 3-']
231['-a 1', 'b 2', 'c 3-']
232['-c 3-']
233['--']
234['--']
235## END
236## N-I mksh status: 1
237## N-I mksh stdout-json: ""
238## BUG zsh stdout-json: ""
239
240#### ${@:offset:length} and ${*:offset:length}
241case $SH in (zsh) return ;; esac # zsh is very different
242
243argv.shell-name-checked () {
244 argv.py "${@//$0/SHELL}"
245}
246fun() {
247 argv.shell-name-checked -${*:0:2}- # include $0
248 argv.shell-name-checked -${*:1:2}- # from $1
249 argv.shell-name-checked -${*:3:2}- # last parameter $3
250 argv.shell-name-checked -${*:4:2}- # empty
251 argv.shell-name-checked -${*:5:2}- # out of boundary
252 argv.shell-name-checked -${@:0:2}-
253 argv.shell-name-checked -${@:1:2}-
254 argv.shell-name-checked -${@:3:2}-
255 argv.shell-name-checked -${@:4:2}-
256 argv.shell-name-checked -${@:5:2}-
257 argv.shell-name-checked "-${*:0:2}-"
258 argv.shell-name-checked "-${*:1:2}-"
259 argv.shell-name-checked "-${*:3:2}-"
260 argv.shell-name-checked "-${*:4:2}-"
261 argv.shell-name-checked "-${*:5:2}-"
262 argv.shell-name-checked "-${@:0:2}-"
263 argv.shell-name-checked "-${@:1:2}-"
264 argv.shell-name-checked "-${@:3:2}-"
265 argv.shell-name-checked "-${@:4:2}-"
266 argv.shell-name-checked "-${@:5:2}-"
267}
268fun "a 1" "b 2" "c 3"
269## STDOUT:
270['-SHELL', 'a', '1-']
271['-a', '1', 'b', '2-']
272['-c', '3-']
273['--']
274['--']
275['-SHELL', 'a', '1-']
276['-a', '1', 'b', '2-']
277['-c', '3-']
278['--']
279['--']
280['-SHELL a 1-']
281['-a 1 b 2-']
282['-c 3-']
283['--']
284['--']
285['-SHELL', 'a 1-']
286['-a 1', 'b 2-']
287['-c 3-']
288['--']
289['--']
290## END
291## N-I mksh status: 1
292## N-I mksh stdout-json: ""
293## BUG zsh stdout-json: ""
294
295#### ${@:0:1}
296set a b c
297result=$(echo ${@:0:1})
298echo ${result//"$0"/'SHELL'}
299## STDOUT:
300SHELL
301## END
302## N-I mksh stdout-json: "\n"
303
304#### Permutations of implicit begin and length
305array=(1 2 3)
306
307argv.py ${array[@]}
308
309# *** implicit length of N **
310argv.py ${array[@]:0}
311
312# Why is this one not allowed
313#argv.py ${array[@]:}
314
315# ** implicit length of ZERO **
316#argv.py ${array[@]::}
317#argv.py ${array[@]:0:}
318
319argv.py ${array[@]:0:0}
320echo
321
322# Same agreed upon permutations
323set -- 1 2 3
324argv.py ${@}
325argv.py ${@:1}
326argv.py ${@:1:0}
327echo
328
329s='123'
330argv.py "${s}"
331argv.py "${s:0}"
332argv.py "${s:0:0}"
333
334## STDOUT:
335['1', '2', '3']
336['1', '2', '3']
337[]
338
339['1', '2', '3']
340['1', '2', '3']
341[]
342
343['123']
344['123']
345['']
346## END
347
348## BUG mksh status: 1
349## BUG mksh STDOUT:
350['1', '2', '3']
351## END
352
353#### ${array[@]:} vs ${array[@]: } - bash and zsh inconsistent
354
355$SH -c 'array=(1 2 3); argv.py ${array[@]:}'
356$SH -c 'array=(1 2 3); argv.py space ${array[@]: }'
357
358$SH -c 's=123; argv.py ${s:}'
359$SH -c 's=123; argv.py space ${s: }'
360
361## STDOUT:
362['space', '1', '2', '3']
363['space', '123']
364## END
365
366## OK osh STDOUT:
367['1', '2', '3']
368['space', '1', '2', '3']
369['123']
370['space', '123']
371## END
372
373## BUG mksh STDOUT:
374['space', '123']
375## END
376
377#### ${array[@]::} has implicit length of zero - for ble.sh
378
379# https://oilshell.zulipchat.com/#narrow/stream/121540-oil-discuss/topic/.24.7Barr.5B.40.5D.3A.3A.7D.20in.20bash.20-.20is.20it.20documented.3F
380
381array=(1 2 3)
382argv.py ${array[@]::}
383argv.py ${array[@]:0:}
384
385echo
386
387set -- 1 2 3
388argv.py ${@::}
389argv.py ${@:0:}
390
391## status: 0
392## STDOUT:
393
394## status: 0
395## STDOUT:
396[]
397[]
398
399[]
400[]
401## END
402
403## OK mksh/zsh status: 1
404## OK mksh/zsh STDOUT:
405## END