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

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