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

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