#!/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
.*?)\};\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 != '