Files
Python3-Win9x/scripts/vc6-setobject-setiter-reduce-c89.test.py

121 lines
3.9 KiB
Python

#!/usr/bin/env python3
"""Compile the exact setiter_reduce as C89 and check ownership and call order."""
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 \*\nsetiter_reduce\([^\n]+\)\n\{.*?\n\}", source, re.S
)
assert match, "setiter_reduce not found"
harness = r'''
#include <assert.h>
#include <stddef.h>
#include <string.h>
typedef struct { int refs; } PyObject;
typedef struct {
PyObject head;
PyObject *si_set;
long si_used, si_pos, len;
} setiterobject;
#define Py_UNUSED(name) name
#define _Py_ID(name) name
static int iter, mode, exhausted;
static PyObject backing, list_value, builtin, built;
static setiterobject original;
static char events[32];
static void event(char c) {
size_t n = strlen(events);
assert(n + 1 < sizeof(events));
events[n] = c;
events[n + 1] = '\0';
}
static void Py_XINCREF(PyObject *obj) {
assert(obj == original.si_set);
assert(strcmp(events, "") == 0);
event('I');
if (obj != NULL) ++obj->refs;
}
static void Py_XDECREF(PyObject *obj) {
assert(obj == (mode == 1 ? NULL : original.si_set));
assert(strcmp(events, "IL") == 0);
event('D');
if (obj != NULL) --obj->refs;
}
static PyObject *PySequence_List(PyObject *obj) {
setiterobject *tmp = (setiterobject *)obj;
assert(tmp != &original);
assert(tmp->head.refs == original.head.refs);
assert(tmp->si_set == original.si_set);
assert(tmp->si_used == original.si_used);
assert(tmp->si_pos == original.si_pos && tmp->len == original.len);
assert(backing.refs == (exhausted ? 1 : 2));
assert(strcmp(events, "I") == 0);
event('L');
tmp->si_pos = 99;
tmp->len = 0;
if (mode == 1 && tmp->si_set != NULL) {
--tmp->si_set->refs;
tmp->si_set = NULL;
}
return mode == 2 ? NULL : &list_value;
}
static PyObject *_PyEval_GetBuiltin(int *name) {
assert(name == &iter);
assert(strcmp(events, "ILD") == 0 && backing.refs == 1);
event('G');
return &builtin;
}
static PyObject *Py_BuildValue(const char *format, PyObject *func, PyObject *list) {
assert(strcmp(format, "N(N)") == 0);
assert(func == &builtin && list == &list_value);
assert(strcmp(events, "ILDG") == 0 && backing.refs == 1);
event('B');
--func->refs;
--list->refs;
return mode == 3 ? NULL : &built;
}
'''
harness += match.group(0)
harness += r'''
int main(void) {
setiterobject before;
PyObject *result;
for (exhausted = 0; exhausted < 2; ++exhausted) {
for (mode = 0; mode < 4; ++mode) {
backing.refs = list_value.refs = builtin.refs = 1;
memset(&original, 0, sizeof(original));
original.head.refs = 7;
original.si_set = exhausted ? NULL : &backing;
original.si_used = 5;
original.si_pos = 2;
original.len = 3;
memcpy(&before, &original, sizeof(before));
events[0] = '\0';
result = setiter_reduce(&original, NULL);
assert(memcmp(&before, &original, sizeof(before)) == 0);
assert(backing.refs == 1);
assert(strcmp(events, mode == 2 ? "ILD" : "ILDGB") == 0);
assert(result == (mode >= 2 ? NULL : &built));
assert(list_value.refs == (mode == 2 ? 1 : 0));
assert(builtin.refs == (mode == 2 ? 1 : 0));
}
}
return 0;
}
'''
with tempfile.TemporaryDirectory(prefix="vc6-setiter-reduce-") as directory:
path = Path(directory)
(path / "test.c").write_text(harness)
result = subprocess.run([
"cc", "-std=c89", "-pedantic-errors", "-Wall", "-Wextra", "-Werror",
"-Wno-unused-parameter", str(path / "test.c"), "-o", str(path / "test"),
])
if result.returncode:
sys.exit(result.returncode)
subprocess.run([str(path / "test")], check=True)
print("setiter_reduce C89 declaration/evaluation/cleanup/return: PASS (8 cases)")