120 lines
4.2 KiB
Bash
Executable File
120 lines
4.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
#
|
|
# Regression tests for reproducible getpath.py frozen-header generation.
|
|
|
|
set -u
|
|
|
|
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
GENERATOR="$REPO_ROOT/scripts/generate-getpath-frozen.sh"
|
|
TMP_ROOT="$REPO_ROOT/build/test-getpath-frozen"
|
|
OUT_HEADER="$TMP_ROOT/cpython/Python/frozen_modules/getpath.h"
|
|
DIRECT_HEADER="$TMP_ROOT/direct/getpath.h"
|
|
|
|
fail=0
|
|
pass() { echo "ok - $1"; }
|
|
bad() { echo "not ok - $1"; fail=1; }
|
|
|
|
rm -rf "$TMP_ROOT"
|
|
out="$($GENERATOR "$TMP_ROOT" 2>&1)"
|
|
status=$?
|
|
if [ "$status" -eq 0 ]; then
|
|
pass "generator exits 0"
|
|
else
|
|
bad "generator exits 0 (got exit $status)"
|
|
echo "$out"
|
|
fi
|
|
|
|
if [ "$out" = "build/test-getpath-frozen/cpython/Python/frozen_modules/getpath.h" ]; then
|
|
pass "generator reports the project-local build-relative output path"
|
|
else
|
|
bad "generator reports the project-local build-relative output path (got: $out)"
|
|
fi
|
|
|
|
if [ -s "$OUT_HEADER" ]; then
|
|
pass "generator writes a nonempty getpath.h under build/"
|
|
else
|
|
bad "generator writes a nonempty getpath.h under build/"
|
|
fi
|
|
|
|
first_line="$(sed -n '1p' "$OUT_HEADER" 2>/dev/null)"
|
|
if [ "$first_line" = '/* Auto-generated by Programs/_freeze_module.py */' ]; then
|
|
pass "generated header records the host-Python _freeze_module.py path"
|
|
else
|
|
bad "generated header records the host-Python _freeze_module.py path (got: $first_line)"
|
|
fi
|
|
|
|
second_line="$(sed -n '2p' "$OUT_HEADER" 2>/dev/null)"
|
|
if [ "$second_line" = 'const unsigned char _Py_M__getpath[] = {' ]; then
|
|
pass "generated header declares the expected getpath frozen symbol"
|
|
else
|
|
bad "generated header declares the expected getpath frozen symbol (got: $second_line)"
|
|
fi
|
|
|
|
python3 - "$OUT_HEADER" <<'PY'
|
|
import marshal
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
path = Path(sys.argv[1])
|
|
text = path.read_text()
|
|
if not text.endswith('};\n'):
|
|
raise SystemExit('header does not end with closing array marker')
|
|
match = re.search(r'const unsigned char _Py_M__getpath\[\] = \{\n(?P<body>.*?)\};\n\Z', text, re.S)
|
|
if not match:
|
|
raise SystemExit('array body not found')
|
|
lines = match.group('body').splitlines()
|
|
values = []
|
|
for index, line in enumerate(lines, 1):
|
|
if not line.startswith(' '):
|
|
raise SystemExit(f'line {index} is not four-space indented')
|
|
payload = line.strip()
|
|
if not payload.endswith(','):
|
|
raise SystemExit(f'line {index} is missing trailing comma')
|
|
nums = [part for part in payload[:-1].split(',') if part]
|
|
if len(nums) > 16:
|
|
raise SystemExit(f'line {index} has more than 16 bytes')
|
|
if index < len(lines) and len(nums) != 16:
|
|
raise SystemExit(f'non-final line {index} has {len(nums)} bytes, expected 16')
|
|
for num in nums:
|
|
value = int(num)
|
|
if not 0 <= value <= 255:
|
|
raise SystemExit(f'byte out of range: {value}')
|
|
values.append(value)
|
|
code = marshal.loads(bytes(values))
|
|
if code.co_filename != '<frozen getpath>':
|
|
raise SystemExit(f'unexpected code filename: {code.co_filename!r}')
|
|
if code.co_name != '<module>':
|
|
raise SystemExit(f'unexpected code name: {code.co_name!r}')
|
|
print('format-ok')
|
|
PY
|
|
format_status=$?
|
|
if [ "$format_status" -eq 0 ]; then
|
|
pass "generated byte array unmarshals as frozen getpath code with CPython format"
|
|
else
|
|
bad "generated byte array unmarshals as frozen getpath code with CPython format"
|
|
fi
|
|
|
|
mkdir -p "$(dirname "$DIRECT_HEADER")"
|
|
python3 "$REPO_ROOT/cpython/Programs/_freeze_module.py" getpath \
|
|
"$REPO_ROOT/cpython/Modules/getpath.py" "$DIRECT_HEADER"
|
|
if cmp -s "$OUT_HEADER" "$DIRECT_HEADER"; then
|
|
pass "generator output matches direct Programs/_freeze_module.py invocation exactly"
|
|
else
|
|
bad "generator output matches direct Programs/_freeze_module.py invocation exactly"
|
|
fi
|
|
|
|
frontier_out="$(bash "$REPO_ROOT/scripts/vc6-probe-pythoncore-frontier.sh" --list-only 2>&1)"
|
|
frontier_status=$?
|
|
if [ "$frontier_status" -eq 0 ] && printf '%s\n' "$frontier_out" | grep -q $'^compile\tcpython/Modules/getpath.c\t'; then
|
|
pass "frontier list still starts from Modules/getpath.c without requiring generated output"
|
|
else
|
|
bad "frontier list still starts from Modules/getpath.c without requiring generated output"
|
|
echo "$frontier_out"
|
|
fi
|
|
|
|
if [ "$fail" -ne 0 ]; then
|
|
echo "FAILED"
|
|
exit 1
|
|
fi
|
|
echo "ALL TESTS PASSED"
|