Files
Python3-Win9x/scripts/vc6-odict-or-c89.test.py

96 lines
3.1 KiB
Python

#!/usr/bin/env python3
"""Compile the exact odict_or as C89 and exercise its operation ordering."""
import re
import subprocess
import sys
import tempfile
from pathlib import Path
source = Path(sys.argv[1]).read_text()
match = re.search(
r"static PyObject \*\nodict_or\(PyObject \*left, PyObject \*right\)\n\{.*?\n\}",
source, re.S,
)
assert match, "odict_or definition not found"
harness = r'''
#include <assert.h>
#include <stddef.h>
typedef struct { int ordered; int dict; } PyObject;
typedef PyObject PyTypeObject;
static PyObject left_obj, right_obj, result_obj, not_implemented;
static PyObject *expected_type;
static int stage, fail_call, fail_update;
static int PyODict_Check(PyObject *obj) {
assert(stage == 0 && obj == &left_obj);
stage = 1;
return obj->ordered;
}
static PyTypeObject *Py_TYPE(PyObject *obj) {
assert(stage == 1 && obj == expected_type);
stage = 2;
return obj;
}
static int PyDict_Check(PyObject *obj) {
assert(stage == 2);
assert(obj == (left_obj.ordered ? &right_obj : &left_obj));
stage = 3;
return obj->dict;
}
#define Py_RETURN_NOTIMPLEMENTED return &not_implemented
static PyObject *PyObject_CallOneArg(PyObject *type, PyObject *arg) {
assert(stage == 3 && type == expected_type && arg == &left_obj);
stage = 4;
return fail_call ? NULL : &result_obj;
}
static int mutablemapping_update_arg(PyObject *obj, PyObject *arg) {
assert(stage == 4 && obj == &result_obj && arg == &right_obj);
stage = 5;
return fail_update ? -1 : 0;
}
static void Py_DECREF(PyObject *obj) {
assert(stage == 5 && fail_update && obj == &result_obj);
stage = 6;
}
'''
harness += match.group(0)
harness += r'''
int main(void) {
int ordered, scenario;
PyObject *result;
for (ordered = 0; ordered < 2; ++ordered) {
for (scenario = 0; scenario < 4; ++scenario) {
left_obj.ordered = ordered;
right_obj.ordered = 1;
left_obj.dict = right_obj.dict = scenario != 0;
expected_type = ordered ? &left_obj : &right_obj;
fail_call = scenario == 1;
fail_update = scenario == 2;
stage = 0;
result = odict_or(&left_obj, &right_obj);
if (scenario == 0) {
assert(result == &not_implemented && stage == 3);
} else if (scenario == 1) {
assert(result == NULL && stage == 4);
} else if (scenario == 2) {
assert(result == NULL && stage == 6);
} else {
assert(result == &result_obj && stage == 5);
}
}
}
return 0;
}
'''
with tempfile.TemporaryDirectory(prefix="vc6-odict-or-") as directory:
path = Path(directory)
(path / "test.c").write_text(harness)
compiled = subprocess.run([
"cc", "-std=c89", "-pedantic-errors", "-Wall", "-Wextra", "-Werror",
str(path / "test.c"), "-o", str(path / "test"),
])
if compiled.returncode:
sys.exit(compiled.returncode)
subprocess.run([str(path / "test")], check=True)
print("odict_or C89 compile and operand/rejection/construction/update/cleanup order: PASS (8 cases)")