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

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