Files
Python3-Win9x/scripts/vc6-probe-core.test.sh
T

338 lines
15 KiB
Bash
Executable File

#!/usr/bin/env bash
#
# Regression tests for scripts/vc6-probe-core.sh and, through it, the VC6
# _Py_ATOMIC_VC6_X86 branch added to
# cpython/Include/internal/pycore_atomic.h.
#
# Skipped (not failed) when wine + MSVC600 are unavailable, matching
# scripts/vc6-probe.test.sh's convention, since CI/dev boxes without the
# external MSVC600 bundle cannot exercise this.
#
# Usage: scripts/vc6-probe-core.test.sh
set -u
REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
PROBE="$REPO_ROOT/scripts/vc6-probe-core.sh"
fail=0
pass() { echo "ok - $1"; }
bad() { echo "not ok - $1"; fail=1; }
MSVC600_ROOT="${MSVC600_ROOT:-$REPO_ROOT/MSVC600}"
if command -v wine >/dev/null 2>&1 && [ -e "$MSVC600_ROOT/VC98/Bin/CL.EXE" ]; then
# --- positive case: the isolated atomics smoke fixture compiles clean ---
out="$("$PROBE" scripts/fixtures/vc6_atomic_smoke.c 2>&1)"
status=$?
if [ "$status" -eq 0 ]; then
pass "pycore_atomic.h VC6 branch: atomics smoke fixture compiles (exit 0)"
else
bad "pycore_atomic.h VC6 branch: atomics smoke fixture compiles (exit $status)"
echo "$out"
fi
if printf '%s' "$out" | grep -qi 'error'; then
bad "atomics smoke fixture: no compiler errors in output"
else
pass "atomics smoke fixture: no compiler errors in output"
fi
if printf '%s' "$out" | grep -q 'intrin.h'; then
bad "atomics smoke fixture: does not hit the intrin.h blocker"
else
pass "atomics smoke fixture: does not hit the intrin.h blocker"
fi
# --- negative case: a deliberately invalid atomics usage still fails ---
BAD_SRC="$REPO_ROOT/scripts/fixtures/_vc6_atomic_smoke_bad.c"
cat > "$BAD_SRC" <<'EOF'
#include <inttypes.h>
#include "pycore_atomic.h"
int bad(void) { return this_identifier_does_not_exist; }
EOF
trap 'rm -f "$BAD_SRC"' EXIT
out_bad="$("$PROBE" scripts/fixtures/_vc6_atomic_smoke_bad.c 2>&1)"
status_bad=$?
if [ "$status_bad" -ne 0 ]; then
pass "probe-core reports nonzero exit for a broken translation unit"
else
bad "probe-core reports nonzero exit for a broken translation unit (got: $status_bad)"
fi
if printf '%s' "$out_bad" | grep -q 'error C'; then
pass "probe-core output surfaces the compiler diagnostic"
else
bad "probe-core output surfaces the compiler diagnostic"
fi
# --- reference case: Modules/main.c reaches past pycore_atomic.h ---
# main.c is expected to fail today (pycore_interp.h needs <stdbool.h>,
# a separate, unrelated VC6 gap) but must not fail *at*
# pycore_atomic.h/intrin.h; that would mean the atomics branch
# regressed even though the isolated fixture above passed.
out_main="$("$PROBE" cpython/Modules/main.c 2>&1)"
if printf '%s' "$out_main" | grep -q 'pycore_atomic.h.*intrin.h\|intrin.h.*No such file'; then
bad "Modules/main.c probe: does not regress to the pycore_atomic.h/intrin.h blocker"
else
pass "Modules/main.c probe: does not regress to the pycore_atomic.h/intrin.h blocker"
fi
# --- positive case: the isolated stdbool smoke fixture compiles clean ---
out_bool="$("$PROBE" scripts/fixtures/vc6_stdbool_smoke.c 2>&1)"
status_bool=$?
if [ "$status_bool" -eq 0 ]; then
pass "compat/msvc600/stdbool.h: stdbool smoke fixture compiles (exit 0)"
else
bad "compat/msvc600/stdbool.h: stdbool smoke fixture compiles (exit $status_bool)"
echo "$out_bool"
fi
if printf '%s' "$out_bool" | grep -qi 'error'; then
bad "stdbool smoke fixture: no compiler errors in output"
else
pass "stdbool smoke fixture: no compiler errors in output"
fi
# --- negative case: a deliberately invalid bool usage still fails ---
BAD_BOOL_SRC="$REPO_ROOT/scripts/fixtures/_vc6_stdbool_smoke_bad.c"
cat > "$BAD_BOOL_SRC" <<'EOF'
#include <stdbool.h>
int bad(void) { return this_identifier_does_not_exist; }
EOF
trap 'rm -f "$BAD_SRC" "$BAD_BOOL_SRC"' EXIT
out_bool_bad="$("$PROBE" scripts/fixtures/_vc6_stdbool_smoke_bad.c 2>&1)"
status_bool_bad=$?
if [ "$status_bool_bad" -ne 0 ]; then
pass "probe-core reports nonzero exit for a broken stdbool translation unit"
else
bad "probe-core reports nonzero exit for a broken stdbool translation unit (got: $status_bool_bad)"
fi
if printf '%s' "$out_bool_bad" | grep -q 'error C'; then
pass "probe-core output surfaces the compiler diagnostic (stdbool case)"
else
bad "probe-core output surfaces the compiler diagnostic (stdbool case)"
fi
# --- reference case: Modules/main.c reaches past pycore_interp.h's
# <stdbool.h> include. It is expected to still fail today -- the next,
# unrelated blocker is VC6's C89-only parser rejecting C99-style mixed
# declarations-and-code in several pycore_*.h inline functions (e.g.
# Include/internal/pycore_code.h's _PyLocals_GetKind(), which declares
# `char *ptr` after a preceding `assert(...)` statement) -- but it must
# not fail *at* <stdbool.h> anymore; that would mean this slice
# regressed even though the isolated fixture above passed.
if printf '%s' "$out_main" | grep -q "Cannot open include file: 'stdbool.h'"; then
bad "Modules/main.c probe: does not regress to the pycore_interp.h/stdbool.h blocker"
else
pass "Modules/main.c probe: does not regress to the pycore_interp.h/stdbool.h blocker"
fi
# --- positive case: the isolated mixed-declarations smoke fixture
# compiles clean (pycore_code.h, pycore_dict.h, pycore_list.h,
# pycore_call.h all hoisted their C99 mid-block declarations) ---
out_decls="$("$PROBE" scripts/fixtures/vc6_mixed_decls_smoke.c 2>&1)"
status_decls=$?
if [ "$status_decls" -eq 0 ]; then
pass "mixed-declarations header slice: smoke fixture compiles (exit 0)"
else
bad "mixed-declarations header slice: smoke fixture compiles (exit $status_decls)"
echo "$out_decls"
fi
if printf '%s' "$out_decls" | grep -qi 'error'; then
bad "mixed-declarations smoke fixture: no compiler errors in output"
else
pass "mixed-declarations smoke fixture: no compiler errors in output"
fi
# --- negative case: a deliberately invalid mixed-declarations usage
# still fails ---
BAD_DECLS_SRC="$REPO_ROOT/scripts/fixtures/_vc6_mixed_decls_smoke_bad.c"
cat > "$BAD_DECLS_SRC" <<'EOF'
#include "Python.h"
#include "pycore_code.h"
int bad(void) { return this_identifier_does_not_exist; }
EOF
trap 'rm -f "$BAD_SRC" "$BAD_BOOL_SRC" "$BAD_DECLS_SRC"' EXIT
out_decls_bad="$("$PROBE" scripts/fixtures/_vc6_mixed_decls_smoke_bad.c 2>&1)"
status_decls_bad=$?
if [ "$status_decls_bad" -ne 0 ]; then
pass "probe-core reports nonzero exit for a broken mixed-declarations translation unit"
else
bad "probe-core reports nonzero exit for a broken mixed-declarations translation unit (got: $status_decls_bad)"
fi
if printf '%s' "$out_decls_bad" | grep -q 'error C'; then
pass "probe-core output surfaces the compiler diagnostic (mixed-declarations case)"
else
bad "probe-core output surfaces the compiler diagnostic (mixed-declarations case)"
fi
# --- reference case: Modules/main.c no longer fails inside any of the
# four fixed pycore_*.h headers. It is expected to still fail today --
# Modules/main.c itself uses the same C99 mixed-declarations pattern
# pervasively in its own function bodies, a much larger, whole-file
# source rewrite that is out of scope for this header-only slice; see
# PORT_STATUS.md's "Mixed-declarations header slice" section for the
# documented boundary -- but it must not fail *inside*
# pycore_code.h/pycore_dict.h/pycore_list.h/pycore_call.h anymore;
# that would mean this slice regressed even though the isolated
# fixture above passed.
if printf '%s' "$out_main" | grep -qE 'pycore_(code|dict|list|call)\.h\([0-9]+\)'; then
bad "Modules/main.c probe: does not regress to the pycore_code/dict/list/call.h mixed-declarations blocker"
else
pass "Modules/main.c probe: does not regress to the pycore_code/dict/list/call.h mixed-declarations blocker"
fi
# --- positive case: the isolated declaration-order smoke fixture
# compiles clean. It exercises, self-contained, the same five hoist
# shapes applied to Modules/main.c itself (bare hoist above an early
# return, side-effecting-initializer hoist, a hoisted pair where fixing
# the first declaration would otherwise turn the second into a new
# violation, a nested-block hoist, and a platform-conditional same-name
# hoist) so this guards the general transformation, independent of
# main.c's own future edits. ---
out_decl_order="$("$PROBE" scripts/fixtures/vc6_decl_order_smoke.c 2>&1)"
status_decl_order=$?
if [ "$status_decl_order" -eq 0 ]; then
pass "Modules/main.c declaration-order slice: smoke fixture compiles (exit 0)"
else
bad "Modules/main.c declaration-order slice: smoke fixture compiles (exit $status_decl_order)"
echo "$out_decl_order"
fi
if printf '%s' "$out_decl_order" | grep -qi 'error'; then
bad "declaration-order smoke fixture: no compiler errors in output"
else
pass "declaration-order smoke fixture: no compiler errors in output"
fi
# --- negative case: a deliberately invalid declaration-order usage
# still fails ---
BAD_DECL_ORDER_SRC="$REPO_ROOT/scripts/fixtures/_vc6_decl_order_smoke_bad.c"
cat > "$BAD_DECL_ORDER_SRC" <<'EOF'
int bad(void) { return this_identifier_does_not_exist; }
EOF
trap 'rm -f "$BAD_SRC" "$BAD_BOOL_SRC" "$BAD_DECLS_SRC" "$BAD_DECL_ORDER_SRC"' EXIT
out_decl_order_bad="$("$PROBE" scripts/fixtures/_vc6_decl_order_smoke_bad.c 2>&1)"
status_decl_order_bad=$?
if [ "$status_decl_order_bad" -ne 0 ]; then
pass "probe-core reports nonzero exit for a broken declaration-order translation unit"
else
bad "probe-core reports nonzero exit for a broken declaration-order translation unit (got: $status_decl_order_bad)"
fi
if printf '%s' "$out_decl_order_bad" | grep -q 'error C'; then
pass "probe-core output surfaces the compiler diagnostic (declaration-order case)"
else
bad "probe-core output surfaces the compiler diagnostic (declaration-order case)"
fi
# --- reference case: Modules/main.c no longer fails on any C89
# mixed-declaration site anywhere in its own body (the C2146/C2065/
# C2275 "illegal use of this type as an expression" pattern tied to a
# declaration keyword). At the time this check was written, main.c
# still failed with a distinct, out-of-scope blocker instead (C99
# compound literals/designated initializers, see below); that blocker
# is now also fixed (see the compound-literal checks further down),
# but this check's job is narrower and unchanged: main.c must not show
# the declaration-order-specific error codes; that would mean this
# slice regressed even though the isolated fixture above passed.
if printf '%s' "$out_main" | grep -qE "main\.c\([0-9]+\) : error C2146|main\.c\([0-9]+\) : error C2065.*undeclared identifier|main\.c\([0-9]+\) : error C2275"; then
bad "Modules/main.c probe: does not regress to a C89 mixed-declaration error inside main.c's own body"
else
pass "Modules/main.c probe: does not regress to a C89 mixed-declaration error inside main.c's own body"
fi
# --- positive case: the isolated compound-literal/designated-
# initializer smoke fixture compiles clean. It exercises, self-
# contained (aside from the real Python.h/pycore_initconfig.h types
# it needs), the three replacement patterns applied to main.c: calling
# PyStatus_Ok() instead of the _PyStatus_OK() compound-literal macro,
# explicit field assignment instead of the _PyCompilerFlags_INIT
# compound-literal macro, and explicit field assignment instead of a
# _PyArgv designated-initializer aggregate. ---
out_compound="$("$PROBE" scripts/fixtures/vc6_compound_literal_smoke.c 2>&1)"
status_compound=$?
if [ "$status_compound" -eq 0 ]; then
pass "compound-literal slice: smoke fixture compiles (exit 0)"
else
bad "compound-literal slice: smoke fixture compiles (exit $status_compound)"
echo "$out_compound"
fi
if printf '%s' "$out_compound" | grep -qi 'error'; then
bad "compound-literal smoke fixture: no compiler errors in output"
else
pass "compound-literal smoke fixture: no compiler errors in output"
fi
# --- negative case: a deliberately invalid compound-literal-fixture
# usage still fails ---
BAD_COMPOUND_SRC="$REPO_ROOT/scripts/fixtures/_vc6_compound_literal_smoke_bad.c"
cat > "$BAD_COMPOUND_SRC" <<'EOF'
#include "Python.h"
#include "pycore_initconfig.h"
int bad(void) { return this_identifier_does_not_exist; }
EOF
trap 'rm -f "$BAD_SRC" "$BAD_BOOL_SRC" "$BAD_DECLS_SRC" "$BAD_DECL_ORDER_SRC" "$BAD_COMPOUND_SRC"' EXIT
out_compound_bad="$("$PROBE" scripts/fixtures/_vc6_compound_literal_smoke_bad.c 2>&1)"
status_compound_bad=$?
if [ "$status_compound_bad" -ne 0 ]; then
pass "probe-core reports nonzero exit for a broken compound-literal translation unit"
else
bad "probe-core reports nonzero exit for a broken compound-literal translation unit (got: $status_compound_bad)"
fi
if printf '%s' "$out_compound_bad" | grep -q 'error C'; then
pass "probe-core output surfaces the compiler diagnostic (compound-literal case)"
else
bad "probe-core output surfaces the compiler diagnostic (compound-literal case)"
fi
# --- reference case: Modules/main.c itself no longer shows any C2059
# "syntax error : '{'"/"syntax error : '.'" (the compound-literal/
# designated-initializer error signature), and -- since this was the
# last recorded blocker for main.c as a compile-only (/c) translation
# unit -- now compiles with exit status 0. This is a compile-only
# result: no link or runtime success is claimed (vc6-probe-core.sh is
# /c only; see its header comment). ---
if printf '%s' "$out_main" | grep -q 'main\.c([0-9]*) : error C2059'; then
bad "Modules/main.c probe: does not regress to the compound-literal/designated-initializer C2059 blocker"
else
pass "Modules/main.c probe: does not regress to the compound-literal/designated-initializer C2059 blocker"
fi
out_main_status="$("$PROBE" cpython/Modules/main.c >/dev/null 2>&1; echo $?)"
if [ "$out_main_status" -eq 0 ]; then
pass "Modules/main.c probe: compiles clean end-to-end (compile-only, exit 0)"
else
bad "Modules/main.c probe: compiles clean end-to-end (compile-only, got exit $out_main_status)"
fi
else
echo "skip - wine/MSVC600 not available; skipping live probe-core integration checks"
fi
if [ "$fail" -ne 0 ]; then
echo "FAILED"
exit 1
fi
echo "ALL TESTS PASSED"