Bash · 20080 bytes Raw Blame History
1 #!/bin/sh
2 # =====================================
3 # POSIX Compliance Here-Document and Expansion Test Suite for rush
4 # =====================================
5 # Tests here-documents and parameter expansion per IEEE Std 1003.1-2017
6 # Section: Shell Command Language - Here-Documents, Parameter Expansion
7
8 # Colors (POSIX-compliant way)
9 RED='\033[0;31m'
10 GREEN='\033[0;32m'
11 YELLOW='\033[1;33m'
12 BLUE='\033[0;34m'
13 NC='\033[0m'
14
15 # Test identification
16 TEST_PREFIX="[posix-heredoc]"
17 CURRENT_SECTION=""
18 TEST_NUM=0
19
20 PASSED=0
21 FAILED=0
22 SKIPPED=0
23 FAILED_TESTS_LIST=""
24
25 # Get script directory (POSIX way)
26 SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
27 RUSH_BIN="${RUSH_BIN:-$SCRIPT_DIR/../target/release/rush}"
28
29 # Check if fortsh exists
30 if [ ! -x "$RUSH_BIN" ]; then
31 printf "${RED}ERROR${NC}: rush binary not found at $RUSH_BIN\n"
32 printf "Please run 'make' first or set RUSH_BIN environment variable\n"
33 exit 1
34 fi
35
36 # Test result trackers
37 pass() {
38 TEST_NUM=$((TEST_NUM + 1))
39 printf "${GREEN}✓ PASS${NC} ${TEST_PREFIX} ${CURRENT_SECTION}.${TEST_NUM}: %s\n" "$1"
40 PASSED=$((PASSED + 1))
41 }
42
43 fail() {
44 TEST_NUM=$((TEST_NUM + 1))
45 TEST_ID="${TEST_PREFIX} ${CURRENT_SECTION}.${TEST_NUM}"
46 printf "${RED}✗ FAIL${NC} ${TEST_ID}: %s\n" "$1"
47 FAILED_TESTS_LIST="${FAILED_TESTS_LIST} ${TEST_ID}: $1\n"
48 if [ -n "$2" ]; then
49 printf " expected: %s\n" "$2"
50 fi
51 if [ -n "$3" ]; then
52 printf " got: %s\n" "$3"
53 fi
54 FAILED=$((FAILED + 1))
55 }
56
57 skip() {
58 TEST_NUM=$((TEST_NUM + 1))
59 printf "${YELLOW}⊘ SKIP${NC} ${TEST_PREFIX} ${CURRENT_SECTION}.${TEST_NUM}: %s - %s\n" "$1" "$2"
60 SKIPPED=$((SKIPPED + 1))
61 }
62
63 section() {
64 CURRENT_SECTION=$(echo "$1" | grep -oE '^[0-9]+' || echo "0")
65 TEST_NUM=0
66 printf "\n"
67 printf "${BLUE}==========================================\n"
68 printf "%s\n" "$1"
69 printf "==========================================${NC}\n"
70 }
71
72 # =====================================
73 section "396. BASIC HERE-DOCUMENT"
74 # =====================================
75
76 result=$("$RUSH_BIN" -c 'cat <<EOF
77 hello world
78 EOF' 2>&1)
79 if [ "$result" = "hello world" ]; then
80 pass "Basic here-document"
81 else
82 fail "Basic here-document" "hello world" "$result"
83 fi
84
85 result=$("$RUSH_BIN" -c 'cat <<END
86 line one
87 line two
88 END' 2>&1)
89 expected=$(printf "line one\nline two")
90 if [ "$result" = "$expected" ]; then
91 pass "Here-document multiple lines"
92 else
93 fail "Here-document multiple lines" "$expected" "$result"
94 fi
95
96 result=$("$RUSH_BIN" -c 'x=world; cat <<EOF
97 hello $x
98 EOF' 2>&1)
99 if [ "$result" = "hello world" ]; then
100 pass "Here-document with variable expansion"
101 else
102 fail "Here-document with variable expansion" "hello world" "$result"
103 fi
104
105 result=$("$RUSH_BIN" -c 'cat <<EOF
106 result: $(echo test)
107 EOF' 2>&1)
108 if [ "$result" = "result: test" ]; then
109 pass "Here-document with command substitution"
110 else
111 fail "Here-document with command substitution" "result: test" "$result"
112 fi
113
114 # =====================================
115 section "397. QUOTED HERE-DOCUMENT DELIMITER"
116 # =====================================
117
118 result=$("$RUSH_BIN" -c 'x=world; cat <<"EOF"
119 hello $x
120 EOF' 2>&1)
121 if [ "$result" = 'hello $x' ]; then
122 pass "Quoted delimiter prevents expansion"
123 else
124 fail "Quoted delimiter prevents expansion" 'hello $x' "$result"
125 fi
126
127 result=$("$RUSH_BIN" -c "cat <<'END'
128 test \$(echo foo)
129 END" 2>&1)
130 if [ "$result" = 'test $(echo foo)' ]; then
131 pass "Single-quoted delimiter prevents command sub"
132 else
133 fail "Single-quoted delimiter prevents command sub" 'test $(echo foo)' "$result"
134 fi
135
136 # =====================================
137 section "398. HERE-DOCUMENT WITH TAB STRIPPING (<<-)"
138 # =====================================
139
140 result=$("$RUSH_BIN" -c ' cat <<-EOF
141 hello
142 world
143 EOF' 2>&1)
144 expected=$(printf "hello\nworld")
145 if [ "$result" = "$expected" ]; then
146 pass "<<- strips leading tabs"
147 else
148 fail "<<- strips leading tabs" "$expected" "$result"
149 fi
150
151 result=$("$RUSH_BIN" -c 'cat <<-END
152 indented
153 END' 2>&1)
154 if [ "$result" = "indented" ]; then
155 pass "<<- strips multiple tabs"
156 else
157 fail "<<- strips multiple tabs" "indented" "$result"
158 fi
159
160 # =====================================
161 section "399. HERE-DOCUMENT TO DIFFERENT COMMANDS"
162 # =====================================
163
164 result=$("$RUSH_BIN" -c 'wc -l <<EOF
165 one
166 two
167 three
168 EOF' 2>&1)
169 if echo "$result" | grep -q "3"; then
170 pass "Here-document to wc -l"
171 else
172 fail "Here-document to wc -l" "3" "$result"
173 fi
174
175 # Note: read with heredoc can hang if not implemented - use timeout
176 result=$(timeout 2 "$RUSH_BIN" -c 'read x <<EOF
177 test input
178 EOF
179 echo "$x"' 2>&1)
180 exit_code=$?
181 if [ "$result" = "test input" ]; then
182 pass "Here-document to read"
183 elif [ $exit_code -eq 124 ]; then
184 fail "Here-document to read" "test input" "(timeout - hangs)"
185 else
186 fail "Here-document to read" "test input" "$result"
187 fi
188
189 # =====================================
190 section "400. PARAMETER EXPANSION ${var:-default}"
191 # =====================================
192
193 result=$("$RUSH_BIN" -c 'unset x; echo ${x:-default}' 2>&1)
194 if [ "$result" = "default" ]; then
195 pass "\${var:-default} for unset variable"
196 else
197 fail "\${var:-default} for unset variable" "default" "$result"
198 fi
199
200 result=$("$RUSH_BIN" -c 'x=""; echo ${x:-default}' 2>&1)
201 if [ "$result" = "default" ]; then
202 pass "\${var:-default} for empty variable"
203 else
204 fail "\${var:-default} for empty variable" "default" "$result"
205 fi
206
207 result=$("$RUSH_BIN" -c 'x=value; echo ${x:-default}' 2>&1)
208 if [ "$result" = "value" ]; then
209 pass "\${var:-default} for set variable"
210 else
211 fail "\${var:-default} for set variable" "value" "$result"
212 fi
213
214 result=$("$RUSH_BIN" -c 'unset x; echo ${x-default}' 2>&1)
215 if [ "$result" = "default" ]; then
216 pass "\${var-default} for unset (no colon)"
217 else
218 fail "\${var-default} for unset (no colon)" "default" "$result"
219 fi
220
221 result=$("$RUSH_BIN" -c 'x=""; echo ${x-default}' 2>&1)
222 if [ "$result" = "" ]; then
223 pass "\${var-default} for empty (no colon)"
224 else
225 fail "\${var-default} for empty (no colon)" "(empty)" "$result"
226 fi
227
228 # =====================================
229 section "401. PARAMETER EXPANSION ${var:+alternate}"
230 # =====================================
231
232 result=$("$RUSH_BIN" -c 'x=value; echo ${x:+alternate}' 2>&1)
233 if [ "$result" = "alternate" ]; then
234 pass "\${var:+alternate} for set variable"
235 else
236 fail "\${var:+alternate} for set variable" "alternate" "$result"
237 fi
238
239 result=$("$RUSH_BIN" -c 'unset x; echo ${x:+alternate}' 2>&1)
240 if [ "$result" = "" ]; then
241 pass "\${var:+alternate} for unset variable"
242 else
243 fail "\${var:+alternate} for unset variable" "(empty)" "$result"
244 fi
245
246 result=$("$RUSH_BIN" -c 'x=""; echo ${x:+alternate}' 2>&1)
247 if [ "$result" = "" ]; then
248 pass "\${var:+alternate} for empty variable"
249 else
250 fail "\${var:+alternate} for empty variable" "(empty)" "$result"
251 fi
252
253 # =====================================
254 section "402. PARAMETER EXPANSION ${var:=assign}"
255 # =====================================
256
257 result=$("$RUSH_BIN" -c 'unset x; echo ${x:=assigned}; echo $x' 2>&1)
258 expected=$(printf "assigned\nassigned")
259 if [ "$result" = "$expected" ]; then
260 pass "\${var:=value} assigns when unset"
261 else
262 fail "\${var:=value} assigns when unset" "$expected" "$result"
263 fi
264
265 result=$("$RUSH_BIN" -c 'x=""; echo ${x:=assigned}; echo $x' 2>&1)
266 expected=$(printf "assigned\nassigned")
267 if [ "$result" = "$expected" ]; then
268 pass "\${var:=value} assigns when empty"
269 else
270 fail "\${var:=value} assigns when empty" "$expected" "$result"
271 fi
272
273 result=$("$RUSH_BIN" -c 'x=original; echo ${x:=assigned}; echo $x' 2>&1)
274 expected=$(printf "original\noriginal")
275 if [ "$result" = "$expected" ]; then
276 pass "\${var:=value} keeps original when set"
277 else
278 fail "\${var:=value} keeps original when set" "$expected" "$result"
279 fi
280
281 # =====================================
282 section "403. PARAMETER EXPANSION ${var:?error}"
283 # =====================================
284
285 result=$("$RUSH_BIN" -c 'x=value; echo ${x:?error message}' 2>&1)
286 if [ "$result" = "value" ]; then
287 pass "\${var:?error} returns value when set"
288 else
289 fail "\${var:?error} returns value when set" "value" "$result"
290 fi
291
292 result=$("$RUSH_BIN" -c 'unset x; echo ${x:?custom error}' 2>&1)
293 if echo "$result" | grep -qi "error\|custom"; then
294 pass "\${var:?error} shows error when unset"
295 else
296 fail "\${var:?error} shows error when unset" "error message" "$result"
297 fi
298
299 # =====================================
300 section "404. PARAMETER EXPANSION ${#var}"
301 # =====================================
302
303 result=$("$RUSH_BIN" -c 'x=hello; echo ${#x}' 2>&1)
304 if [ "$result" = "5" ]; then
305 pass "\${#var} string length"
306 else
307 fail "\${#var} string length" "5" "$result"
308 fi
309
310 result=$("$RUSH_BIN" -c 'x=""; echo ${#x}' 2>&1)
311 if [ "$result" = "0" ]; then
312 pass "\${#var} empty string length"
313 else
314 fail "\${#var} empty string length" "0" "$result"
315 fi
316
317 result=$("$RUSH_BIN" -c 'x="hello world"; echo ${#x}' 2>&1)
318 if [ "$result" = "11" ]; then
319 pass "\${#var} string with space"
320 else
321 fail "\${#var} string with space" "11" "$result"
322 fi
323
324 # =====================================
325 section "405. PARAMETER EXPANSION ${var%pattern}"
326 # =====================================
327
328 result=$("$RUSH_BIN" -c 'x="file.txt"; echo ${x%.txt}' 2>&1)
329 if [ "$result" = "file" ]; then
330 pass "\${var%pattern} removes shortest suffix"
331 else
332 fail "\${var%pattern} removes shortest suffix" "file" "$result"
333 fi
334
335 result=$("$RUSH_BIN" -c 'x="file.tar.gz"; echo ${x%.*}' 2>&1)
336 if [ "$result" = "file.tar" ]; then
337 pass "\${var%.*} removes extension"
338 else
339 fail "\${var%.*} removes extension" "file.tar" "$result"
340 fi
341
342 result=$("$RUSH_BIN" -c 'x="file.tar.gz"; echo ${x%%.*}' 2>&1)
343 if [ "$result" = "file" ]; then
344 pass "\${var%%.*} removes all extensions"
345 else
346 fail "\${var%%.*} removes all extensions" "file" "$result"
347 fi
348
349 # =====================================
350 section "406. PARAMETER EXPANSION ${var#pattern}"
351 # =====================================
352
353 result=$("$RUSH_BIN" -c 'x="/path/to/file"; echo ${x#*/}' 2>&1)
354 if [ "$result" = "path/to/file" ]; then
355 pass "\${var#*/} removes shortest prefix"
356 else
357 fail "\${var#*/} removes shortest prefix" "path/to/file" "$result"
358 fi
359
360 result=$("$RUSH_BIN" -c 'x="/path/to/file"; echo ${x##*/}' 2>&1)
361 if [ "$result" = "file" ]; then
362 pass "\${var##*/} basename extraction"
363 else
364 fail "\${var##*/} basename extraction" "file" "$result"
365 fi
366
367 result=$("$RUSH_BIN" -c 'x="prefix_name"; echo ${x#prefix_}' 2>&1)
368 if [ "$result" = "name" ]; then
369 pass "\${var#prefix} removes literal prefix"
370 else
371 fail "\${var#prefix} removes literal prefix" "name" "$result"
372 fi
373
374 # =====================================
375 section "407. BACKTICK COMMAND SUBSTITUTION"
376 # =====================================
377
378 result=$("$RUSH_BIN" -c 'echo `echo hello`' 2>&1)
379 if [ "$result" = "hello" ]; then
380 pass "Basic backtick substitution"
381 else
382 fail "Basic backtick substitution" "hello" "$result"
383 fi
384
385 result=$("$RUSH_BIN" -c 'x=`expr 2 + 3`; echo $x' 2>&1)
386 if [ "$result" = "5" ]; then
387 pass "Backtick with expr"
388 else
389 fail "Backtick with expr" "5" "$result"
390 fi
391
392 result=$("$RUSH_BIN" -c 'echo `echo \`echo nested\``' 2>&1)
393 if [ "$result" = "nested" ]; then
394 pass "Nested backtick substitution"
395 else
396 fail "Nested backtick substitution" "nested" "$result"
397 fi
398
399 # =====================================
400 section "408. COMMAND SUBSTITUTION EDGE CASES"
401 # =====================================
402
403 result=$("$RUSH_BIN" -c 'echo "$(echo "inner quotes")"' 2>&1)
404 if [ "$result" = "inner quotes" ]; then
405 pass "\$(...) with inner quotes"
406 else
407 fail "\$(...) with inner quotes" "inner quotes" "$result"
408 fi
409
410 result=$("$RUSH_BIN" -c 'echo $(echo $(echo nested))' 2>&1)
411 if [ "$result" = "nested" ]; then
412 pass "Nested \$(...) substitution"
413 else
414 fail "Nested \$(...) substitution" "nested" "$result"
415 fi
416
417 result=$("$RUSH_BIN" -c 'x=$(cat <<EOF
418 multi
419 line
420 EOF
421 ); echo "$x"' 2>&1)
422 expected=$(printf "multi\nline")
423 if [ "$result" = "$expected" ]; then
424 pass "\$(...) with here-document inside"
425 else
426 fail "\$(...) with here-document inside" "$expected" "$result"
427 fi
428
429 # =====================================
430 section "409. ARITHMETIC EXPANSION"
431 # =====================================
432
433 result=$("$RUSH_BIN" -c 'echo $((2 + 3))' 2>&1)
434 if [ "$result" = "5" ]; then
435 pass "\$((...)) addition"
436 else
437 fail "\$((...)) addition" "5" "$result"
438 fi
439
440 result=$("$RUSH_BIN" -c 'echo $((10 - 3))' 2>&1)
441 if [ "$result" = "7" ]; then
442 pass "\$((...)) subtraction"
443 else
444 fail "\$((...)) subtraction" "7" "$result"
445 fi
446
447 result=$("$RUSH_BIN" -c 'echo $((4 * 5))' 2>&1)
448 if [ "$result" = "20" ]; then
449 pass "\$((...)) multiplication"
450 else
451 fail "\$((...)) multiplication" "20" "$result"
452 fi
453
454 result=$("$RUSH_BIN" -c 'echo $((20 / 4))' 2>&1)
455 if [ "$result" = "5" ]; then
456 pass "\$((...)) division"
457 else
458 fail "\$((...)) division" "5" "$result"
459 fi
460
461 result=$("$RUSH_BIN" -c 'echo $((17 % 5))' 2>&1)
462 if [ "$result" = "2" ]; then
463 pass "\$((...)) modulo"
464 else
465 fail "\$((...)) modulo" "2" "$result"
466 fi
467
468 result=$("$RUSH_BIN" -c 'x=5; echo $((x * 2))' 2>&1)
469 if [ "$result" = "10" ]; then
470 pass "\$((...)) with variable (no \$)"
471 else
472 fail "\$((...)) with variable (no \$)" "10" "$result"
473 fi
474
475 result=$("$RUSH_BIN" -c 'x=5; echo $(($x * 2))' 2>&1)
476 if [ "$result" = "10" ]; then
477 pass "\$((...)) with \$variable"
478 else
479 fail "\$((...)) with \$variable" "10" "$result"
480 fi
481
482 result=$("$RUSH_BIN" -c 'echo $(( (2 + 3) * 4 ))' 2>&1)
483 if [ "$result" = "20" ]; then
484 pass "\$((...)) with parentheses"
485 else
486 fail "\$((...)) with parentheses" "20" "$result"
487 fi
488
489 result=$("$RUSH_BIN" -c 'echo $((-5 + 3))' 2>&1)
490 if [ "$result" = "-2" ]; then
491 pass "\$((...)) negative numbers"
492 else
493 fail "\$((...)) negative numbers" "-2" "$result"
494 fi
495
496 result=$("$RUSH_BIN" -c 'echo $((5 > 3))' 2>&1)
497 if [ "$result" = "1" ]; then
498 pass "\$((...)) greater than comparison"
499 else
500 fail "\$((...)) greater than comparison" "1" "$result"
501 fi
502
503 result=$("$RUSH_BIN" -c 'echo $((3 > 5))' 2>&1)
504 if [ "$result" = "0" ]; then
505 pass "\$((...)) greater than false"
506 else
507 fail "\$((...)) greater than false" "0" "$result"
508 fi
509
510 result=$("$RUSH_BIN" -c 'echo $((5 < 10))' 2>&1)
511 if [ "$result" = "1" ]; then
512 pass "\$((...)) less than comparison"
513 else
514 fail "\$((...)) less than comparison" "1" "$result"
515 fi
516
517 result=$("$RUSH_BIN" -c 'echo $((5 == 5))' 2>&1)
518 if [ "$result" = "1" ]; then
519 pass "\$((...)) equality"
520 else
521 fail "\$((...)) equality" "1" "$result"
522 fi
523
524 result=$("$RUSH_BIN" -c 'echo $((5 != 3))' 2>&1)
525 if [ "$result" = "1" ]; then
526 pass "\$((...)) inequality"
527 else
528 fail "\$((...)) inequality" "1" "$result"
529 fi
530
531 result=$("$RUSH_BIN" -c 'echo $((5 >= 5))' 2>&1)
532 if [ "$result" = "1" ]; then
533 pass "\$((...)) greater or equal"
534 else
535 fail "\$((...)) greater or equal" "1" "$result"
536 fi
537
538 result=$("$RUSH_BIN" -c 'echo $((3 <= 5))' 2>&1)
539 if [ "$result" = "1" ]; then
540 pass "\$((...)) less or equal"
541 else
542 fail "\$((...)) less or equal" "1" "$result"
543 fi
544
545 result=$("$RUSH_BIN" -c 'echo $((1 && 1))' 2>&1)
546 if [ "$result" = "1" ]; then
547 pass "\$((...)) logical AND"
548 else
549 fail "\$((...)) logical AND" "1" "$result"
550 fi
551
552 result=$("$RUSH_BIN" -c 'echo $((1 && 0))' 2>&1)
553 if [ "$result" = "0" ]; then
554 pass "\$((...)) logical AND false"
555 else
556 fail "\$((...)) logical AND false" "0" "$result"
557 fi
558
559 result=$("$RUSH_BIN" -c 'echo $((0 || 1))' 2>&1)
560 if [ "$result" = "1" ]; then
561 pass "\$((...)) logical OR"
562 else
563 fail "\$((...)) logical OR" "1" "$result"
564 fi
565
566 result=$("$RUSH_BIN" -c 'echo $((!0))' 2>&1)
567 if [ "$result" = "1" ]; then
568 pass "\$((...)) logical NOT"
569 else
570 fail "\$((...)) logical NOT" "1" "$result"
571 fi
572
573 result=$("$RUSH_BIN" -c 'echo $((5 & 3))' 2>&1)
574 if [ "$result" = "1" ]; then
575 pass "\$((...)) bitwise AND"
576 else
577 fail "\$((...)) bitwise AND" "1" "$result"
578 fi
579
580 result=$("$RUSH_BIN" -c 'echo $((5 | 3))' 2>&1)
581 if [ "$result" = "7" ]; then
582 pass "\$((...)) bitwise OR"
583 else
584 fail "\$((...)) bitwise OR" "7" "$result"
585 fi
586
587 result=$("$RUSH_BIN" -c 'echo $((5 ^ 3))' 2>&1)
588 if [ "$result" = "6" ]; then
589 pass "\$((...)) bitwise XOR"
590 else
591 fail "\$((...)) bitwise XOR" "6" "$result"
592 fi
593
594 result=$("$RUSH_BIN" -c 'echo $((1 << 4))' 2>&1)
595 if [ "$result" = "16" ]; then
596 pass "\$((...)) left shift"
597 else
598 fail "\$((...)) left shift" "16" "$result"
599 fi
600
601 result=$("$RUSH_BIN" -c 'echo $((16 >> 2))' 2>&1)
602 if [ "$result" = "4" ]; then
603 pass "\$((...)) right shift"
604 else
605 fail "\$((...)) right shift" "4" "$result"
606 fi
607
608 result=$("$RUSH_BIN" -c 'echo $((5 > 3 ? 10 : 20))' 2>&1)
609 if [ "$result" = "10" ]; then
610 pass "\$((...)) ternary true"
611 else
612 fail "\$((...)) ternary true" "10" "$result"
613 fi
614
615 result=$("$RUSH_BIN" -c 'echo $((5 < 3 ? 10 : 20))' 2>&1)
616 if [ "$result" = "20" ]; then
617 pass "\$((...)) ternary false"
618 else
619 fail "\$((...)) ternary false" "20" "$result"
620 fi
621
622 result=$("$RUSH_BIN" -c 'x=5; echo $((x += 3)); echo $x' 2>&1)
623 expected=$(printf "8\n8")
624 if [ "$result" = "$expected" ]; then
625 pass "\$((...)) += assignment"
626 else
627 fail "\$((...)) += assignment" "$expected" "$result"
628 fi
629
630 result=$("$RUSH_BIN" -c 'x=10; echo $((x -= 3)); echo $x' 2>&1)
631 expected=$(printf "7\n7")
632 if [ "$result" = "$expected" ]; then
633 pass "\$((...)) -= assignment"
634 else
635 fail "\$((...)) -= assignment" "$expected" "$result"
636 fi
637
638 result=$("$RUSH_BIN" -c 'x=5; echo $((x *= 3))' 2>&1)
639 if [ "$result" = "15" ]; then
640 pass "\$((...)) *= assignment"
641 else
642 fail "\$((...)) *= assignment" "15" "$result"
643 fi
644
645 result=$("$RUSH_BIN" -c 'x=5; echo $((++x)); echo $x' 2>&1)
646 expected=$(printf "6\n6")
647 if [ "$result" = "$expected" ]; then
648 pass "\$((...)) pre-increment"
649 else
650 fail "\$((...)) pre-increment" "$expected" "$result"
651 fi
652
653 result=$("$RUSH_BIN" -c 'x=5; echo $((x++)); echo $x' 2>&1)
654 expected=$(printf "5\n6")
655 if [ "$result" = "$expected" ]; then
656 pass "\$((...)) post-increment"
657 else
658 fail "\$((...)) post-increment" "$expected" "$result"
659 fi
660
661 result=$("$RUSH_BIN" -c 'x=5; echo $((--x)); echo $x' 2>&1)
662 expected=$(printf "4\n4")
663 if [ "$result" = "$expected" ]; then
664 pass "\$((...)) pre-decrement"
665 else
666 fail "\$((...)) pre-decrement" "$expected" "$result"
667 fi
668
669 result=$("$RUSH_BIN" -c 'x=5; echo $((x--)); echo $x' 2>&1)
670 expected=$(printf "5\n4")
671 if [ "$result" = "$expected" ]; then
672 pass "\$((...)) post-decrement"
673 else
674 fail "\$((...)) post-decrement" "$expected" "$result"
675 fi
676
677 result=$("$RUSH_BIN" -c 'echo $(( 2 + 3 * 4 ))' 2>&1)
678 if [ "$result" = "14" ]; then
679 pass "\$((...)) operator precedence"
680 else
681 fail "\$((...)) operator precedence" "14" "$result"
682 fi
683
684 result=$("$RUSH_BIN" -c 'a=2; b=3; echo $(( a * b + a ))' 2>&1)
685 if [ "$result" = "8" ]; then
686 pass "\$((...)) multiple variables"
687 else
688 fail "\$((...)) multiple variables" "8" "$result"
689 fi
690
691 # =====================================
692 section "410. TILDE EXPANSION"
693 # =====================================
694
695 result=$("$RUSH_BIN" -c 'echo ~' 2>&1)
696 if [ "$result" = "$HOME" ]; then
697 pass "~ expands to \$HOME"
698 else
699 fail "~ expands to \$HOME" "$HOME" "$result"
700 fi
701
702 result=$("$RUSH_BIN" -c 'echo ~/test' 2>&1)
703 if [ "$result" = "$HOME/test" ]; then
704 pass "~/path expands correctly"
705 else
706 fail "~/path expands correctly" "$HOME/test" "$result"
707 fi
708
709 result=$("$RUSH_BIN" -c 'x=~; echo $x' 2>&1)
710 if [ "$result" = "$HOME" ]; then
711 pass "~ in assignment expands"
712 else
713 fail "~ in assignment expands" "$HOME" "$result"
714 fi
715
716 # =====================================
717 # Summary
718 # =====================================
719 printf "\n"
720 printf "${BLUE}==========================================\n"
721 printf "POSIX Here-Document and Expansion Summary\n"
722 printf "==========================================${NC}\n"
723 printf "Passed: ${GREEN}%d${NC}\n" "$PASSED"
724 printf "Failed: ${RED}%d${NC}\n" "$FAILED"
725 printf "Skipped: ${YELLOW}%d${NC}\n" "$SKIPPED"
726 printf "Total: %d\n" "$((PASSED + FAILED + SKIPPED))"
727
728 if [ -n "$FAILED_TESTS_LIST" ]; then
729 printf "\n${RED}Failed tests:${NC}\n"
730 printf "%b" "$FAILED_TESTS_LIST"
731 fi
732
733 if [ "$FAILED" -gt 0 ]; then
734 exit 1
735 fi
736 exit 0