OILS / test / spec.sh View on Github | oils.pub

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