Bash · 6571 bytes Raw Blame History
1 #!/bin/sh
2 # =====================================
3 # POSIX Redirection Gap Tests
4 # =====================================
5 # Tests for POSIX redirection operators
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-redirect]"
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 # BASIC REDIRECTIONS
79 # ============================================================================
80
81 section "1. OUTPUT REDIRECTION"
82 compare_posix_output "redir out" 'echo test > /tmp/r$$; cat /tmp/r$$; rm /tmp/r$$'
83 compare_posix_output "redir in" 'echo test > /tmp/r$$; cat < /tmp/r$$; rm /tmp/r$$'
84 compare_posix_output "redir append" 'echo a > /tmp/r$$; echo b >> /tmp/r$$; cat /tmp/r$$; rm /tmp/r$$'
85 compare_posix_output "redir stderr" 'ls /nonexistent$$ 2>/dev/null; echo done'
86
87 section "2. READ/WRITE REDIRECTION"
88 compare_posix_exit_code "redirect <> creates file" "echo test <> /tmp/posix_gaps_rw_$$; test -f /tmp/posix_gaps_rw_$$; rm -f /tmp/posix_gaps_rw_$$"
89 compare_posix_exit_code "redirect <> opens existing" "echo data > /tmp/posix_gaps_rw2_$$; cat <> /tmp/posix_gaps_rw2_$$ 2>/dev/null; rm -f /tmp/posix_gaps_rw2_$$"
90
91 # ============================================================================
92 # ADVANCED REDIRECTIONS
93 # ============================================================================
94
95 section "3. FD REDIRECTION"
96 compare_posix_output "redirect order matters" "echo test 2>&1 >/dev/null | wc -l"
97 compare_posix_output "redirect to same fd" "echo test >&1 2>&1"
98 compare_posix_output "redirect append" "echo a > /tmp/posix_gaps_redir_$$; echo b >> /tmp/posix_gaps_redir_$$; wc -l < /tmp/posix_gaps_redir_$$; rm -f /tmp/posix_gaps_redir_$$"
99
100 section "4. HERE DOCUMENTS IN REDIRECT"
101 compare_posix_output "redirect here-string alternative" "cat <<EOF
102 test
103 EOF"
104 compare_posix_output "redirect duplicate stdin" "cat <&0 <<EOF
105 input
106 EOF"
107
108 section "5. LOOP REDIRECTIONS"
109 compare_posix_output "redirect in loop" 'for i in 1 2 3; do echo $i; done > /tmp/redir_test_$$; cat /tmp/redir_test_$$; rm /tmp/redir_test_$$'
110 compare_posix_output "append multiple" 'echo a >> /tmp/app_test_$$; echo b >> /tmp/app_test_$$; cat /tmp/app_test_$$; rm /tmp/app_test_$$'
111 compare_posix_output "stderr to file" 'ls /nonexistent 2>/tmp/err_test_$$ || cat /tmp/err_test_$$ | wc -l; rm -f /tmp/err_test_$$'
112
113 # ============================================================================
114 # IFS FIELD SPLITTING
115 # ============================================================================
116
117 section "6. IFS FIELD SPLITTING"
118 compare_posix_output "IFS mixed ws and non-ws" "IFS=': \t'; VAR='a:b c:d'; set -- \$VAR; echo \$# \$1 \$2 \$3 \$4"
119 compare_posix_output "IFS multiple delimiters" "IFS=',:'; VAR='a,b:c,d'; set -- \$VAR; echo \$#"
120 compare_posix_output "IFS trailing delimiters" "IFS=:; VAR='a:b:c:'; set -- \$VAR; echo \$#"
121 compare_posix_output "IFS leading and trailing" "IFS=:; VAR=':a:b:'; set -- \$VAR; echo \$# \$1 \$2"
122 compare_posix_output "IFS consecutive delimiters" "IFS=:; VAR='a::b'; set -- \$VAR; echo \$# \$1 \$2 \$3"
123 compare_posix_output "IFS whitespace collapsing" "IFS=' '; VAR='a b c'; set -- \$VAR; echo \$#"
124
125 # ============================================================================
126 # COMMENTS
127 # ============================================================================
128
129 section "7. COMMENTS"
130 compare_posix_output "comment inline" 'echo yes # comment'
131 compare_posix_output "comment in dquote" 'echo "not # comment"'
132 compare_posix_output "comment in squote" "echo 'not # comment'"
133
134 # ============================================================================
135 # EXIT CODES
136 # ============================================================================
137
138 section "8. EXIT CODES"
139 compare_posix_exit_code "true exits 0" "true"
140 compare_posix_exit_code "false exits 1" "false"
141 compare_posix_exit_code "exit 0" "(exit 0)"
142 compare_posix_output "exit code chain" "true; echo \$?"
143 compare_posix_output "backtick vs dollar-paren" "a=\`echo test\`; b=\$(echo test); test \"\$a\" = \"\$b\" && echo same"
144
145 # Summary
146 printf "\n==========================================\n"
147 printf "REDIRECTION GAP TEST RESULTS\n"
148 printf "==========================================\n"
149 printf "${GREEN}Passed:${NC} %d\n" "$PASSED"
150 printf "${RED}Failed:${NC} %d\n" "$FAILED"
151 printf "Total: %d\n" "$((PASSED + FAILED))"
152 if [ "$FAILED" -gt 0 ]; then
153 printf "\n${RED}Failed tests:${NC}\n%b" "$FAILED_TESTS_LIST"
154 exit 1
155 fi
156 exit 0