| 1 | #!/bin/sh |
| 2 | # ===================================== |
| 3 | # POSIX Here-Document Gap Tests |
| 4 | # ===================================== |
| 5 | # Tests for POSIX here-document functionality |
| 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-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 | 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 | # HEREDOC TESTS |
| 79 | # ============================================================================ |
| 80 | |
| 81 | section "1. BASIC HEREDOC" |
| 82 | compare_posix_output "simple" 'cat <<EOF |
| 83 | hello |
| 84 | EOF' |
| 85 | compare_posix_output "multiline" 'cat <<EOF |
| 86 | line1 |
| 87 | line2 |
| 88 | EOF' |
| 89 | compare_posix_output "empty" 'cat <<EOF |
| 90 | EOF' |
| 91 | |
| 92 | section "2. VARIABLE EXPANSION" |
| 93 | compare_posix_output "var expansion" 'x=value; cat <<EOF |
| 94 | $x |
| 95 | EOF' |
| 96 | compare_posix_output "var with text" 'X=world; cat <<EOF |
| 97 | hello $X |
| 98 | EOF' |
| 99 | |
| 100 | section "3. COMMAND SUBSTITUTION" |
| 101 | compare_posix_output "cmd sub" 'cat <<EOF |
| 102 | $(echo hello) |
| 103 | EOF' |
| 104 | |
| 105 | section "4. ARITHMETIC EXPANSION" |
| 106 | compare_posix_output "arith" 'cat <<EOF |
| 107 | $((1+2)) |
| 108 | EOF' |
| 109 | |
| 110 | section "5. QUOTED DELIMITER" |
| 111 | compare_posix_output "single quoted" "cat <<'EOF' |
| 112 | \$x \$(cmd) |
| 113 | EOF" |
| 114 | compare_posix_output "double quoted" 'cat <<"EOF" |
| 115 | $x $(cmd) |
| 116 | EOF' |
| 117 | compare_posix_output "quoted no expand" "cat <<'EOF' |
| 118 | \$notvar |
| 119 | EOF" |
| 120 | |
| 121 | section "6. TAB STRIPPING (<<-)" |
| 122 | compare_posix_output "dash strips tabs" "cat <<-EOF |
| 123 | line1 |
| 124 | line2 |
| 125 | line3 |
| 126 | EOF" |
| 127 | compare_posix_output "dash mixed" "cat <<-EOF |
| 128 | tab_line |
| 129 | space_line |
| 130 | EOF" |
| 131 | compare_posix_output "dash with vars" "VAR=test; cat <<-EOF |
| 132 | value=\$VAR |
| 133 | end |
| 134 | EOF" |
| 135 | compare_posix_output "dash quoted" "cat <<-'EOF' |
| 136 | \$VAR |
| 137 | literal |
| 138 | EOF" |
| 139 | compare_posix_output "dash simple" 'cat <<-EOF |
| 140 | tabbed |
| 141 | EOF' |
| 142 | |
| 143 | section "7. MULTIPLE HEREDOCS" |
| 144 | compare_posix_output "double heredoc" 'cat <<EOF1; cat <<EOF2 |
| 145 | first |
| 146 | EOF1 |
| 147 | second |
| 148 | EOF2' |
| 149 | |
| 150 | # Summary |
| 151 | printf "\n==========================================\n" |
| 152 | printf "HEREDOC GAP TEST RESULTS\n" |
| 153 | printf "==========================================\n" |
| 154 | printf "${GREEN}Passed:${NC} %d\n" "$PASSED" |
| 155 | printf "${RED}Failed:${NC} %d\n" "$FAILED" |
| 156 | printf "Total: %d\n" "$((PASSED + FAILED))" |
| 157 | if [ "$FAILED" -gt 0 ]; then |
| 158 | printf "\n${RED}Failed tests:${NC}\n%b" "$FAILED_TESTS_LIST" |
| 159 | exit 1 |
| 160 | fi |
| 161 | exit 0 |