OILS / spec / ysh-options.test.sh View on Github | oils.pub

772 lines, 466 significant
1## oils_failures_allowed: 1
2
3# Test shell execution options.
4
5#### simple_word_eval doesn't split, glob, or elide empty
6mkdir mydir
7touch foo.z bar.z spam.z
8spaces='a b'
9dir=mydir
10glob=*.z
11prefix=sp
12set -- 'x y' z
13
14for i in 1 2; do
15 local empty=
16 argv.py $spaces $glob $empty $prefix*.z
17
18 # arrays still work too, with this weird rule
19 argv.py -"$@"-
20
21 shopt -s simple_word_eval
22done
23## STDOUT:
24['a', 'b', 'bar.z', 'foo.z', 'spam.z', 'spam.z']
25['-x y', 'z-']
26['a b', '*.z', '', 'spam.z']
27['-x y', 'z-']
28## END
29
30#### simple_word_eval and strict_array conflict over globs
31touch foo.txt bar.txt
32set -- f
33
34argv.py "$@"*.txt
35shopt -s simple_word_eval
36argv.py "$@"*.txt
37shopt -s strict_array
38argv.py "$@"*.txt
39
40## status: 1
41## STDOUT:
42['foo.txt']
43['foo.txt']
44## END
45
46#### simple_word_eval and glob
47shopt -s simple_word_eval
48
49# rm -v -f *.ff
50touch 1.ff 2.ff
51
52for i in *.ff; do
53 echo $i
54done
55
56array=(*.ff)
57echo "${array[@]}"
58
59echo *.ff
60
61## STDOUT:
621.ff
632.ff
641.ff 2.ff
651.ff 2.ff
66## END
67
68#### parse_at
69words=(a 'b c')
70argv.py @words
71
72shopt -s parse_at
73argv.py @words
74
75## STDOUT:
76['@words']
77['a', 'b c']
78## END
79
80#### DISABLED: parse_at can't be used outside top level
81
82# shopt -u expand_aliases conflicted with ble.sh, and it was also broken for
83# proc/func
84
85f() {
86 shopt -s parse_at
87 echo status=$?
88}
89f
90echo 'should not get here'
91## status: 1
92## stdout-json: ""
93
94
95#### sourcing a file that sets parse_at
96cat >lib.sh <<EOF
97shopt -s parse_at
98echo lib.sh
99EOF
100
101words=(a 'b c')
102argv.py @words
103
104# This has a side effect, which is a bit weird, but not sure how to avoid it.
105# Maybe we should say that libraries aren't allowed to change it?
106
107source lib.sh
108echo 'main.sh'
109
110argv.py @words
111## STDOUT:
112['@words']
113lib.sh
114main.sh
115['a', 'b c']
116## END
117
118#### parse_at can be specified through sh -O
119$SH +O parse_at -c 'words=(a "b c"); argv.py @words'
120$SH -O parse_at -c 'words=(a "b c"); argv.py @words'
121## STDOUT:
122['@words']
123['a', 'b c']
124## END
125
126#### @a splices into $0
127shopt -s simple_word_eval parse_at
128a=(echo hi)
129"${a[@]}"
130@a
131
132# Bug fix
133shopt -s strict_array
134
135"${a[@]}"
136@a
137## STDOUT:
138hi
139hi
140hi
141hi
142## END
143
144#### shopt -s strict:all
145shopt -s strict:all
146# normal option names
147shopt -o -p | grep -- ' -o ' | grep -v hashall
148shopt -p strict:all
149## STDOUT:
150shopt -s strict_argv
151shopt -s strict_arith
152shopt -s strict_array
153shopt -s strict_control_flow
154shopt -s strict_errexit
155shopt -s strict_glob
156shopt -s strict_nameref
157shopt -s strict_parse_slice
158shopt -s strict_tilde
159shopt -s strict_word_eval
160## END
161
162#### shopt -s ysh:upgrade
163shopt -s ysh:upgrade
164# normal option names
165shopt -o -p | grep -- ' -o ' | grep -v hashall
166shopt -p ysh:upgrade
167## STDOUT:
168set -o errexit
169set -o nounset
170set -o pipefail
171shopt -s command_sub_errexit
172shopt -u dashglob
173shopt -s env_obj
174shopt -s errexit
175shopt -s for_loop_frames
176shopt -s inherit_errexit
177shopt -s init_ysh_globals
178shopt -s nounset
179shopt -s nullglob
180shopt -s parse_at
181shopt -s parse_brace
182shopt -s parse_bracket
183shopt -s parse_equals
184shopt -s parse_func
185shopt -s parse_paren
186shopt -s parse_proc
187shopt -s parse_triple_quote
188shopt -s parse_ysh_string
189shopt -s pipefail
190shopt -s process_sub_fail
191shopt -s sigpipe_status_ok
192shopt -s simple_word_eval
193shopt -s verbose_errexit
194shopt -u xtrace_details
195shopt -s xtrace_rich
196## END
197
198#### osh -O oil:upgrade
199$SH -O oil:upgrade -c 'var x = %(one two three); write @x'
200## STDOUT:
201one
202two
203three
204## END
205
206#### osh -O errexit: use -O everywhere, even for Bourne options
207$SH -O errexit -c 'shopt -p -o errexit'
208#$SH -O errexit -c 'shopt -p errexit' # bash doesn't allow this, but Oil does
209## STDOUT:
210set -o errexit
211## END
212
213#### osh -O invalid
214$SH -O errexit -c 'echo hi'
215echo status=$?
216$SH -O invalid -c 'echo hi'
217echo status=$?
218## STDOUT:
219hi
220status=0
221status=2
222## END
223
224#### osh -o new_option is also accepted
225
226$SH -o nullglob -c 'echo nullglob'
227echo $? flag nullglob
228
229$SH -o oil:upgrade -c 'proc p { echo upgrade }; p'
230echo $? flag oil:upgrade
231
232# Should disallow these
233
234set -o nullglob
235echo $? set builtin nullglob
236set -o oil:upgrade
237echo $? set builtin oil:upgrade
238
239## STDOUT:
240nullglob
2410 flag nullglob
242upgrade
2430 flag oil:upgrade
2442 set builtin nullglob
2452 set builtin oil:upgrade
246## END
247
248
249#### oil:upgrade includes inherit_errexit
250shopt -s oil:upgrade
251echo $(echo one; false; echo two)
252## status: 1
253## stdout-json: ""
254
255#### parse_brace: bad block to assignment builtin
256shopt -s oil:upgrade
257# This is a fatal programming error. It's unlike passing an extra arg?
258local x=y { echo 'bad block' }
259echo status=$?
260## status: 1
261## stdout-json: ""
262
263#### parse_brace: bad block to external program
264shopt -s oil:upgrade
265# This is a fatal programming error. It's unlike passing an extra arg?
266ls { echo 'bad block' }
267echo status=$?
268## status: 1
269## stdout-json: ""
270
271#### parse_brace: cd { } in pipeline
272shopt -s oil:upgrade
273cd /tmp {
274 pwd
275 pwd
276} | tr a-z A-Z
277## STDOUT:
278/TMP
279/TMP
280## END
281
282
283#### parse_brace: if accepts blocks
284shopt -s oil:upgrade
285shopt -u errexit # don't need strict_errexit check!
286
287if test -n foo {
288 echo one
289}
290# harder
291if test -n foo; test -n bar {
292 echo two
293}
294
295# just like POSIX shell!
296if test -n foo;
297
298 test -n bar {
299 echo three
300}
301
302if test -z foo {
303 echo if
304} else {
305 echo else
306}
307
308if test -z foo {
309 echo if
310} elif test -z '' {
311 echo elif
312} else {
313 echo else
314}
315
316echo 'one line'
317if test -z foo { echo if } elif test -z '' { echo 1 }; if test -n foo { echo 2 };
318
319echo 'sh syntax'
320if test -z foo; then echo if; elif test -z ''; then echo 1; fi; if test -n foo { echo 2 };
321
322# NOTE: This is not allowed because it's like a brace group!
323# if test -n foo; {
324
325## STDOUT:
326one
327two
328three
329else
330elif
331one line
3321
3332
334sh syntax
3351
3362
337## END
338
339#### parse_brace: brace group in if condition
340
341# strict_errexit would make this a RUNTIME error
342shopt -s parse_brace
343if { echo one; echo two } {
344 echo three
345}
346## STDOUT:
347one
348two
349three
350## END
351
352#### parse_brace: while/until
353shopt -s oil:upgrade
354while true {
355 echo one
356 break
357}
358while true { echo two; break }
359
360echo 'sh syntax'
361while true; do echo three; break; done
362## STDOUT:
363one
364two
365sh syntax
366three
367## END
368
369#### parse_brace: for-in loop
370shopt -s oil:upgrade
371for x in one two {
372 echo $x
373}
374for x in three { echo $x }
375
376echo 'sh syntax'
377for x in four; do echo $x; done
378
379## STDOUT:
380one
381two
382three
383sh syntax
384four
385## END
386
387#### parse_brace case
388shopt -s ysh:upgrade
389
390var files = :| foo.py 'foo test.sh' |
391for name in (files) {
392 case $name in
393 *.py)
394 echo python
395 ;;
396 *.sh)
397 echo shell
398 ;;
399 esac
400}
401
402for name in @files {
403 case (name) {
404 *.py {
405 echo python
406 }
407 *.sh { echo shell }
408 }
409}
410
411## STDOUT:
412python
413shell
414python
415shell
416## END
417
418#### parse_paren: if statement
419shopt -s oil:upgrade
420var x = 1
421if (x < 42) {
422 echo less
423}
424
425if (x < 0) {
426 echo negative
427} elif (x < 42) {
428 echo less
429}
430
431if (x < 0) {
432 echo negative
433} elif (x < 1) {
434 echo less
435} else {
436 echo other
437}
438
439
440## STDOUT:
441less
442less
443other
444## END
445
446#### parse_paren: while statement
447shopt -s oil:upgrade
448
449# ksh style
450var x = 1
451while (( x < 3 )) {
452 echo $x
453 setvar x += 1
454}
455echo 'done ksh'
456
457# sh style
458var y = 1
459while test $y -lt 3 {
460 echo $y
461 setvar y += 1
462}
463echo 'done sh'
464
465# oil
466var z = 1
467while (z < 3) {
468 echo $z
469 setvar z += 1
470}
471echo 'done oil'
472
473## STDOUT:
4741
4752
476done ksh
4771
4782
479done sh
4801
4812
482done oil
483## END
484
485#### while subshell without parse_paren
486while ( echo one ); do
487 echo two
488 break
489done
490## STDOUT:
491one
492two
493## END
494
495#### nullglob is on with oil:upgrade
496write one *.zzz two
497shopt -s oil:upgrade
498write __
499write one *.zzz two
500## STDOUT:
501one
502*.zzz
503two
504__
505one
506two
507## END
508
509#### nullglob is on with oil:all
510write one *.zzz two
511shopt -s oil:all
512write __
513write one *.zzz two
514## STDOUT:
515one
516*.zzz
517two
518__
519one
520two
521## END
522
523#### shopt -s simple_echo
524foo='one two'
525echo $foo # bad split then join
526shopt -s simple_echo
527echo
528echo "$foo" # good
529echo $foo
530
531echo -e "$foo" # -e isn't special!
532echo -n "$foo" # -n isn't special!
533
534## STDOUT:
535one two
536
537one two
538one two
539-e one two
540-n one two
541## END
542
543#### shopt -s dashglob
544mkdir globdir
545cd globdir
546
547touch -- file -v
548
549argv.py *
550
551shopt -s oil:upgrade # turns OFF dashglob
552argv.py *
553
554shopt -s dashglob # turn it ON
555argv.py *
556
557## STDOUT:
558['-v', 'file']
559['file']
560['-v', 'file']
561## END
562
563#### shopt -s oil:upgrade turns some options on and others off
564show() {
565 shopt -p | egrep 'dashglob|simple_word_eval'
566}
567
568show
569echo ---
570
571shopt -s simple_word_eval
572show
573echo ---
574
575shopt -s oil:upgrade # strict_arith should still be on after this!
576show
577echo ---
578
579shopt -u oil:upgrade # strict_arith should still be on after this!
580show
581
582## STDOUT:
583shopt -s dashglob
584shopt -u simple_word_eval
585---
586shopt -s dashglob
587shopt -s simple_word_eval
588---
589shopt -u dashglob
590shopt -s simple_word_eval
591---
592shopt -s dashglob
593shopt -u simple_word_eval
594## END
595
596#### sigpipe_status_ok
597
598status_141() {
599 return 141
600}
601
602yes | head -n 1
603echo ${PIPESTATUS[@]}
604
605# DUMMY
606yes | status_141
607echo ${PIPESTATUS[@]}
608
609shopt --set oil:upgrade # sigpipe_status_ok
610shopt --unset errexit
611
612yes | head -n 1
613echo ${PIPESTATUS[@]}
614
615# Conveniently, the last 141 isn't changed to 0, because it's run in the
616# CURRENT process.
617
618yes | status_141
619echo ${PIPESTATUS[@]}
620
621echo background
622false | status_141 &
623wait
624echo status=$? pipestatus=${PIPESTATUS[@]}
625
626## STDOUT:
627y
628141 0
629141 141
630y
6310 0
6320 141
633background
634status=0 pipestatus=0 141
635## END
636
637
638#### printf | head regression (sigpipe_status_ok)
639
640shopt --set ysh:upgrade
641shopt --unset errexit
642
643bad() {
644 /usr/bin/printf '%65538s\n' foo | head -c 1
645 echo external on @_pipeline_status
646
647 shopt --unset sigpipe_status_ok {
648 /usr/bin/printf '%65538s\n' foo | head -c 1
649 }
650 echo external off @_pipeline_status
651
652 printf '%65538s\n' foo | head -c 1
653 echo builtin on @_pipeline_status
654
655 shopt --unset sigpipe_status_ok {
656 printf '%65538s\n' foo | head -c 1
657 }
658 echo builtin off @_pipeline_status
659}
660
661bad
662echo finished
663
664## STDOUT:
665 external on 0 0
666 external off 141 0
667 builtin on 0 0
668 builtin off 141 0
669finished
670## END
671
672#### redefine_proc is on in interactive shell
673
674$SH -O oil:all -i --rcfile /dev/null -c "
675source $REPO_ROOT/spec/testdata/module/common.ysh
676source $REPO_ROOT/spec/testdata/module/redefinition.ysh
677log hi
678"
679## STDOUT:
680common
681redefinition
682## END
683## STDERR:
684hi
685## END
686
687
688#### redefine_source is on in interactive shell
689
690$SH -O oil:all -i --rcfile /dev/null -c "
691source $REPO_ROOT/spec/testdata/module/common.ysh
692source $REPO_ROOT/spec/testdata/module/common.ysh
693log hi
694" 2>stderr.txt
695echo status=$?
696
697# Make sure there are two lines
698wc -l stderr.txt
699## STDOUT:
700common
701common
702status=0
7032 stderr.txt
704## END
705
706
707#### parse options in sourced file (bug #1628)
708
709set -e # catch errors
710
711alias e=echo
712shopt -u expand_aliases
713
714source $REPO_ROOT/spec/testdata/parse_opts.sh a b c
715
716echo OK
717
718# alias persists
719e alias on
720
721# parse_paren doesn't persist
722#if (x > 1) {
723# echo 'OK'
724#}
725
726FOO=bar source $REPO_ROOT/spec/testdata/parse_opts.sh
727echo OK
728
729
730## STDOUT:
731OK
732alias on
733OK
734## END
735
736#### expand_aliases turned off only in ysh:all
737
738alias e=echo
739e normal
740
741shopt -s ysh:upgrade
742e upgrade
743
744shopt -s ysh:all
745e all
746
747## status: 127
748## STDOUT:
749normal
750upgrade
751## END
752
753#### [[ isn't allowed in ysh
754[[ 3 == 3 ]]
755echo status=$?
756
757shopt -s ysh:upgrade
758[[ 3 == 3 ]]
759echo status=$?
760
761shopt -s ysh:all
762[[ 3 == 3 ]]
763echo status=$?
764
765[[ 0 == 0 ]]
766echo status=$?
767
768## status: 2
769## STDOUT:
770status=0
771status=0
772## END