Bash · 5964 bytes Raw Blame History
1 #!/bin/sh
2 # =====================================
3 # POSIX Arithmetic Gap Tests
4 # =====================================
5 # Tests for POSIX arithmetic expansion
6 # Split from posix_compliance_gaps.sh for better organization
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="[gaps-arithmetic]"
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 SHELL_BIN="${SHELL_BIN:?ERROR: SHELL_BIN must be set}"
28 BASH_REF="${BASH_REF:-bash}"
29
30 # Check if shell binary exists
31 if [ ! -x "$SHELL_BIN" ]; then
32 printf "${RED}ERROR${NC}: shell binary not found at $SHELL_BIN\n"
33 printf "Please set SHELL_BIN or set SHELL_BIN environment variable\n"
34 exit 1
35 fi
36
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 printf " posix: %s\n" "$2"; fi
49 if [ -n "$3" ]; then printf " shell: %s\n" "$3"; fi
50 FAILED=$((FAILED + 1))
51 }
52
53 section() {
54 CURRENT_SECTION=$(echo "$1" | grep -oE '^[0-9]+' || echo "0")
55 TEST_NUM=0
56 printf "\n${BLUE}==========================================\n%s\n==========================================${NC}\n" "$1"
57 }
58
59 normalize_output() { sed -e 's|^[^ ]*/[a-z]*sh[0-9]*: |sh: |' -e 's|^[a-z]*sh[0-9]*: |sh: |' -e 's/line [0-9]*: //'; }
60
61 compare_posix_output() {
62 test_name="$1"; command="$2"
63 posix_out=$("$BASH_REF" -c "$command" 2>&1 | normalize_output)
64 shell_out=$("$SHELL_BIN" -c "$command" 2>&1 | normalize_output)
65 if [ "$posix_out" = "$shell_out" ]; then pass "$test_name"
66 else fail "$test_name" "$posix_out" "$shell_out"; fi
67 }
68
69 compare_posix_exit_code() {
70 test_name="$1"; command="$2"
71 "$BASH_REF" -c "$command" >/dev/null 2>&1; posix_code=$?
72 "$SHELL_BIN" -c "$command" >/dev/null 2>&1; shell_code=$?
73 if [ "$posix_code" = "$shell_code" ]; then pass "$test_name"
74 else fail "$test_name" "exit $posix_code" "exit $shell_code"; fi
75 }
76
77 # ============================================================================
78 # ARITHMETIC TESTS
79 # ============================================================================
80
81 section "1. BASIC OPERATORS"
82 compare_posix_output "add" 'echo $((5+3))'
83 compare_posix_output "sub" 'echo $((5-3))'
84 compare_posix_output "mul" 'echo $((5*3))'
85 compare_posix_output "div" 'echo $((15/3))'
86 compare_posix_output "mod" 'echo $((17%5))'
87 compare_posix_output "neg" 'echo $((-5))'
88
89 section "2. SPACING"
90 compare_posix_output "with spaces" 'echo $(( 1 + 2 ))'
91 compare_posix_output "mixed spacing" 'echo $(( 5 +3 ))'
92
93 section "3. COMPARISONS"
94 compare_posix_output "lt" 'echo $((3<5))'
95 compare_posix_output "gt" 'echo $((5>3))'
96 compare_posix_output "le" 'echo $((5<=5))'
97 compare_posix_output "ge" 'echo $((5>=5))'
98 compare_posix_output "eq" 'echo $((5==5))'
99 compare_posix_output "ne" 'echo $((5!=3))'
100
101 section "4. LOGICAL"
102 compare_posix_output "and" 'echo $((1&&1))'
103 compare_posix_output "or" 'echo $((0||1))'
104 compare_posix_output "not" 'echo $((!0))'
105
106 section "5. BITWISE"
107 compare_posix_output "band" 'echo $((12&10))'
108 compare_posix_output "bor" 'echo $((12|10))'
109 compare_posix_output "bxor" 'echo $((12^10))'
110 compare_posix_output "lshift" 'echo $((1<<4))'
111 compare_posix_output "rshift" 'echo $((16>>2))'
112
113 section "6. TERNARY"
114 compare_posix_output "ternary t" 'echo $((1?10:20))'
115 compare_posix_output "ternary f" 'echo $((0?10:20))'
116 compare_posix_output "ternary expr" 'echo $((5>3?1:0))'
117
118 section "7. ASSIGNMENT OPS"
119 compare_posix_output "pluseq" 'x=5; echo $((x+=3))'
120 compare_posix_output "minuseq" 'x=5; echo $((x-=3))'
121 compare_posix_output "muleq" 'x=5; echo $((x*=3))'
122 compare_posix_output "diveq" 'x=15; echo $((x/=3))'
123
124 section "8. PRECEDENCE"
125 compare_posix_output "mul before add" 'echo $((2+3*4))'
126 compare_posix_output "parens override" 'echo $(((2+3)*4))'
127 compare_posix_output "div add" 'echo $((10/2+3))'
128 compare_posix_output "nested parens" 'echo $(((2 + 3) * (4 + 5)))'
129
130 section "9. VARIABLES"
131 compare_posix_output "var simple" 'x=5; echo $((x))'
132 compare_posix_output "var expr" 'a=3; b=4; echo $((a*a+b*b))'
133 compare_posix_output "var unset" 'unset z; echo $((z))'
134 compare_posix_output "var ref" 'X=10; echo $((X + 5))'
135
136 section "10. NUMBER BASES"
137 compare_posix_output "octal" 'echo $((010))'
138 compare_posix_output "hex" 'echo $((0x10))'
139 compare_posix_output "hex lowercase" 'echo $((0xa))'
140
141 section "11. INCREMENT/DECREMENT"
142 compare_posix_output "preinc" 'x=5; echo $((++x))'
143 compare_posix_output "predec" 'x=5; echo $((--x))'
144 compare_posix_output "postinc" 'x=5; echo $((x++))'
145 compare_posix_output "postdec" 'x=5; echo $((x--))'
146
147 section "12. EDGE CASES"
148 compare_posix_output "negative numbers" "echo \$((-5 * -3))"
149 compare_posix_output "large numbers" "echo \$((999999 + 1))"
150 compare_posix_output "modulo negative" "echo \$((-17 % 5))"
151 compare_posix_output "comparison chain" "echo \$((5 > 3 && 10 > 8))"
152 compare_posix_output "unary minus" "X=5; echo \$((-X))"
153 compare_posix_output "unary plus" "X=5; echo \$((+X))"
154 compare_posix_output "zero" 'echo $((0))'
155 compare_posix_output "nested arith" 'echo $(($((1 + 2)) + 3))'
156 compare_posix_exit_code "division by zero" "echo \$((5 / 0)) 2>/dev/null"
157
158 # Summary
159 printf "\n==========================================\n"
160 printf "ARITHMETIC GAP TEST RESULTS\n"
161 printf "==========================================\n"
162 printf "${GREEN}Passed:${NC} %d\n" "$PASSED"
163 printf "${RED}Failed:${NC} %d\n" "$FAILED"
164 printf "Total: %d\n" "$((PASSED + FAILED))"
165 if [ "$FAILED" -gt 0 ]; then
166 printf "\n${RED}Failed tests:${NC}\n%b" "$FAILED_TESTS_LIST"
167 exit 1
168 fi
169 exit 0