Bash · 11844 bytes Raw Blame History
1 #!/bin/sh
2 # =====================================
3 # POSIX Compliance printf Builtin Test Suite for rush
4 # =====================================
5 # Tests the printf builtin command per IEEE Std 1003.1-2017
6 # Section: Shell & Utilities - printf
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-printf]"
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 "358. PRINTF BASIC STRING FORMAT %s"
74 # =====================================
75
76 result=$("$RUSH_BIN" -c 'printf "%s\n" "hello"' 2>&1)
77 if [ "$result" = "hello" ]; then
78 pass "printf %s basic string"
79 else
80 fail "printf %s basic string" "hello" "$result"
81 fi
82
83 result=$("$RUSH_BIN" -c 'printf "%s %s\n" "hello" "world"' 2>&1)
84 if [ "$result" = "hello world" ]; then
85 pass "printf %s multiple arguments"
86 else
87 fail "printf %s multiple arguments" "hello world" "$result"
88 fi
89
90 result=$("$RUSH_BIN" -c 'printf "%s" ""' 2>&1)
91 if [ "$result" = "" ]; then
92 pass "printf %s empty string"
93 else
94 fail "printf %s empty string" "(empty)" "$result"
95 fi
96
97 result=$("$RUSH_BIN" -c 'printf "%.3s\n" "hello"' 2>&1)
98 if [ "$result" = "hel" ]; then
99 pass "printf %.3s precision truncates"
100 else
101 fail "printf %.3s precision truncates" "hel" "$result"
102 fi
103
104 result=$("$RUSH_BIN" -c 'printf "%10s\n" "hi"' 2>&1)
105 if [ "$result" = " hi" ]; then
106 pass "printf %10s width right-align"
107 else
108 fail "printf %10s width right-align" " hi" "$result"
109 fi
110
111 result=$("$RUSH_BIN" -c 'printf "%-10s|\n" "hi"' 2>&1)
112 if [ "$result" = "hi |" ]; then
113 pass "printf %-10s width left-align"
114 else
115 fail "printf %-10s width left-align" "hi |" "$result"
116 fi
117
118 # =====================================
119 section "359. PRINTF INTEGER FORMATS %d %i"
120 # =====================================
121
122 result=$("$RUSH_BIN" -c 'printf "%d\n" 42' 2>&1)
123 if [ "$result" = "42" ]; then
124 pass "printf %d basic decimal"
125 else
126 fail "printf %d basic decimal" "42" "$result"
127 fi
128
129 result=$("$RUSH_BIN" -c 'printf "%i\n" 42' 2>&1)
130 if [ "$result" = "42" ]; then
131 pass "printf %i basic integer"
132 else
133 fail "printf %i basic integer" "42" "$result"
134 fi
135
136 result=$("$RUSH_BIN" -c 'printf "%d\n" -42' 2>&1)
137 if [ "$result" = "-42" ]; then
138 pass "printf %d negative number"
139 else
140 fail "printf %d negative number" "-42" "$result"
141 fi
142
143 result=$("$RUSH_BIN" -c 'printf "%5d\n" 42' 2>&1)
144 if [ "$result" = " 42" ]; then
145 pass "printf %5d width padding"
146 else
147 fail "printf %5d width padding" " 42" "$result"
148 fi
149
150 result=$("$RUSH_BIN" -c 'printf "%05d\n" 42' 2>&1)
151 if [ "$result" = "00042" ]; then
152 pass "printf %05d zero padding"
153 else
154 fail "printf %05d zero padding" "00042" "$result"
155 fi
156
157 result=$("$RUSH_BIN" -c 'printf "%-5d|\n" 42' 2>&1)
158 if [ "$result" = "42 |" ]; then
159 pass "printf %-5d left-align"
160 else
161 fail "printf %-5d left-align" "42 |" "$result"
162 fi
163
164 result=$("$RUSH_BIN" -c 'printf "%+d\n" 42' 2>&1)
165 if [ "$result" = "+42" ]; then
166 pass "printf %+d explicit plus sign"
167 else
168 fail "printf %+d explicit plus sign" "+42" "$result"
169 fi
170
171 # =====================================
172 section "360. PRINTF OCTAL AND HEX FORMATS %o %x %X"
173 # =====================================
174
175 result=$("$RUSH_BIN" -c 'printf "%o\n" 8' 2>&1)
176 if [ "$result" = "10" ]; then
177 pass "printf %o octal format"
178 else
179 fail "printf %o octal format" "10" "$result"
180 fi
181
182 result=$("$RUSH_BIN" -c 'printf "%x\n" 255' 2>&1)
183 if [ "$result" = "ff" ]; then
184 pass "printf %x lowercase hex"
185 else
186 fail "printf %x lowercase hex" "ff" "$result"
187 fi
188
189 result=$("$RUSH_BIN" -c 'printf "%X\n" 255' 2>&1)
190 if [ "$result" = "FF" ]; then
191 pass "printf %X uppercase hex"
192 else
193 fail "printf %X uppercase hex" "FF" "$result"
194 fi
195
196 result=$("$RUSH_BIN" -c 'printf "%#x\n" 255' 2>&1)
197 if [ "$result" = "0xff" ]; then
198 pass "printf %#x alternate form"
199 else
200 fail "printf %#x alternate form" "0xff" "$result"
201 fi
202
203 result=$("$RUSH_BIN" -c 'printf "%#o\n" 8' 2>&1)
204 if [ "$result" = "010" ]; then
205 pass "printf %#o alternate octal form"
206 else
207 fail "printf %#o alternate octal form" "010" "$result"
208 fi
209
210 # =====================================
211 section "361. PRINTF CHARACTER FORMAT %c"
212 # =====================================
213
214 result=$("$RUSH_BIN" -c 'printf "%c\n" A' 2>&1)
215 if [ "$result" = "A" ]; then
216 pass "printf %c single character"
217 else
218 fail "printf %c single character" "A" "$result"
219 fi
220
221 result=$("$RUSH_BIN" -c 'printf "%c\n" "hello"' 2>&1)
222 if [ "$result" = "h" ]; then
223 pass "printf %c first char of string"
224 else
225 fail "printf %c first char of string" "h" "$result"
226 fi
227
228 result=$("$RUSH_BIN" -c 'printf "%c%c%c\n" a b c' 2>&1)
229 if [ "$result" = "abc" ]; then
230 pass "printf %c multiple chars"
231 else
232 fail "printf %c multiple chars" "abc" "$result"
233 fi
234
235 # =====================================
236 section "362. PRINTF ESCAPE SEQUENCES"
237 # =====================================
238
239 result=$("$RUSH_BIN" -c 'printf "hello\nworld\n"' 2>&1)
240 expected=$(printf "hello\nworld")
241 if [ "$result" = "$expected" ]; then
242 pass "printf \\n newline"
243 else
244 fail "printf \\n newline" "$expected" "$result"
245 fi
246
247 result=$("$RUSH_BIN" -c 'printf "a\tb\n"' 2>&1)
248 expected=$(printf "a\tb")
249 if [ "$result" = "$expected" ]; then
250 pass "printf \\t tab"
251 else
252 fail "printf \\t tab" "$expected" "$result"
253 fi
254
255 result=$("$RUSH_BIN" -c 'printf "back\\\\slash\n"' 2>&1)
256 if [ "$result" = 'back\slash' ]; then
257 pass "printf \\\\ literal backslash"
258 else
259 fail "printf \\\\ literal backslash" 'back\slash' "$result"
260 fi
261
262 result=$("$RUSH_BIN" -c 'printf "100%%\n"' 2>&1)
263 if [ "$result" = "100%" ]; then
264 pass "printf %% literal percent"
265 else
266 fail "printf %% literal percent" "100%" "$result"
267 fi
268
269 result=$("$RUSH_BIN" -c 'printf "\101\n"' 2>&1)
270 if [ "$result" = "A" ]; then
271 pass "printf \\NNN octal escape"
272 else
273 fail "printf \\NNN octal escape" "A" "$result"
274 fi
275
276 # =====================================
277 section "363. PRINTF %b ESCAPE INTERPRETATION"
278 # =====================================
279
280 result=$("$RUSH_BIN" -c 'printf "%b\n" "hello\nworld"' 2>&1)
281 expected=$(printf "hello\nworld")
282 if [ "$result" = "$expected" ]; then
283 pass "printf %b interprets backslash escapes"
284 else
285 fail "printf %b interprets backslash escapes" "(newline)" "$result"
286 fi
287
288 result=$("$RUSH_BIN" -c 'printf "%b\n" "tab\there"' 2>&1)
289 expected=$(printf "tab\there")
290 if [ "$result" = "$expected" ]; then
291 pass "printf %b interprets \\t"
292 else
293 fail "printf %b interprets \\t" "(tab)" "$result"
294 fi
295
296 # =====================================
297 section "364. PRINTF FORMAT REUSE"
298 # =====================================
299
300 result=$("$RUSH_BIN" -c 'printf "%s\n" one two three' 2>&1)
301 expected=$(printf "one\ntwo\nthree")
302 if [ "$result" = "$expected" ]; then
303 pass "printf format reused for extra args"
304 else
305 fail "printf format reused for extra args" "$expected" "$result"
306 fi
307
308 result=$("$RUSH_BIN" -c 'printf "%d " 1 2 3 4 5; printf "\n"' 2>&1)
309 if [ "$result" = "1 2 3 4 5 " ]; then
310 pass "printf %d reused for multiple integers"
311 else
312 fail "printf %d reused for multiple integers" "1 2 3 4 5 " "$result"
313 fi
314
315 # =====================================
316 section "365. PRINTF WITH VARIABLES"
317 # =====================================
318
319 result=$("$RUSH_BIN" -c 'x="hello"; printf "%s\n" "$x"' 2>&1)
320 if [ "$result" = "hello" ]; then
321 pass "printf with variable argument"
322 else
323 fail "printf with variable argument" "hello" "$result"
324 fi
325
326 result=$("$RUSH_BIN" -c 'n=42; printf "Value: %d\n" "$n"' 2>&1)
327 if [ "$result" = "Value: 42" ]; then
328 pass "printf integer from variable"
329 else
330 fail "printf integer from variable" "Value: 42" "$result"
331 fi
332
333 result=$("$RUSH_BIN" -c 'fmt="%s: %d\n"; printf "$fmt" name 42' 2>&1)
334 if [ "$result" = "name: 42" ]; then
335 pass "printf format from variable"
336 else
337 fail "printf format from variable" "name: 42" "$result"
338 fi
339
340 # =====================================
341 section "366. PRINTF DYNAMIC WIDTH AND PRECISION"
342 # =====================================
343
344 result=$("$RUSH_BIN" -c 'printf "%*s\n" 10 hi' 2>&1)
345 if [ "$result" = " hi" ]; then
346 pass "printf %*s dynamic width"
347 else
348 fail "printf %*s dynamic width" " hi" "$result"
349 fi
350
351 result=$("$RUSH_BIN" -c 'printf "%.*s\n" 3 hello' 2>&1)
352 if [ "$result" = "hel" ]; then
353 pass "printf %.*s dynamic precision"
354 else
355 fail "printf %.*s dynamic precision" "hel" "$result"
356 fi
357
358 result=$("$RUSH_BIN" -c 'printf "%*.*s\n" 10 3 hello' 2>&1)
359 if [ "$result" = " hel" ]; then
360 pass "printf %*.*s dynamic width and precision"
361 else
362 fail "printf %*.*s dynamic width and precision" " hel" "$result"
363 fi
364
365 # =====================================
366 section "367. PRINTF RETURN VALUE"
367 # =====================================
368
369 result=$("$RUSH_BIN" -c 'printf "%s" "test"; echo $?' 2>&1)
370 if echo "$result" | grep -q "0"; then
371 pass "printf returns 0 on success"
372 else
373 fail "printf returns 0 on success" "0" "$result"
374 fi
375
376 # =====================================
377 section "368. PRINTF EDGE CASES"
378 # =====================================
379
380 result=$("$RUSH_BIN" -c 'printf "%d\n" 0' 2>&1)
381 if [ "$result" = "0" ]; then
382 pass "printf %d zero"
383 else
384 fail "printf %d zero" "0" "$result"
385 fi
386
387 result=$("$RUSH_BIN" -c 'printf "%s\n" ""' 2>&1)
388 if [ "$result" = "" ]; then
389 pass "printf empty argument"
390 else
391 fail "printf empty argument" "(empty)" "$result"
392 fi
393
394 result=$("$RUSH_BIN" -c 'printf "no format"' 2>&1)
395 if [ "$result" = "no format" ]; then
396 pass "printf literal string no format"
397 else
398 fail "printf literal string no format" "no format" "$result"
399 fi
400
401 result=$("$RUSH_BIN" -c 'printf ""' 2>&1)
402 if [ "$result" = "" ]; then
403 pass "printf empty format string"
404 else
405 fail "printf empty format string" "(empty)" "$result"
406 fi
407
408 # =====================================
409 # Summary
410 # =====================================
411 printf "\n"
412 printf "${BLUE}==========================================\n"
413 printf "POSIX printf Builtin Test Summary\n"
414 printf "==========================================${NC}\n"
415 printf "Passed: ${GREEN}%d${NC}\n" "$PASSED"
416 printf "Failed: ${RED}%d${NC}\n" "$FAILED"
417 printf "Skipped: ${YELLOW}%d${NC}\n" "$SKIPPED"
418 printf "Total: %d\n" "$((PASSED + FAILED + SKIPPED))"
419
420 if [ -n "$FAILED_TESTS_LIST" ]; then
421 printf "\n${RED}Failed tests:${NC}\n"
422 printf "%b" "$FAILED_TESTS_LIST"
423 fi
424
425 if [ "$FAILED" -gt 0 ]; then
426 exit 1
427 fi
428 exit 0