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

971 lines, 652 significant
1#!/usr/bin/env bash
2#
3# Usage:
4# test/spec.sh <function name>
5
6set -o nounset
7set -o pipefail
8set -o errexit
9shopt -s strict:all 2>/dev/null || true # dogfood for OSH
10
11REPO_ROOT=$(cd "$(dirname $0)/.."; pwd)
12
13source test/common.sh
14source test/spec-common.sh
15source devtools/run-task.sh
16
17if test -z "${IN_NIX_SHELL:-}"; then
18 source build/dev-shell.sh # to run 'dash', etc.
19fi
20
21# TODO: Just use 'dash bash' and $PATH
22readonly DASH=dash
23readonly BASH=bash
24readonly MKSH=mksh
25readonly ZSH=zsh
26readonly BUSYBOX_ASH=ash
27
28# ash and dash are similar, so not including ash by default. zsh is not quite
29# POSIX.
30readonly REF_SHELLS=($DASH $BASH $MKSH)
31
32check-survey-shells() {
33 ### Make sure bash, zsh, OSH, etc. exist
34
35 # Note: yash isn't here, but it is used in a couple tests
36
37 test/spec-runner.sh shell-sanity-check "${REF_SHELLS[@]}" $ZSH $BUSYBOX_ASH $OSH_LIST
38}
39
40# TODO: remove this stub after we hollow out this file
41
42run-file() { test/spec-py.sh run-file "$@"; }
43
44#
45# Misc
46#
47
48# Really what I want is enter(func) and exit(func), and filter by regex?
49trace-var-sub() {
50 local out=_tmp/coverage
51 mkdir -p $out
52
53 # This creates *.cover files, with line counts.
54 #python -m trace --count -C $out \
55
56 # This prints trace with line numbers to stdout.
57 #python -m trace --trace -C $out \
58 PYTHONPATH=. python -m trace --trackcalls -C $out \
59 test/sh_spec.py spec/var-sub.test.sh $DASH $BASH "$@"
60
61 ls -l $out
62 head $out/*.cover
63}
64
65#
66# Individual tests.
67#
68# We configure the shells they run on and the number of allowed failures (to
69# prevent regressions.)
70#
71
72interactive-parse() {
73 run-file interactive-parse "$@"
74}
75
76smoke() {
77 run-file smoke "$@"
78}
79
80interactive() {
81 run-file interactive "$@"
82}
83
84prompt() {
85 run-file prompt "$@"
86}
87
88bugs() {
89 run-file bugs "$@"
90}
91
92TODO-deprecate() {
93 run-file TODO-deprecate "$@"
94}
95
96blog1() {
97 sh-spec spec/blog1.test.sh \
98 ${REF_SHELLS[@]} $ZSH $OSH_LIST "$@"
99}
100
101blog2() {
102 run-file blog2 "$@"
103}
104
105blog-other1() {
106 sh-spec spec/blog-other1.test.sh \
107 ${REF_SHELLS[@]} $ZSH $OSH_LIST "$@"
108}
109
110alias() {
111 run-file alias "$@"
112}
113
114comments() {
115 sh-spec spec/comments.test.sh ${REF_SHELLS[@]} $OSH_LIST "$@"
116}
117
118word-split() {
119 run-file word-split "$@"
120}
121
122word-eval() {
123 sh-spec spec/word-eval.test.sh \
124 ${REF_SHELLS[@]} $OSH_LIST "$@"
125}
126
127# These cases apply to many shells.
128assign() {
129 run-file assign "$@"
130}
131
132# These cases apply to a few shells.
133assign-extended() {
134 run-file assign-extended "$@"
135}
136
137# Corner cases that OSH doesn't handle
138assign-deferred() {
139 sh-spec spec/assign-deferred.test.sh \
140 $BASH $MKSH "$@"
141}
142
143# These test associative arrays
144assign-dialects() {
145 run-file assign-dialects "$@"
146}
147
148background() {
149 run-file background "$@"
150}
151
152subshell() {
153 sh-spec spec/subshell.test.sh \
154 ${REF_SHELLS[@]} $OSH_LIST "$@"
155}
156
157quote() {
158 sh-spec spec/quote.test.sh \
159 ${REF_SHELLS[@]} $BUSYBOX_ASH $OSH_LIST "$@"
160}
161
162unicode() {
163 run-file unicode "$@"
164}
165
166loop() {
167 run-file loop "$@"
168}
169
170case_() {
171 run-file case_ "$@"
172}
173
174if_() {
175 sh-spec spec/if_.test.sh \
176 ${REF_SHELLS[@]} $ZSH $OSH_LIST "$@"
177}
178
179builtin-misc() {
180 run-file builtin-misc "$@"
181}
182
183builtin-process() {
184 run-file builtin-process "$@"
185}
186
187builtin-cd() {
188 run-file builtin-cd "$@"
189}
190
191builtin-eval-source() {
192 run-file builtin-eval-source "$@"
193}
194
195builtin-echo() {
196 run-file builtin-echo "$@"
197}
198
199builtin-read() {
200 run-file builtin-read "$@"
201}
202
203nul-bytes() {
204 run-file nul-bytes "$@"
205}
206
207whitespace() {
208 run-file whitespace "$@"
209}
210
211# Special bash printf things like -v and %q. Portable stuff goes in builtin-io.
212builtin-printf() {
213 run-file builtin-printf "$@"
214}
215
216builtin-meta() {
217 run-file builtin-meta "$@"
218}
219
220builtin-history() {
221 run-file builtin-history "$@"
222}
223
224# dash and mksh don't implement 'dirs'
225builtin-dirs() {
226 sh-spec spec/builtin-dirs.test.sh \
227 $BASH $ZSH $OSH_LIST "$@"
228}
229
230builtin-vars() {
231 run-file builtin-vars "$@"
232}
233
234builtin-getopts() {
235 run-file builtin-getopts "$@"
236}
237
238builtin-bracket() {
239 run-file builtin-bracket "$@"
240}
241
242builtin-trap() {
243 run-file builtin-trap "$@"
244}
245
246builtin-trap-err() {
247 run-file builtin-trap-err "$@"
248}
249
250builtin-trap-bash() {
251 run-file builtin-trap-bash "$@"
252}
253
254# Bash implements type -t, but no other shell does. For Nix.
255# zsh/mksh/dash don't have the 'help' builtin.
256builtin-bash() {
257 run-file builtin-bash "$@"
258}
259
260builtin-type() {
261 run-file builtin-type "$@"
262}
263
264builtin-type-bash() {
265 run-file builtin-type-bash "$@"
266}
267
268vars-bash() {
269 run-file vars-bash "$@"
270}
271
272vars-special() {
273 run-file vars-special "$@"
274}
275
276builtin-completion() {
277 run-file builtin-completion "$@"
278}
279
280builtin-special() {
281 run-file builtin-special "$@"
282}
283
284builtin-times() {
285 sh-spec spec/builtin-times.test.sh $BASH $ZSH $OSH_LIST "$@"
286}
287
288command-parsing() {
289 sh-spec spec/command-parsing.test.sh ${REF_SHELLS[@]} $OSH_LIST "$@"
290}
291
292func-parsing() {
293 sh-spec spec/func-parsing.test.sh ${REF_SHELLS[@]} $OSH_LIST "$@"
294}
295
296sh-func() {
297 run-file sh-func "$@"
298}
299
300glob() {
301 run-file glob "$@"
302}
303
304globignore() {
305 run-file globignore "$@"
306}
307
308arith() {
309 run-file arith "$@"
310}
311
312command-sub() {
313 sh-spec spec/command-sub.test.sh \
314 ${REF_SHELLS[@]} $OSH_LIST "$@"
315}
316
317command_() {
318 sh-spec spec/command_.test.sh \
319 ${REF_SHELLS[@]} $ZSH $OSH_LIST "$@"
320}
321
322pipeline() {
323 sh-spec spec/pipeline.test.sh \
324 ${REF_SHELLS[@]} $ZSH $OSH_LIST "$@"
325}
326
327explore-parsing() {
328 sh-spec spec/explore-parsing.test.sh \
329 ${REF_SHELLS[@]} $OSH_LIST "$@"
330}
331
332parse-errors() {
333 run-file parse-errors "$@"
334}
335
336here-doc() {
337 # NOTE: The last two tests, 31 and 32, have different behavior on my Ubuntu
338 # and Debian machines.
339 # - On Ubuntu, read_from_fd.py fails with Errno 9 -- bad file descriptor.
340 # - On Debian, the whole process hangs.
341 # Is this due to Python 3.2 vs 3.4? Either way osh doesn't implement the
342 # functionality, so it's probably best to just implement it.
343 sh-spec spec/here-doc.test.sh --range 0-31 \
344 ${REF_SHELLS[@]} $OSH_LIST "$@"
345}
346
347redirect() {
348 run-file redirect "$@"
349}
350
351redirect-command() {
352 run-file redirect-command "$@"
353}
354
355redirect-multi() {
356 run-file redirect-multi "$@"
357}
358
359posix() {
360 sh-spec spec/posix.test.sh \
361 ${REF_SHELLS[@]} $OSH_LIST "$@"
362}
363
364introspect() {
365 run-file introspect "$@"
366}
367
368tilde() {
369 run-file tilde "$@"
370}
371
372var-op-test() {
373 run-file var-op-test "$@"
374}
375
376var-op-len() {
377 sh-spec spec/var-op-len.test.sh \
378 ${REF_SHELLS[@]} $ZSH $OSH_LIST "$@"
379}
380
381var-op-patsub() {
382 # 1 unicode failure, and [^]] which is a parsing divergence
383 run-file var-op-patsub "$@"
384}
385
386var-op-slice() {
387 run-file var-op-slice "$@"
388}
389
390var-op-bash() {
391 run-file var-op-bash "$@"
392}
393
394var-op-strip() {
395 sh-spec spec/var-op-strip.test.sh \
396 ${REF_SHELLS[@]} $ZSH $BUSYBOX_ASH $OSH_LIST "$@"
397}
398
399var-sub() {
400 # NOTE: ZSH has interesting behavior, like echo hi > "$@" can write to TWO
401 # FILES! But ultimately we don't really care, so I disabled it.
402 sh-spec spec/var-sub.test.sh \
403 ${REF_SHELLS[@]} $OSH_LIST "$@"
404}
405
406var-num() {
407 run-file var-num "$@"
408}
409
410var-sub-quote() {
411 sh-spec spec/var-sub-quote.test.sh \
412 ${REF_SHELLS[@]} $OSH_LIST "$@"
413}
414
415sh-usage() {
416 run-file sh-usage "$@"
417}
418
419sh-options() {
420 run-file sh-options "$@"
421}
422
423xtrace() {
424 run-file xtrace "$@"
425}
426
427strict-options() {
428 run-file strict-options "$@"
429}
430
431exit-status() {
432 run-file exit-status "$@"
433}
434
435errexit() {
436 run-file errexit "$@"
437}
438
439errexit-osh() {
440 run-file errexit-osh "$@"
441}
442
443fatal-errors() {
444 sh-spec spec/fatal-errors.test.sh \
445 ${REF_SHELLS[@]} $ZSH $OSH_LIST "$@"
446}
447
448#
449# Non-POSIX extensions: arrays, brace expansion, [[, ((, etc.
450#
451
452# There as many non-POSIX arithmetic contexts.
453arith-context() {
454 run-file arith-context "$@"
455}
456
457array() {
458 run-file array "$@"
459}
460
461array-basic() {
462 run-file array-basic "$@"
463}
464
465array-compat() {
466 run-file array-compat "$@"
467}
468
469type-compat() {
470 run-file type-compat "$@"
471}
472
473# += is not POSIX and not in dash.
474append() {
475 run-file append "$@"
476}
477
478# associative array -- mksh and zsh implement different associative arrays.
479assoc() {
480 run-file assoc "$@"
481}
482
483# ZSH also has associative arrays
484assoc-zsh() {
485 sh-spec spec/assoc-zsh.test.sh $ZSH "$@"
486}
487
488dbracket() {
489 run-file dbracket "$@"
490}
491
492dparen() {
493 run-file dparen "$@"
494}
495
496brace-expansion() {
497 run-file brace-expansion "$@"
498}
499
500regex() {
501 run-file regex "$@"
502}
503
504process-sub() {
505 run-file process-sub "$@"
506}
507
508# This does file system globbing
509extglob-files() {
510 run-file extglob-files "$@"
511}
512
513# This does string matching.
514extglob-match() {
515 sh-spec spec/extglob-match.test.sh \
516 $BASH $MKSH $OSH_LIST "$@"
517}
518
519nocasematch-match() {
520 run-file nocasematch-match "$@"
521}
522
523# ${!var} syntax -- oil should replace this with associative arrays.
524# mksh has completely different behavior for this syntax. Not worth testing.
525var-ref() {
526 run-file var-ref "$@"
527}
528
529nameref() {
530 ### declare -n / local -n
531 run-file nameref "$@"
532}
533
534let() {
535 sh-spec spec/let.test.sh $BASH $MKSH $ZSH "$@"
536}
537
538for-expr() {
539 run-file for-expr "$@"
540}
541
542empty-bodies() {
543 sh-spec spec/empty-bodies.test.sh "${REF_SHELLS[@]}" $ZSH $OSH_LIST "$@"
544}
545
546# TODO: This is for the ANTLR grammars, in the oil-sketch repo.
547# osh has infinite loop?
548shell-grammar() {
549 sh-spec spec/shell-grammar.test.sh $BASH $MKSH $ZSH "$@"
550}
551
552serialize() {
553 run-file serialize "$@"
554}
555
556#
557# Smoosh
558#
559
560readonly SMOOSH_REPO=~/git/languages/smoosh
561
562sh-spec-smoosh-env() {
563 local test_file=$1
564 shift
565
566 # - smoosh tests use $TEST_SHELL instead of $SH
567 # - cd $TMP to avoid littering repo
568 # - pass -o posix
569 # - timeout of 1 second
570 # - Some tests in smoosh use $HOME and $LOGNAME
571
572 sh-spec $test_file \
573 --sh-env-var-name TEST_SHELL \
574 --posix \
575 --env-pair "TEST_UTIL=$SMOOSH_REPO/tests/util" \
576 --env-pair "LOGNAME=$LOGNAME" \
577 --env-pair "HOME=$HOME" \
578 --timeout 1 \
579 --oils-bin-dir $REPO_ROOT/bin \
580 --compare-shells \
581 "$@"
582}
583
584# For speed, only run with one copy of OSH.
585readonly smoosh_osh_list=$OSH_CPYTHON
586
587smoosh() {
588 ### Run case smoosh from the console
589
590 # TODO: Use --oils-bin-dir
591 # our_shells, etc.
592
593 sh-spec-smoosh-env _tmp/smoosh.test.sh \
594 ${REF_SHELLS[@]} $smoosh_osh_list \
595 "$@"
596}
597
598smoosh-hang() {
599 ### Run case smoosh-hang from the console
600
601 # Need the smoosh timeout tool to run correctly.
602 sh-spec-smoosh-env _tmp/smoosh-hang.test.sh \
603 --timeout-bin "$SMOOSH_REPO/tests/util/timeout" \
604 --timeout 1 \
605 "$@"
606}
607
608_one-html() {
609 local spec_name=$1
610 shift
611
612 local out_dir=_tmp/spec/smoosh
613 local tmp_dir=_tmp/src-smoosh
614 mkdir -p $out_dir $out_dir
615
616 doctools/src_tree.py smoosh-file \
617 _tmp/$spec_name.test.sh \
618 $out_dir/$spec_name.test.html
619
620 local out=$out_dir/${spec_name}.html
621 set +o errexit
622 # Shell function is smoosh or smoosh-hang
623 time $spec_name --format html "$@" > $out
624 set -o errexit
625
626 echo
627 echo "Wrote $out"
628
629 # NOTE: This IGNORES the exit status.
630}
631
632# TODO:
633# - Put these tests in the CI
634# - Import smoosh spec tests into the repo, with 'test/smoosh.sh'
635
636smoosh-html() {
637 ### Run by devtools/release.sh
638 _one-html smoosh "$@"
639}
640
641smoosh-hang-html() {
642 ### Run by devtools/release.sh
643 _one-html smoosh-hang "$@"
644}
645
646html-demo() {
647 ### Test for --format html
648
649 local out=_tmp/spec/demo.html
650 builtin-special --format html "$@" > $out
651
652 echo
653 echo "Wrote $out"
654}
655
656#
657# Hay is part of the YSH suite
658#
659
660hay() {
661 run-file hay "$@"
662}
663
664hay-isolation() {
665 run-file hay-isolation "$@"
666}
667
668hay-meta() {
669 run-file hay-meta "$@"
670}
671
672#
673# YSH
674#
675
676ysh-convert() {
677 run-file ysh-convert "$@"
678}
679
680ysh-completion() {
681 run-file ysh-completion "$@"
682}
683
684ysh-stdlib() {
685 run-file ysh-stdlib "$@"
686}
687
688ysh-stdlib-2() {
689 run-file ysh-stdlib-2 "$@"
690}
691
692ysh-stdlib-args() {
693 run-file ysh-stdlib-args "$@"
694}
695
696ysh-stdlib-testing() {
697 run-file ysh-stdlib-testing "$@"
698}
699
700ysh-stdlib-synch() {
701 run-file ysh-stdlib-synch "$@"
702}
703
704ysh-source() {
705 run-file ysh-source "$@"
706}
707
708ysh-usage() {
709 run-file ysh-usage "$@"
710}
711
712ysh-unicode() {
713 run-file ysh-unicode "$@"
714}
715
716ysh-bin() {
717 run-file ysh-bin "$@"
718}
719
720ysh-dict() {
721 run-file ysh-dict "$@"
722}
723
724ysh-list() {
725 run-file ysh-list "$@"
726}
727
728ysh-place() {
729 run-file ysh-place "$@"
730}
731
732ysh-prompt() {
733 run-file ysh-prompt "$@"
734}
735
736ysh-assign() {
737 run-file ysh-assign "$@"
738}
739
740ysh-augmented() {
741 run-file ysh-augmented "$@"
742}
743
744ysh-blocks() {
745 run-file ysh-blocks "$@"
746}
747
748ysh-bugs() {
749 run-file ysh-bugs "$@"
750}
751
752ysh-builtins() {
753 run-file ysh-builtins "$@"
754}
755
756ysh-builtin-module() {
757 run-file ysh-builtin-module "$@"
758}
759
760ysh-builtin-eval() {
761 run-file ysh-builtin-eval "$@"
762}
763
764# Related to errexit-oil
765ysh-builtin-error() {
766 run-file ysh-builtin-error "$@"
767}
768
769ysh-builtin-meta() {
770 run-file ysh-builtin-meta "$@"
771}
772
773ysh-builtin-process() {
774 run-file ysh-builtin-process "$@"
775}
776
777ysh-builtin-shopt() {
778 run-file ysh-builtin-shopt "$@"
779}
780
781ysh-case() {
782 run-file ysh-case "$@"
783}
784
785ysh-command-sub() {
786 run-file ysh-command-sub "$@"
787}
788
789ysh-demo() {
790 run-file ysh-demo "$@"
791}
792
793ysh-expr() {
794 run-file ysh-expr "$@"
795}
796
797ysh-int-float() {
798 run-file ysh-int-float "$@"
799}
800
801ysh-expr-bool() {
802 run-file ysh-expr-bool "$@"
803}
804
805ysh-expr-arith() {
806 run-file ysh-expr-arith "$@"
807}
808
809ysh-expr-compare() {
810 run-file ysh-expr-compare "$@"
811}
812
813ysh-expr-sub() {
814 run-file ysh-expr-sub "$@"
815}
816
817ysh-cmd-lang() {
818 run-file ysh-cmd-lang "$@"
819}
820
821ysh-for() {
822 run-file ysh-for "$@"
823}
824
825ysh-methods() {
826 run-file ysh-methods "$@"
827}
828
829ysh-func() {
830 run-file ysh-func "$@"
831}
832
833ysh-func-builtin() {
834 run-file ysh-func-builtin "$@"
835}
836
837ysh-funcs-external() {
838 run-file ysh-funcs-external "$@"
839}
840
841ysh-interactive() {
842 run-file ysh-interactive "$@"
843}
844
845ysh-json() {
846 run-file ysh-json "$@"
847}
848
849ysh-keywords() {
850 run-file ysh-keywords "$@"
851}
852
853ysh-multiline() {
854 run-file ysh-multiline "$@"
855}
856
857ysh-options() {
858 run-file ysh-options "$@"
859}
860
861ysh-options-assign() {
862 run-file ysh-options-assign "$@"
863}
864
865ysh-proc() {
866 run-file ysh-proc "$@"
867}
868
869ysh-regex() {
870 run-file ysh-regex "$@"
871}
872
873ysh-regex-api() {
874 run-file ysh-regex-api "$@"
875}
876
877ysh-reserved() {
878 run-file ysh-reserved "$@"
879}
880
881ysh-scope() {
882 run-file ysh-scope "$@"
883}
884
885ysh-slice-range() {
886 run-file ysh-slice-range "$@"
887}
888
889ysh-string() {
890 run-file ysh-string "$@"
891}
892
893ysh-special-vars() {
894 run-file ysh-special-vars "$@"
895}
896
897ysh-tuple() {
898 run-file ysh-tuple "$@"
899}
900
901ysh-var-sub() {
902 run-file ysh-var-sub "$@"
903}
904
905ysh-with-sh() {
906 run-file ysh-with-sh "$@"
907}
908
909ysh-word-eval() {
910 run-file ysh-word-eval "$@"
911}
912
913ysh-xtrace() {
914 run-file ysh-xtrace "$@"
915}
916
917ysh-user-feedback() {
918 run-file ysh-user-feedback "$@"
919}
920
921ysh-builtin-ctx() {
922 run-file ysh-builtin-ctx "$@"
923}
924
925ysh-builtin-error() {
926 run-file ysh-builtin-error "$@"
927}
928
929ysh-builtin-help() {
930 run-file ysh-builtin-help "$@"
931}
932
933ysh-dev() {
934 run-file ysh-dev "$@"
935}
936
937ysh-printing() {
938 run-file ysh-printing "$@"
939}
940
941
942#
943# More OSH
944#
945
946nix-idioms() {
947 run-file nix-idioms "$@"
948}
949
950zsh-idioms() {
951 run-file zsh-idioms "$@"
952}
953
954ble-idioms() {
955 sh-spec spec/ble-idioms.test.sh \
956 $BASH $ZSH $MKSH $BUSYBOX_ASH $OSH_LIST "$@"
957}
958
959ble-features() {
960 run-file ble-features "$@"
961}
962
963toysh() {
964 run-file toysh "$@"
965}
966
967toysh-posix() {
968 run-file toysh-posix "$@"
969}
970
971run-task "$@"