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

774 lines, 468 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_equals
158shopt -s strict_parse_slice
159shopt -s strict_tilde
160shopt -s strict_word_eval
161## END
162
163#### shopt -s ysh:upgrade
164shopt -s ysh:upgrade
165# normal option names
166shopt -o -p | grep -- ' -o ' | grep -v hashall
167shopt -p ysh:upgrade
168## STDOUT:
169set -o errexit
170set -o nounset
171set -o pipefail
172shopt -s command_sub_errexit
173shopt -u dashglob
174shopt -s env_obj
175shopt -s errexit
176shopt -s for_loop_frames
177shopt -s inherit_errexit
178shopt -s init_ysh_globals
179shopt -s nounset
180shopt -s nullglob
181shopt -s parse_at
182shopt -s parse_brace
183shopt -s parse_bracket
184shopt -s parse_equals
185shopt -s parse_func
186shopt -s parse_paren
187shopt -s parse_proc
188shopt -s parse_triple_quote
189shopt -s parse_ysh_string
190shopt -s pipefail
191shopt -s process_sub_fail
192shopt -s sigpipe_status_ok
193shopt -s simple_word_eval
194shopt -s verbose_errexit
195shopt -s verbose_warn
196shopt -u xtrace_details
197shopt -s xtrace_rich
198## END
199
200#### osh -O ysh:upgrade
201$SH -O ysh:upgrade -c 'var x = :|one two three|; write @x'
202## STDOUT:
203one
204two
205three
206## END
207
208#### osh -O errexit: use -O everywhere, even for Bourne options
209$SH -O errexit -c 'shopt -p -o errexit'
210#$SH -O errexit -c 'shopt -p errexit' # bash doesn't allow this, but Oil does
211## STDOUT:
212set -o errexit
213## END
214
215#### osh -O invalid
216$SH -O errexit -c 'echo hi'
217echo status=$?
218$SH -O invalid -c 'echo hi'
219echo status=$?
220## STDOUT:
221hi
222status=0
223status=2
224## END
225
226#### osh -o new_option is also accepted
227
228$SH -o nullglob -c 'echo nullglob'
229echo $? flag nullglob
230
231$SH -o oil:upgrade -c 'proc p { echo upgrade }; p'
232echo $? flag oil:upgrade
233
234# Should disallow these
235
236set -o nullglob
237echo $? set builtin nullglob
238set -o oil:upgrade
239echo $? set builtin oil:upgrade
240
241## STDOUT:
242nullglob
2430 flag nullglob
244upgrade
2450 flag oil:upgrade
2462 set builtin nullglob
2472 set builtin oil:upgrade
248## END
249
250
251#### oil:upgrade includes inherit_errexit
252shopt -s oil:upgrade
253echo $(echo one; false; echo two)
254## status: 1
255## stdout-json: ""
256
257#### parse_brace: bad block to assignment builtin
258shopt -s oil:upgrade
259# This is a fatal programming error. It's unlike passing an extra arg?
260local x=y { echo 'bad block' }
261echo status=$?
262## status: 1
263## stdout-json: ""
264
265#### parse_brace: bad block to external program
266shopt -s oil:upgrade
267# This is a fatal programming error. It's unlike passing an extra arg?
268ls { echo 'bad block' }
269echo status=$?
270## status: 1
271## stdout-json: ""
272
273#### parse_brace: cd { } in pipeline
274shopt -s oil:upgrade
275cd /tmp {
276 pwd
277 pwd
278} | tr a-z A-Z
279## STDOUT:
280/TMP
281/TMP
282## END
283
284
285#### parse_brace: if accepts blocks
286shopt -s oil:upgrade
287shopt -u errexit # don't need strict_errexit check!
288
289if test -n foo {
290 echo one
291}
292# harder
293if test -n foo; test -n bar {
294 echo two
295}
296
297# just like POSIX shell!
298if test -n foo;
299
300 test -n bar {
301 echo three
302}
303
304if test -z foo {
305 echo if
306} else {
307 echo else
308}
309
310if test -z foo {
311 echo if
312} elif test -z '' {
313 echo elif
314} else {
315 echo else
316}
317
318echo 'one line'
319if test -z foo { echo if } elif test -z '' { echo 1 }; if test -n foo { echo 2 };
320
321echo 'sh syntax'
322if test -z foo; then echo if; elif test -z ''; then echo 1; fi; if test -n foo { echo 2 };
323
324# NOTE: This is not allowed because it's like a brace group!
325# if test -n foo; {
326
327## STDOUT:
328one
329two
330three
331else
332elif
333one line
3341
3352
336sh syntax
3371
3382
339## END
340
341#### parse_brace: brace group in if condition
342
343# strict_errexit would make this a RUNTIME error
344shopt -s parse_brace
345if { echo one; echo two } {
346 echo three
347}
348## STDOUT:
349one
350two
351three
352## END
353
354#### parse_brace: while/until
355shopt -s oil:upgrade
356while true {
357 echo one
358 break
359}
360while true { echo two; break }
361
362echo 'sh syntax'
363while true; do echo three; break; done
364## STDOUT:
365one
366two
367sh syntax
368three
369## END
370
371#### parse_brace: for-in loop
372shopt -s oil:upgrade
373for x in one two {
374 echo $x
375}
376for x in three { echo $x }
377
378echo 'sh syntax'
379for x in four; do echo $x; done
380
381## STDOUT:
382one
383two
384three
385sh syntax
386four
387## END
388
389#### parse_brace case
390shopt -s ysh:upgrade
391
392var files = :| foo.py 'foo test.sh' |
393for name in (files) {
394 case $name in
395 *.py)
396 echo python
397 ;;
398 *.sh)
399 echo shell
400 ;;
401 esac
402}
403
404for name in @files {
405 case (name) {
406 *.py {
407 echo python
408 }
409 *.sh { echo shell }
410 }
411}
412
413## STDOUT:
414python
415shell
416python
417shell
418## END
419
420#### parse_paren: if statement
421shopt -s oil:upgrade
422var x = 1
423if (x < 42) {
424 echo less
425}
426
427if (x < 0) {
428 echo negative
429} elif (x < 42) {
430 echo less
431}
432
433if (x < 0) {
434 echo negative
435} elif (x < 1) {
436 echo less
437} else {
438 echo other
439}
440
441
442## STDOUT:
443less
444less
445other
446## END
447
448#### parse_paren: while statement
449shopt -s oil:upgrade
450
451# ksh style
452var x = 1
453while (( x < 3 )) {
454 echo $x
455 setvar x += 1
456}
457echo 'done ksh'
458
459# sh style
460var y = 1
461while test $y -lt 3 {
462 echo $y
463 setvar y += 1
464}
465echo 'done sh'
466
467# oil
468var z = 1
469while (z < 3) {
470 echo $z
471 setvar z += 1
472}
473echo 'done oil'
474
475## STDOUT:
4761
4772
478done ksh
4791
4802
481done sh
4821
4832
484done oil
485## END
486
487#### while subshell without parse_paren
488while ( echo one ); do
489 echo two
490 break
491done
492## STDOUT:
493one
494two
495## END
496
497#### nullglob is on with oil:upgrade
498write one *.zzz two
499shopt -s oil:upgrade
500write __
501write one *.zzz two
502## STDOUT:
503one
504*.zzz
505two
506__
507one
508two
509## END
510
511#### nullglob is on with oil:all
512write one *.zzz two
513shopt -s oil:all
514write __
515write one *.zzz two
516## STDOUT:
517one
518*.zzz
519two
520__
521one
522two
523## END
524
525#### shopt -s simple_echo
526foo='one two'
527echo $foo # bad split then join
528shopt -s simple_echo
529echo
530echo "$foo" # good
531echo $foo
532
533echo -e "$foo" # -e isn't special!
534echo -n "$foo" # -n isn't special!
535
536## STDOUT:
537one two
538
539one two
540one two
541-e one two
542-n one two
543## END
544
545#### shopt -s dashglob
546mkdir globdir
547cd globdir
548
549touch -- file -v
550
551argv.py *
552
553shopt -s oil:upgrade # turns OFF dashglob
554argv.py *
555
556shopt -s dashglob # turn it ON
557argv.py *
558
559## STDOUT:
560['-v', 'file']
561['file']
562['-v', 'file']
563## END
564
565#### shopt -s oil:upgrade turns some options on and others off
566show() {
567 shopt -p | egrep 'dashglob|simple_word_eval'
568}
569
570show
571echo ---
572
573shopt -s simple_word_eval
574show
575echo ---
576
577shopt -s oil:upgrade # strict_arith should still be on after this!
578show
579echo ---
580
581shopt -u oil:upgrade # strict_arith should still be on after this!
582show
583
584## STDOUT:
585shopt -s dashglob
586shopt -u simple_word_eval
587---
588shopt -s dashglob
589shopt -s simple_word_eval
590---
591shopt -u dashglob
592shopt -s simple_word_eval
593---
594shopt -s dashglob
595shopt -u simple_word_eval
596## END
597
598#### sigpipe_status_ok
599
600status_141() {
601 return 141
602}
603
604yes | head -n 1
605echo ${PIPESTATUS[@]}
606
607# DUMMY
608yes | status_141
609echo ${PIPESTATUS[@]}
610
611shopt --set oil:upgrade # sigpipe_status_ok
612shopt --unset errexit
613
614yes | head -n 1
615echo ${PIPESTATUS[@]}
616
617# Conveniently, the last 141 isn't changed to 0, because it's run in the
618# CURRENT process.
619
620yes | status_141
621echo ${PIPESTATUS[@]}
622
623echo background
624false | status_141 &
625wait
626echo status=$? pipestatus=${PIPESTATUS[@]}
627
628## STDOUT:
629y
630141 0
631141 141
632y
6330 0
6340 141
635background
636status=0 pipestatus=0 141
637## END
638
639
640#### printf | head regression (sigpipe_status_ok)
641
642shopt --set ysh:upgrade
643shopt --unset errexit
644
645bad() {
646 /usr/bin/printf '%65538s\n' foo | head -c 1
647 echo external on @_pipeline_status
648
649 shopt --unset sigpipe_status_ok {
650 /usr/bin/printf '%65538s\n' foo | head -c 1
651 }
652 echo external off @_pipeline_status
653
654 printf '%65538s\n' foo | head -c 1
655 echo builtin on @_pipeline_status
656
657 shopt --unset sigpipe_status_ok {
658 printf '%65538s\n' foo | head -c 1
659 }
660 echo builtin off @_pipeline_status
661}
662
663bad
664echo finished
665
666## STDOUT:
667 external on 0 0
668 external off 141 0
669 builtin on 0 0
670 builtin off 141 0
671finished
672## END
673
674#### redefine_proc is on in interactive shell
675
676$SH -O oil:all -i --rcfile /dev/null -c "
677source $REPO_ROOT/spec/testdata/module/common.ysh
678source $REPO_ROOT/spec/testdata/module/redefinition.ysh
679log hi
680"
681## STDOUT:
682common
683redefinition
684## END
685## STDERR:
686hi
687## END
688
689
690#### redefine_source is on in interactive shell
691
692$SH -O oil:all -i --rcfile /dev/null -c "
693source $REPO_ROOT/spec/testdata/module/common.ysh
694source $REPO_ROOT/spec/testdata/module/common.ysh
695log hi
696" 2>stderr.txt
697echo status=$?
698
699# Make sure there are two lines
700wc -l stderr.txt
701## STDOUT:
702common
703common
704status=0
7052 stderr.txt
706## END
707
708
709#### parse options in sourced file (bug #1628)
710
711set -e # catch errors
712
713alias e=echo
714shopt -u expand_aliases
715
716source $REPO_ROOT/spec/testdata/parse_opts.sh a b c
717
718echo OK
719
720# alias persists
721e alias on
722
723# parse_paren doesn't persist
724#if (x > 1) {
725# echo 'OK'
726#}
727
728FOO=bar source $REPO_ROOT/spec/testdata/parse_opts.sh
729echo OK
730
731
732## STDOUT:
733OK
734alias on
735OK
736## END
737
738#### expand_aliases turned off only in ysh:all
739
740alias e=echo
741e normal
742
743shopt -s ysh:upgrade
744e upgrade
745
746shopt -s ysh:all
747e all
748
749## status: 127
750## STDOUT:
751normal
752upgrade
753## END
754
755#### [[ isn't allowed in ysh
756[[ 3 == 3 ]]
757echo status=$?
758
759shopt -s ysh:upgrade
760[[ 3 == 3 ]]
761echo status=$?
762
763shopt -s ysh:all
764[[ 3 == 3 ]]
765echo status=$?
766
767[[ 0 == 0 ]]
768echo status=$?
769
770## status: 2
771## STDOUT:
772status=0
773status=0
774## END