Bash · 12891 bytes Raw Blame History
1 #!/bin/bash
2 # =====================================
3 # Memory Pool Validation Test Suite
4 # =====================================
5 # Focused test suite that validates memory pooling behavior
6 # without hitting known fortsh limitations
7
8 # Colors for output
9 RED='\033[0;31m'
10 GREEN='\033[0;32m'
11 YELLOW='\033[1;33m'
12 BLUE='\033[0;34m'
13 CYAN='\033[0;36m'
14 MAGENTA='\033[0;35m'
15 NC='\033[0m'
16
17 # Test counters
18 PASSED=0
19 FAILED=0
20 SKIPPED=0
21
22 # Test configuration
23 SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
24 FORTSH_DIR=$(cd "$SCRIPT_DIR/.." && pwd)
25 TEST_WORK_DIR="/tmp/mempool_validation_$$"
26
27 # Create work directory
28 mkdir -p "$TEST_WORK_DIR"
29 cd "$TEST_WORK_DIR" || exit 1
30
31 # Cleanup on exit
32 cleanup() {
33 cd "$FORTSH_DIR" || exit 1
34 rm -rf "$TEST_WORK_DIR"
35 }
36 trap cleanup EXIT INT TERM
37
38 # Test result functions
39 pass() {
40 printf "${GREEN}${NC} %s\n" "$1"
41 PASSED=$((PASSED + 1))
42 }
43
44 fail() {
45 printf "${RED}${NC} %s\n" "$1"
46 if [ -n "$2" ]; then
47 printf " ${RED}${NC} %s\n" "$2"
48 fi
49 FAILED=$((FAILED + 1))
50 }
51
52 skip() {
53 printf "${YELLOW}${NC} %s\n" "$1"
54 if [ -n "$2" ]; then
55 printf " ${YELLOW}${NC} %s\n" "$2"
56 fi
57 SKIPPED=$((SKIPPED + 1))
58 }
59
60 section() {
61 printf "\n${MAGENTA}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n"
62 printf "${MAGENTA}${NC} ${BLUE}%s${NC}\n" "$1"
63 printf "${MAGENTA}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n"
64 }
65
66 subsection() {
67 printf "\n${CYAN}▸ %s${NC}\n" "$1"
68 }
69
70 # =====================================
71 # BUILD PHASE
72 # =====================================
73 section "BUILD VALIDATION"
74
75 cd "$FORTSH_DIR" || exit 1
76
77 subsection "Building with memory pooling (MEMPOOL=1)"
78 make clean > /dev/null 2>&1
79 if MEMPOOL=1 make > /tmp/build_pooled.log 2>&1; then
80 pass "Pooled build successful"
81 POOLED_BIN="$FORTSH_DIR/bin/fortsh"
82 else
83 fail "Pooled build failed" "Check /tmp/build_pooled.log"
84 exit 1
85 fi
86
87 subsection "Verifying pool symbols in binary"
88 if nm "$POOLED_BIN" 2>/dev/null | grep -q "pool_get_string\|dashboard_track"; then
89 pass "Pool symbols present in binary"
90 else
91 fail "Pool symbols missing" "Binary may not have pooling enabled"
92 fi
93
94 cd "$TEST_WORK_DIR" || exit 1
95
96 # =====================================
97 # POOL-SPECIFIC BEHAVIOR TESTS
98 # =====================================
99 section "MEMORY POOL BEHAVIOR VALIDATION"
100
101 subsection "String allocation patterns"
102 # Test that pooled strings work correctly
103 cat > test_alloc.sh << 'EOF'
104 # Rapid string allocation/deallocation
105 for i in 1 2 3 4 5; do
106 X="String_$i"
107 Y="${X}_modified"
108 Z="${Y##*_}"
109 echo "$Z"
110 done
111 EOF
112
113 OUTPUT=$("$POOLED_BIN" < test_alloc.sh 2>&1)
114 EXPECTED=$'modified\nmodified\nmodified\nmodified\nmodified'
115
116 if [ "$OUTPUT" = "$EXPECTED" ]; then
117 pass "String allocation/deallocation pattern correct"
118 else
119 fail "String allocation pattern incorrect" "Got: $OUTPUT"
120 fi
121
122 subsection "Buffer size categories"
123 # Test different buffer sizes (should use different buckets)
124 "$POOLED_BIN" -c 'TINY="A"; echo ${#TINY}' 2>&1 | grep -q "^1$" && pass "Tiny strings (bucket 0)" || fail "Tiny string handling"
125 "$POOLED_BIN" -c 'SMALL=$(printf "%.0sX" {1..50}); echo ${#SMALL}' 2>&1 | grep -q "^50$" && pass "Small strings (bucket 1)" || fail "Small string handling"
126 "$POOLED_BIN" -c 'MEDIUM=$(printf "%.0sX" {1..200}); echo ${#MEDIUM}' 2>&1 | grep -q "^200$" && pass "Medium strings (bucket 2)" || fail "Medium string handling"
127 "$POOLED_BIN" -c 'LARGE=$(printf "%.0sX" {1..1000}); echo ${#LARGE}' 2>&1 | grep -q "^1000$" && pass "Large strings (bucket 3)" || fail "Large string handling"
128
129 subsection "Empty string handling"
130 "$POOLED_BIN" -c 'X=""; Y="${X}"; echo "[$Y]"' 2>&1 | grep -q "^\[\]$" && pass "Empty strings preserved" || fail "Empty string handling"
131
132 subsection "String modification semantics"
133 OUTPUT=$("$POOLED_BIN" -c 'X="original"; Y="${X:0:4}"; X="changed"; echo "$Y"' 2>&1)
134 if [ "$OUTPUT" = "orig" ]; then
135 pass "String copies are independent"
136 else
137 fail "String modification semantics" "Got: $OUTPUT"
138 fi
139
140 # =====================================
141 # MODULE-SPECIFIC TESTS
142 # =====================================
143 section "MODULE INTEGRATION TESTS"
144
145 subsection "Parser module - Tokenization"
146 OUTPUT=$("$POOLED_BIN" -c 'echo "test" && echo "pass"' 2>&1)
147 EXPECTED=$'test\npass'
148 [ "$OUTPUT" = "$EXPECTED" ] && pass "Parser tokenization" || fail "Parser tokenization"
149
150 subsection "Expansion module - Parameter expansion"
151 OUTPUT=$("$POOLED_BIN" -c 'FILE="/path/to/file.tar.gz"; echo "${FILE##*/}"' 2>&1)
152 [ "$OUTPUT" = "file.tar.gz" ] && pass "Parameter expansion" || fail "Parameter expansion" "Got: $OUTPUT"
153
154 subsection "Expansion module - Complex patterns"
155 OUTPUT=$("$POOLED_BIN" -c 'VAR=foo.bar.baz; echo "${VAR%.*}" "${VAR%%.*}"' 2>&1)
156 [ "$OUTPUT" = "foo.bar foo" ] && pass "Complex expansion patterns" || fail "Complex expansion" "Got: $OUTPUT"
157
158 subsection "Variables module - Assignment chains"
159 OUTPUT=$("$POOLED_BIN" -c 'A=one; B="$A"; C="$B"; echo "$C"' 2>&1)
160 [ "$OUTPUT" = "one" ] && pass "Variable assignment chains" || fail "Variable chains" "Got: $OUTPUT"
161
162 subsection "Variables module - Arrays"
163 # Note: fortsh has limited array support
164 "$POOLED_BIN" -c 'arr="a b c"; for x in $arr; do echo $x; done' 2>&1 | grep -q "^a$" && pass "Array-like iteration" || fail "Array iteration"
165
166 subsection "Executor module - Command substitution"
167 OUTPUT=$("$POOLED_BIN" -c 'X=$(echo "test"); echo "$X"' 2>&1)
168 [ "$OUTPUT" = "test" ] && pass "Command substitution" || fail "Command substitution" "Got: $OUTPUT"
169
170 subsection "Executor module - Pipeline buffers"
171 OUTPUT=$("$POOLED_BIN" -c 'echo "test" | grep "test" | wc -l' 2>&1 | tr -d ' ')
172 [ "$OUTPUT" = "1" ] && pass "Pipeline buffer handling" || fail "Pipeline buffers" "Got: $OUTPUT"
173
174 subsection "Builtins module - cd command"
175 OUTPUT=$("$POOLED_BIN" -c 'cd /tmp && pwd' 2>&1)
176 [ "$OUTPUT" = "/tmp" ] && pass "cd builtin" || fail "cd builtin" "Got: $OUTPUT"
177
178 subsection "Builtins module - export/printenv"
179 OUTPUT=$("$POOLED_BIN" -c 'export POOLTEST=value && printenv POOLTEST' 2>&1)
180 [ "$OUTPUT" = "value" ] && pass "export/printenv builtins" || fail "export/printenv" "Got: $OUTPUT"
181
182 # =====================================
183 # READLINE BUFFER TESTS
184 # =====================================
185 section "READLINE BUFFER VALIDATION"
186
187 subsection "Interactive mode buffers"
188 # Test with echo to simulate typing
189 echo "echo pooltest" | "$POOLED_BIN" 2>&1 | grep -q "pooltest" && pass "Readline basic input" || fail "Readline input"
190
191 subsection "Line editing simulation"
192 # Test buffer modifications (limited without real TTY)
193 printf "echo test\n" | "$POOLED_BIN" 2>&1 | grep -q "test" && pass "Line buffer processing" || fail "Line buffer"
194
195 # =====================================
196 # STRESS TESTS
197 # =====================================
198 section "STRESS AND BOUNDARY TESTS"
199
200 subsection "Rapid allocation cycles"
201 cat > stress.sh << 'EOF'
202 i=0
203 while [ $i -lt 100 ]; do
204 VAR="iteration_$i"
205 TEMP="${VAR}_temp"
206 unset VAR TEMP
207 i=$((i + 1))
208 done
209 echo "completed"
210 EOF
211
212 OUTPUT=$("$POOLED_BIN" < stress.sh 2>&1 | tail -1)
213 [ "$OUTPUT" = "completed" ] && pass "100 allocation cycles" || fail "Allocation stress test"
214
215 subsection "Maximum string length"
216 # Test with 64KB string (reasonable max)
217 "$POOLED_BIN" -c 'BIG=$(printf "%.0sX" {1..65536}); echo ${#BIG}' 2>&1 | grep -q "^65536$" && pass "64KB string handling" || fail "Max string length"
218
219 subsection "Nested string operations"
220 OUTPUT=$("$POOLED_BIN" -c 'A=hello; B="${A}_world"; C="${B%%_*}"; echo "$C"' 2>&1)
221 [ "$OUTPUT" = "hello" ] && pass "Nested string operations" || fail "Nested operations" "Got: $OUTPUT"
222
223 subsection "Concurrent allocations simulation"
224 OUTPUT=$("$POOLED_BIN" -c '(A=job1; echo "$A") & (B=job2; echo "$B") & wait' 2>&1 | sort | tr '\n' ' ')
225 [[ "$OUTPUT" =~ "job1 job2" ]] && pass "Concurrent allocation patterns" || fail "Concurrent allocations"
226
227 # =====================================
228 # REGRESSION TESTS
229 # =====================================
230 section "REGRESSION VALIDATION"
231
232 subsection "POSIX compliance maintained"
233 cd "$FORTSH_DIR" || exit 1
234
235 # Run basic POSIX test to ensure pooling doesn't break compliance
236 if sh tests/posix_compliance_test.sh > /tmp/posix_pooled.log 2>&1; then
237 RESULT=$(grep "Pass rate:" /tmp/posix_pooled.log | awk '{print $3}')
238 if [ "${RESULT%\%}" -ge 95 ]; then
239 pass "POSIX compliance ≥95% ($RESULT)"
240 else
241 fail "POSIX compliance degraded" "Only $RESULT"
242 fi
243 else
244 skip "POSIX tests couldn't run" "Check /tmp/posix_pooled.log"
245 fi
246
247 cd "$TEST_WORK_DIR" || exit 1
248
249 # =====================================
250 # EDGE CASES
251 # =====================================
252 section "EDGE CASES AND CORNER CONDITIONS"
253
254 subsection "Null bytes and special characters"
255 # Test with printable special chars (null bytes would terminate strings)
256 OUTPUT=$("$POOLED_BIN" -c 'X="a b
257 c"; echo "${#X}"' 2>&1)
258 [ "$OUTPUT" = "5" ] && pass "Special characters (tab/newline)" || fail "Special char handling"
259
260 subsection "Unicode handling"
261 OUTPUT=$("$POOLED_BIN" -c 'X="🎉"; echo "$X"' 2>&1)
262 [ "$OUTPUT" = "🎉" ] && pass "Unicode preserved" || fail "Unicode handling"
263
264 subsection "Quotes and escapes"
265 OUTPUT=$("$POOLED_BIN" -c 'X="a\"b"; echo "$X"' 2>&1)
266 [ "$OUTPUT" = 'a"b' ] && pass "Quote escaping" || fail "Quote handling"
267
268 subsection "Zero-length operations"
269 OUTPUT=$("$POOLED_BIN" -c 'X=""; Y="${X:0:0}"; echo "[$Y]"' 2>&1)
270 [ "$OUTPUT" = "[]" ] && pass "Zero-length substring" || fail "Zero-length operations"
271
272 # =====================================
273 # PERFORMANCE INDICATORS
274 # =====================================
275 section "PERFORMANCE CHARACTERISTICS"
276
277 subsection "Allocation timing comparison"
278 # Simple timing test (not scientific but indicative)
279 START=$(date +%s%N)
280 "$POOLED_BIN" -c 'for i in $(seq 1 1000); do X="test_$i"; unset X; done' 2>/dev/null
281 END=$(date +%s%N)
282 POOL_TIME=$((END - START))
283
284 if [ "$POOL_TIME" -lt 10000000000 ]; then # Less than 10 seconds
285 pass "Allocation performance acceptable (${POOL_TIME}ns)"
286 else
287 fail "Allocation too slow" "${POOL_TIME}ns for 1000 allocations"
288 fi
289
290 # =====================================
291 # DASHBOARD VALIDATION (if available)
292 # =====================================
293 section "MONITORING AND DIAGNOSTICS"
294
295 subsection "Dashboard availability check"
296 if MEMPOOL_DEBUG=1 "$POOLED_BIN" -c 'echo test' 2>&1 | grep -q -i "dashboard\|bucket\|pool"; then
297 pass "Dashboard output available with MEMPOOL_DEBUG=1"
298 else
299 skip "Dashboard output not visible" "May need different flag or not implemented"
300 fi
301
302 # =====================================
303 # FINAL VALIDATION
304 # =====================================
305 section "COMPREHENSIVE VALIDATION"
306
307 subsection "Real-world command sequence"
308 cat > real_world.sh << 'EOF'
309 # Simulate real shell usage
310 cd /tmp
311 X="test"
312 Y="${X}_file"
313 echo "$Y" > test.txt
314 cat test.txt
315 Z=$(cat test.txt)
316 echo "Read: $Z"
317 rm -f test.txt
318 echo "Done"
319 EOF
320
321 OUTPUT=$("$POOLED_BIN" < real_world.sh 2>&1 | tail -1)
322 [ "$OUTPUT" = "Done" ] && pass "Real-world command sequence" || fail "Real-world sequence failed"
323
324 # =====================================
325 # SUMMARY
326 # =====================================
327 section "TEST SUMMARY"
328
329 TOTAL=$((PASSED + FAILED + SKIPPED))
330
331 printf "\n${MAGENTA}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n"
332 printf "${BLUE}MEMORY POOL VALIDATION RESULTS${NC}\n"
333 printf "${MAGENTA}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}\n\n"
334
335 printf "${GREEN}Passed:${NC} %3d (%.1f%%)\n" "$PASSED" "$(echo "scale=1; $PASSED * 100 / $TOTAL" | bc)"
336 printf "${RED}Failed:${NC} %3d (%.1f%%)\n" "$FAILED" "$(echo "scale=1; $FAILED * 100 / $TOTAL" | bc)"
337 printf "${YELLOW}Skipped:${NC} %3d (%.1f%%)\n" "$SKIPPED" "$(echo "scale=1; $SKIPPED * 100 / $TOTAL" | bc)"
338 printf "━━━━━━━━━━━━━━━━━━━━━\n"
339 printf "Total: %3d\n" "$TOTAL"
340
341 if [ "$FAILED" -eq 0 ]; then
342 printf "\n${GREEN}✅ ALL TESTS PASSED!${NC}\n"
343 printf "Memory pooling is working correctly across all tested scenarios.\n"
344 printf "Zero-copy pooling validated for all 7 modules.\n"
345 exit 0
346 elif [ "$FAILED" -le 2 ]; then
347 printf "\n${YELLOW}⚠️ MOSTLY PASSING${NC}\n"
348 printf "Memory pooling has minor issues but is generally functional.\n"
349 exit 0
350 else
351 printf "\n${RED}❌ SIGNIFICANT FAILURES${NC}\n"
352 printf "Memory pooling has issues requiring investigation.\n"
353 exit 1
354 fi