1 | #!/usr/bin/env bash
|
2 | #
|
3 | # Test ysh-prettify transformations
|
4 | #
|
5 | # Usage:
|
6 | # ./ysh-ify.sh <function name>
|
7 |
|
8 | : ${LIB_OSH=stdlib/osh}
|
9 | source $LIB_OSH/bash-strict.sh
|
10 | source $LIB_OSH/task-five.sh
|
11 |
|
12 | source test/common.sh # $OSH
|
13 |
|
14 | readonly TEMP_DIR=_tmp
|
15 |
|
16 | prettify-one() {
|
17 | local file=$1
|
18 |
|
19 | set +o errexit
|
20 | $OSH --tool ysh-ify "$file"
|
21 | local status=$?
|
22 | set +o errexit
|
23 |
|
24 | if test $status = 0; then
|
25 | echo " (DONE $file)"
|
26 | else
|
27 | echo " FAIL: $file"
|
28 | return 255 # xargs FAILURE
|
29 | fi
|
30 | }
|
31 |
|
32 | smoke-test() {
|
33 | ### Run it against many of our files
|
34 | find build benchmarks -name '*.sh' | xargs -n 1 -- $0 prettify-one
|
35 | }
|
36 |
|
37 | run-all() {
|
38 | ### For both CI and release.
|
39 |
|
40 | # Note: might want to split these up.
|
41 |
|
42 | run-test-funcs
|
43 |
|
44 | smoke-test
|
45 | }
|
46 |
|
47 | soil-run() {
|
48 | run-all
|
49 | }
|
50 |
|
51 | soil-run-cpp() {
|
52 | ### Not used yet, but it works
|
53 |
|
54 | local osh=_bin/cxx-asan/osh
|
55 | ninja $osh
|
56 |
|
57 | #OSH=$osh run-test-funcs
|
58 | OSH=$osh run-all
|
59 | }
|
60 |
|
61 | run-for-release() {
|
62 | run-other-suite-for-release ysh-ify run-all
|
63 | }
|
64 |
|
65 |
|
66 | #
|
67 | # Test Harness
|
68 | #
|
69 |
|
70 | check-osh2ysh() {
|
71 | local osh_str=$1
|
72 | local ysh_str=$2 # expected
|
73 | local allow_invalid=${3:-}
|
74 |
|
75 | # Make sure they are valid
|
76 |
|
77 | bin/osh -n -c "$osh_str"
|
78 | if test -z "$allow_invalid"; then
|
79 | bin/ysh -n -c "$ysh_str"
|
80 | fi
|
81 |
|
82 | local tmp=$TEMP_DIR/actual.ysh
|
83 | echo "$osh_str" | bin/osh --tool ysh-ify | tee $tmp
|
84 |
|
85 | echo "$ysh_str" | diff -u $tmp -
|
86 | echo 'OK'
|
87 |
|
88 | # TODO: Also create a variant that tests equal STDOUT and STATUS!
|
89 | # probably assert no stderr
|
90 | #
|
91 | # For backticks, etc.
|
92 | }
|
93 |
|
94 | #
|
95 | # UNCHANGED
|
96 | #
|
97 |
|
98 | test-simple-command() {
|
99 | ### Unchanged
|
100 |
|
101 | check-osh2ysh 'echo hi' 'echo hi'
|
102 | }
|
103 |
|
104 |
|
105 | test-line-breaks() {
|
106 | ### Unchanged
|
107 |
|
108 | check-osh2ysh '
|
109 | echo one \
|
110 | two three \
|
111 | four
|
112 | ' '
|
113 | echo one \
|
114 | two three \
|
115 | four
|
116 | '
|
117 | }
|
118 |
|
119 | test-and-or() {
|
120 | check-osh2ysh \
|
121 | 'ls && echo "$@" || die "foo"' \
|
122 | 'ls && echo @ARGV || die "foo"'
|
123 | }
|
124 |
|
125 | #
|
126 | # CHANGED WORD LANGUAGE
|
127 | #
|
128 |
|
129 | test-dollar-at() {
|
130 | check-osh2ysh \
|
131 | 'echo one "$@" two' \
|
132 | 'echo one @ARGV two'
|
133 | }
|
134 |
|
135 | TODO-test-prefix-ops() {
|
136 | check-osh2ysh \
|
137 | 'echo ${#s} ${#a[@]}' \
|
138 | 'echo $[len(s)] $[len(a)]'
|
139 | }
|
140 |
|
141 | test-unquote-subs-TODO() {
|
142 | check-osh2ysh \
|
143 | 'echo "$1" "$foo"' \
|
144 | 'echo $1 $foo'
|
145 |
|
146 | check-osh2ysh \
|
147 | 'echo "$(echo hi)"' \
|
148 | 'echo $(echo hi)'
|
149 |
|
150 | return
|
151 | # TODO: echo $foo
|
152 | check-osh2ysh \
|
153 | 'echo "${foo}"' \
|
154 | 'echo $foo'
|
155 | }
|
156 |
|
157 | TODO-test-word-joining() {
|
158 | local osh=$(cat <<EOF
|
159 | echo 'foo " bar '"'"
|
160 | EOF
|
161 | )
|
162 |
|
163 | # TODO: Use new YSTR syntax!
|
164 | local ysh=$(cat <<EOF
|
165 | echo y"foo \" bar '"
|
166 | EOF
|
167 | )
|
168 | check-osh2ysh "$osh" "$ysh"
|
169 | }
|
170 |
|
171 | # Unchanged
|
172 | test-command-sub() {
|
173 | check-osh2ysh \
|
174 | 'echo $(echo hi)' \
|
175 | 'echo $(echo hi)'
|
176 |
|
177 | check-osh2ysh \
|
178 | 'echo "__$(echo hi)__"' \
|
179 | 'echo "__$(echo hi)__"'
|
180 | }
|
181 |
|
182 | test-var-sub() {
|
183 | # Unchanged
|
184 | check-osh2ysh \
|
185 | 'echo $foo' \
|
186 | 'echo $foo'
|
187 |
|
188 | # Could just be $bar
|
189 | check-osh2ysh \
|
190 | 'echo $foo ${bar} "__${bar}__"' \
|
191 | 'echo $foo ${bar} "__${bar}__"'
|
192 |
|
193 | return
|
194 |
|
195 | # We could make this $[foo ? 'default'], but meh, let's not introduce more
|
196 | # operators
|
197 | #
|
198 | # Better is getvar('foo', 'default')
|
199 |
|
200 | check-osh2ysh \
|
201 | 'echo ${foo:-default}' \
|
202 | "echo $[getvar('foo', 'default')]"
|
203 | }
|
204 |
|
205 | # Downgraded to one_pass_parse. This means \" will be wrong, but meh.
|
206 | # Here the WordParser makes another pass with CommandParser.
|
207 | #
|
208 | # We could also translate it to:
|
209 | # echo $[compat backticks 'echo hi']
|
210 | # But that might be overly pedantic. This will work most of the time.
|
211 |
|
212 | test-backticks-TODO() {
|
213 | check-osh2ysh \
|
214 | 'echo `echo hi ${var}`' \
|
215 | 'echo $(echo hi ${var})'
|
216 |
|
217 | check-osh2ysh \
|
218 | 'echo $({ echo hi; })' \
|
219 | 'echo $({ echo hi; })'
|
220 |
|
221 | # TODO: Fix this
|
222 | check-osh2ysh \
|
223 | 'echo `{ echo hi; }`' \
|
224 | 'echo $(do { echo hi)' \
|
225 | INVALID
|
226 | }
|
227 |
|
228 | #
|
229 | # CHANGED BUILTIN LANGUAGE
|
230 | #
|
231 |
|
232 | test-bracket-builtin() {
|
233 | check-osh2ysh \
|
234 | '[ ! -z "$foo" ] || die' \
|
235 | 'test ! -z $foo || die'
|
236 |
|
237 | # Don't touch this invalid code?
|
238 | check-osh2ysh \
|
239 | '[ ] || die' \
|
240 | '[ ] || die'
|
241 |
|
242 | check-osh2ysh '
|
243 | if [ "$foo" -eq 3 ]; then
|
244 | echo yes
|
245 | fi' \
|
246 | '
|
247 | if test $foo -eq 3 {
|
248 | echo yes
|
249 | }'
|
250 | }
|
251 |
|
252 | test-source-builtin() {
|
253 | check-osh2ysh \
|
254 | '. lib.sh' \
|
255 | 'source lib.sh'
|
256 |
|
257 | check-osh2ysh \
|
258 | '[ -f lib.sh ] && . lib.sh' \
|
259 | 'test -f lib.sh && source lib.sh'
|
260 | }
|
261 |
|
262 | TODO-test-set-builtin() {
|
263 | # Not as important now that we have 'setvar'
|
264 | check-osh2ysh \
|
265 | 'set -o errexit' \
|
266 | 'shopt --set errexit'
|
267 | }
|
268 |
|
269 | #
|
270 | # CHANGED COMMAND LANGUAGE
|
271 | #
|
272 |
|
273 | test-here-doc() {
|
274 | check-osh2ysh '
|
275 | cat <<EOF
|
276 | hi
|
277 | EOF
|
278 | ' '
|
279 | cat <<< """
|
280 | hi
|
281 | """
|
282 | '
|
283 |
|
284 | check-osh2ysh "
|
285 | cat <<'EOF'
|
286 | hi
|
287 | EOF
|
288 | " "
|
289 | cat <<< '''
|
290 | hi
|
291 | '''
|
292 | "
|
293 | }
|
294 |
|
295 | test-bare-assign-TODO() {
|
296 | check-osh2ysh "
|
297 | a=
|
298 | " "
|
299 | setvar a = ''
|
300 | "
|
301 |
|
302 | check-osh2ysh "
|
303 | a=b
|
304 | " "
|
305 | setvar a = 'b'
|
306 | "
|
307 |
|
308 | # TODO: Make it quoted
|
309 | if false; then
|
310 | check-osh2ysh '
|
311 | a="$x"
|
312 | ' '
|
313 | setvar a = "$x"
|
314 | '
|
315 | fi
|
316 |
|
317 | check-osh2ysh '
|
318 | a=$(hostname)
|
319 | ' '
|
320 | setvar a = $(hostname)
|
321 | '
|
322 |
|
323 | check-osh2ysh '
|
324 | a=${PATH:-}
|
325 | ' '
|
326 | setvar a = ${PATH:-}
|
327 | '
|
328 |
|
329 | return
|
330 | check-osh2ysh '
|
331 | a=$x
|
332 | ' '
|
333 | setvar a = "$x"
|
334 | '
|
335 |
|
336 | }
|
337 |
|
338 | TODO-test-assign-builtins() {
|
339 | check-osh2ysh "
|
340 | local a=
|
341 | " "
|
342 | var a = ''
|
343 | "
|
344 |
|
345 | check-osh2ysh "
|
346 | local a=b
|
347 | " "
|
348 | var a = 'b'
|
349 | "
|
350 |
|
351 | # TODO: more test cases
|
352 |
|
353 | check-osh2ysh "
|
354 | readonly a=b
|
355 | " "
|
356 | const a = 'b'
|
357 | "
|
358 | }
|
359 |
|
360 | test-while-loop() {
|
361 | check-osh2ysh '
|
362 | while read line; do
|
363 | echo $line
|
364 | done' \
|
365 | '
|
366 | while read line {
|
367 | echo $line
|
368 | }'
|
369 |
|
370 | check-osh2ysh '
|
371 | while read \
|
372 | line; do
|
373 | echo $line
|
374 | done' \
|
375 | '
|
376 | while read \
|
377 | line {
|
378 | echo $line
|
379 | }'
|
380 | }
|
381 |
|
382 | test-if() {
|
383 | check-osh2ysh '
|
384 | if true; then
|
385 | echo yes
|
386 | fi' \
|
387 | '
|
388 | if true {
|
389 | echo yes
|
390 | }'
|
391 |
|
392 | check-osh2ysh '
|
393 | if true; then
|
394 | echo yes
|
395 | elif false; then
|
396 | echo elif
|
397 | elif spam; then
|
398 | echo elif
|
399 | else
|
400 | echo no
|
401 | fi' \
|
402 | '
|
403 | if true {
|
404 | echo yes
|
405 | } elif false {
|
406 | echo elif
|
407 | } elif spam {
|
408 | echo elif
|
409 | } else {
|
410 | echo no
|
411 | }'
|
412 |
|
413 | # Redirect
|
414 | check-osh2ysh '
|
415 | if true; then
|
416 | echo yes
|
417 | fi > out' \
|
418 | '
|
419 | if true {
|
420 | echo yes
|
421 | } > out'
|
422 | }
|
423 |
|
424 | TODO-test-then-next-line() {
|
425 | # TODO: Brace must be on same line
|
426 | check-osh2ysh '
|
427 | if true
|
428 | then
|
429 | echo yes
|
430 | fi' \
|
431 | '
|
432 | if true {
|
433 | echo yes
|
434 | }'
|
435 |
|
436 | }
|
437 |
|
438 | test-posix-func() {
|
439 | check-osh2ysh '
|
440 | f() {
|
441 | echo "hi"
|
442 | }' '
|
443 | proc f {
|
444 | echo "hi"
|
445 | }'
|
446 |
|
447 | # The brace is moved
|
448 | check-osh2ysh '
|
449 | f()
|
450 | {
|
451 | echo "hi"
|
452 | }' '
|
453 | proc f {
|
454 | echo "hi"
|
455 | }'
|
456 |
|
457 | return
|
458 |
|
459 | # Nested functinos
|
460 | check-osh2ysh '
|
461 | func1() {
|
462 | echo func1
|
463 | func2()
|
464 | {
|
465 | echo func2
|
466 | }
|
467 | }' \
|
468 | '
|
469 | proc func1 {
|
470 | echo func1
|
471 | proc func2
|
472 | {
|
473 | echo func2
|
474 | }
|
475 | }'
|
476 | return
|
477 |
|
478 | # Non-brace function bodies
|
479 | # TODO: Bail in this case
|
480 | check-osh2ysh '
|
481 | f() (
|
482 | echo hi
|
483 | )' \
|
484 | '
|
485 | proc f (
|
486 | echo hi
|
487 | )' \
|
488 | INVALID
|
489 | }
|
490 |
|
491 | test-ksh-func() {
|
492 | check-osh2ysh '
|
493 | function func1 { # no parens
|
494 | echo func1
|
495 | }' '
|
496 | proc func1 { # no parens
|
497 | echo func1
|
498 | }'
|
499 | }
|
500 |
|
501 | test-for-loop() {
|
502 | check-osh2ysh '
|
503 | for x in a b c \
|
504 | d e f; do
|
505 | echo $x
|
506 | done
|
507 | ' '
|
508 | for x in a b c \
|
509 | d e f {
|
510 | echo $x
|
511 | }
|
512 | '
|
513 |
|
514 | check-osh2ysh '
|
515 | for x in a b c \
|
516 | d e f
|
517 | do
|
518 | echo $x
|
519 | done
|
520 | ' '
|
521 | for x in a b c \
|
522 | d e f
|
523 | {
|
524 | echo $x
|
525 | }
|
526 | '
|
527 | }
|
528 |
|
529 | test-empty-for-loop() {
|
530 | check-osh2ysh '
|
531 | for x in
|
532 | do
|
533 | echo $x
|
534 | done
|
535 | ' '
|
536 | for x in
|
537 | {
|
538 | echo $x
|
539 | }
|
540 | '
|
541 | }
|
542 |
|
543 | test-args-for-loop() {
|
544 | # Why are we missing a newline here?
|
545 | check-osh2ysh '
|
546 | for x; do
|
547 | echo $x
|
548 | done
|
549 | ' 'for x in @ARGV {
|
550 | echo $x
|
551 | }
|
552 | '
|
553 | # Change brace style
|
554 |
|
555 | check-osh2ysh '
|
556 | for x
|
557 | do
|
558 | echo $x
|
559 | done
|
560 | ' 'for x in @ARGV {
|
561 | echo $x
|
562 | }
|
563 | '
|
564 | }
|
565 |
|
566 | # TODO: translate to forkwait { proper spaces }
|
567 |
|
568 | test-subshell() {
|
569 | check-osh2ysh \
|
570 | '(echo hi;)' \
|
571 | 'shell {echo hi;}' \
|
572 | INVALID
|
573 |
|
574 | check-osh2ysh \
|
575 | '(echo hi)' \
|
576 | 'shell {echo hi}' \
|
577 | INVALID
|
578 |
|
579 | check-osh2ysh \
|
580 | '(echo hi; echo bye)' \
|
581 | 'shell {echo hi; echo bye}' \
|
582 | INVALID
|
583 |
|
584 | check-osh2ysh \
|
585 | '( (echo hi; echo bye ) )' \
|
586 | 'shell { shell {echo hi; echo bye } }' \
|
587 | INVALID
|
588 | }
|
589 |
|
590 | test-brace-group() {
|
591 | check-osh2ysh \
|
592 | '{ echo hi; }' \
|
593 | 'do { echo hi; }' \
|
594 | INVALID
|
595 |
|
596 | check-osh2ysh \
|
597 | '{ echo hi; echo bye; }' \
|
598 | 'do { echo hi; echo bye; }' \
|
599 | INVALID
|
600 | }
|
601 |
|
602 | # TODO: New case syntax, which looks like
|
603 | #
|
604 | # case (myvar) {
|
605 | # *.cc | *.h { echo 'C++' }
|
606 | # }
|
607 |
|
608 | # case (myvar) {
|
609 | # *.cc | *.h {
|
610 | # echo 'C++'
|
611 | # }
|
612 | # }
|
613 |
|
614 | test-case() {
|
615 | check-osh2ysh '
|
616 | case $var in
|
617 | foo|bar)
|
618 | [ -f foo ] && echo file
|
619 | ;;
|
620 | "")
|
621 | echo empty
|
622 | ;;
|
623 | *)
|
624 | echo default
|
625 | ;;
|
626 | esac
|
627 | ' '
|
628 | case (var) {
|
629 | foo|bar {
|
630 | test -f foo && echo file
|
631 | }
|
632 | "" {
|
633 | echo empty
|
634 | }
|
635 | * {
|
636 | echo default
|
637 | }
|
638 | }
|
639 | '
|
640 |
|
641 | check-osh2ysh '
|
642 | case "$var" in
|
643 | *)
|
644 | echo foo
|
645 | echo bar # no dsemi
|
646 | esac
|
647 | ' '
|
648 | case (var) {
|
649 | * {
|
650 | echo foo
|
651 | echo bar # no dsemi
|
652 | }
|
653 | }
|
654 | '
|
655 | }
|
656 |
|
657 | task-five "$@"
|