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