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

115 lines
4.0 KiB
Python

#!/usr/bin/env python3
"""Compile exact odictiter_reduce as C89 and check timing and ownership."""
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 \*\nodictiter_reduce\(odictiterobject \*di, PyObject \*Py_UNUSED\(ignored\)\)\n\{.*?\n\}",
source, re.S,
)
assert match, "odictiter_reduce definition not found"
harness = r'''
#include <assert.h>
#include <stddef.h>
#include <string.h>
typedef struct { int refs; } PyObject;
typedef struct { PyObject *di_odict, *di_current; int position; } odictiterobject;
static PyObject dict, current, list_obj, builtin, result_obj;
static odictiterobject *original;
static int stage, failure, consume;
static int iter;
#define Py_UNUSED(name) unused
#define _Py_ID(name) name
static void Py_XINCREF(PyObject *obj) {
assert(stage < 2);
assert(obj == (stage == 0 ? original->di_odict : original->di_current));
if (obj != NULL) ++obj->refs;
++stage;
}
static PyObject *PySequence_List(PyObject *obj) {
odictiterobject *tmp = (odictiterobject *)obj;
assert(stage == 2 && tmp != original);
assert(tmp->di_odict == original->di_odict);
assert(tmp->di_current == original->di_current);
assert(tmp->position == 17);
assert(dict.refs == (original->di_odict ? 2 : 1));
assert(current.refs == (original->di_current ? 2 : 1));
tmp->position = 99;
if (consume) {
if (tmp->di_odict) --tmp->di_odict->refs;
if (tmp->di_current) --tmp->di_current->refs;
tmp->di_odict = tmp->di_current = NULL;
}
stage = 3;
list_obj.refs = failure == 1 ? 0 : 1;
return failure == 1 ? NULL : &list_obj;
}
static void Py_XDECREF(PyObject *obj) {
assert(stage == 3 || stage == 4);
assert(obj == (consume ? NULL : (stage == 3 ? original->di_odict : original->di_current)));
if (obj != NULL) --obj->refs;
++stage;
}
static PyObject *_PyEval_GetBuiltin(int *id) {
assert(stage == 5 && id == &iter && failure != 1);
assert(dict.refs == 1 && current.refs == 1);
stage = 6;
builtin.refs = 1;
return &builtin;
}
static PyObject *Py_BuildValue(const char *format, PyObject *func, PyObject *list) {
assert(stage == 6 && strcmp(format, "N(N)") == 0);
assert(func == &builtin && list == &list_obj);
assert(func->refs == 1 && list->refs == 1);
--func->refs;
--list->refs;
stage = 7;
return failure == 2 ? NULL : &result_obj;
}
'''
harness += match.group(0)
harness += r'''
int main(void) {
int mask;
odictiterobject di;
PyObject *result;
for (mask = 0; mask < 4; ++mask) {
for (consume = 0; consume < 2; ++consume) {
for (failure = 0; failure < 3; ++failure) {
dict.refs = current.refs = 1;
di.di_odict = mask & 1 ? &dict : NULL;
di.di_current = mask & 2 ? &current : NULL;
di.position = 17;
original = &di;
stage = 0;
result = odictiter_reduce(&di, NULL);
assert(result == (failure ? NULL : &result_obj));
assert(stage == (failure == 1 ? 5 : 7));
assert(dict.refs == 1 && current.refs == 1);
assert(list_obj.refs == 0);
assert(di.di_odict == (mask & 1 ? &dict : NULL));
assert(di.di_current == (mask & 2 ? &current : NULL));
assert(di.position == 17);
}
}
}
return 0;
}
'''
with tempfile.TemporaryDirectory(prefix="vc6-odict-list-") as directory:
path = Path(directory)
(path / "test.c").write_text(harness)
compiled = subprocess.run([
"cc", "-std=c89", "-pedantic-errors", "-Wall", "-Wextra", "-Werror",
"-Wno-unused-parameter", str(path / "test.c"), "-o", str(path / "test"),
])
if compiled.returncode:
sys.exit(compiled.returncode)
subprocess.run([str(path / "test")], check=True)
print("odictiter_reduce C89 compile and copy/incref/list/cleanup/ownership/failure order: PASS (24 cases)")