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

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