#!/usr/bin/env python3 """Check only update_arg's first declaration frontier, before later blockers.""" import re import subprocess import sys import tempfile from pathlib import Path source = Path(sys.argv[1]).read_text() match = re.search( r"static int\nmutablemapping_update_arg\(PyObject \*self, PyObject \*arg\)\n\{" r".*?(?= if \(func != NULL\) \{)", source, re.S, ) assert match, "mutablemapping_update_arg prefix not found" # Compile the untouched prefix only: iterator/key declarations farther down # are independent frontier defects. The synthetic tail observes lookup output. harness = r''' #include #include typedef struct { int unused; } PyObject; static PyObject self_obj, arg_obj, items_obj, func_obj; static int scenario, stage, keys; #define _Py_ID(name) name static int PyDict_CheckExact(PyObject *arg) { assert(stage == 0 && arg == &arg_obj); stage = 1; return scenario < 3; } static PyObject *PyDict_Items(PyObject *arg) { assert(stage == 1 && arg == &arg_obj); stage = 2; return scenario == 0 ? NULL : &items_obj; } static int mutablemapping_add_pairs(PyObject *self, PyObject *items) { assert(stage == 2 && self == &self_obj && items == &items_obj); stage = 3; return scenario == 1 ? -1 : 0; } static void Py_DECREF(PyObject *obj) { assert(stage == 3 && obj == &items_obj); stage = 4; } static int _PyObject_LookupAttr(PyObject *arg, int *id, PyObject **func) { assert(stage == 1 && arg == &arg_obj && id == &keys); stage = 5; *func = scenario == 5 ? &func_obj : NULL; return scenario == 3 ? -1 : scenario == 5; } ''' harness += match.group(0) harness += r''' assert(stage == 5 && res == 0); assert(func == (scenario == 5 ? &func_obj : NULL)); stage = 6; return 0; } int main(void) { int result; for (scenario = 0; scenario < 6; ++scenario) { stage = 0; result = mutablemapping_update_arg(&self_obj, &arg_obj); assert(result == ((scenario < 2 || scenario == 3) ? -1 : 0)); assert(stage == (scenario == 0 ? 2 : scenario < 3 ? 4 : scenario == 3 ? 5 : 6)); } return 0; } ''' with tempfile.TemporaryDirectory(prefix="vc6-odict-update-arg-func-") as directory: path = Path(directory) (path / "test.c").write_text(harness) result = subprocess.run([ "cc", "-std=c89", "-pedantic-errors", "-Wall", "-Wextra", "-Werror", str(path / "test.c"), "-o", str(path / "test"), ]) if result.returncode: sys.exit(result.returncode) subprocess.run([str(path / "test")], check=True) print("mutablemapping_update_arg prefix C89 compile and dict/lookup ordering: PASS (6 cases)")