port: advance VC6 typeobject frontier and preserve regression coverage
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compile update_arg's exact keys branch as C89; check evaluation/cleanup order."""
|
||||
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
source = Path(sys.argv[1]).read_text()
|
||||
function = source.split("mutablemapping_update_arg(PyObject *self, PyObject *arg)\n{", 1)[1]
|
||||
match = re.search(
|
||||
r" if \(func != NULL\) \{.*?(?= if \(_PyObject_LookupAttr\(arg, &_Py_ID\(items\))",
|
||||
function, re.S,
|
||||
)
|
||||
assert match, "update_arg keys branch not found"
|
||||
harness = r'''
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
typedef struct { int unused; } PyObject;
|
||||
static PyObject self_obj, arg_obj, func_obj, keys_obj, iter_obj, key_obj, value_obj;
|
||||
static int scenario, calls, error;
|
||||
static char events[64];
|
||||
static void event(char c) {
|
||||
size_t n = strlen(events);
|
||||
assert(n + 1 < sizeof(events));
|
||||
events[n] = c;
|
||||
events[n + 1] = '\0';
|
||||
}
|
||||
static PyObject * _PyObject_CallNoArgs(PyObject *obj) {
|
||||
assert(obj == &func_obj); event('C');
|
||||
return scenario == 0 ? NULL : &keys_obj;
|
||||
}
|
||||
static void Py_DECREF(PyObject *obj) {
|
||||
if (obj == &func_obj) event('f');
|
||||
else if (obj == &keys_obj) event('k');
|
||||
else if (obj == &iter_obj) event('i');
|
||||
else if (obj == &key_obj) event('q');
|
||||
else { assert(obj == &value_obj); event('v'); }
|
||||
}
|
||||
static PyObject *PyObject_GetIter(PyObject *obj) {
|
||||
assert(obj == &keys_obj); event('I');
|
||||
return scenario == 1 ? NULL : &iter_obj;
|
||||
}
|
||||
static PyObject *PyIter_Next(PyObject *obj) {
|
||||
assert(obj == &iter_obj); event('N');
|
||||
if (scenario == 2 || scenario == 3 || calls++ > 0) {
|
||||
error = scenario == 3 || scenario == 7;
|
||||
return NULL;
|
||||
}
|
||||
return &key_obj;
|
||||
}
|
||||
static PyObject *PyObject_GetItem(PyObject *obj, PyObject *key) {
|
||||
assert(obj == &arg_obj && key == &key_obj); event('G');
|
||||
return scenario == 4 ? NULL : &value_obj;
|
||||
}
|
||||
static int PyObject_SetItem(PyObject *obj, PyObject *key, PyObject *value) {
|
||||
assert(obj == &self_obj && key == &key_obj && value == &value_obj);
|
||||
event('S'); return scenario == 5 ? -1 : 0;
|
||||
}
|
||||
static int PyErr_Occurred(void) { event('E'); return error; }
|
||||
static int run(PyObject *self, PyObject *arg, PyObject *func) {
|
||||
int res = 0;
|
||||
'''
|
||||
harness += match.group(0)
|
||||
harness += r'''
|
||||
return 42;
|
||||
}
|
||||
int main(void) {
|
||||
static const char *expected[] = {
|
||||
"Cf", "CfIk", "CfIkNiE", "CfIkNiE",
|
||||
"CfIkNGqi", "CfIkNGSvqi", "CfIkNGSvqNiE", "CfIkNGSvqNiE"
|
||||
};
|
||||
int result;
|
||||
for (scenario = 0; scenario < 8; ++scenario) {
|
||||
events[0] = '\0'; calls = error = 0;
|
||||
result = run(&self_obj, &arg_obj, &func_obj);
|
||||
assert(result == (scenario == 2 || scenario == 6 ? 0 : -1));
|
||||
assert(strcmp(events, expected[scenario]) == 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
with tempfile.TemporaryDirectory(prefix="vc6-odict-update-arg-iterator-") 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("update_arg keys branch C89 compile and evaluation/cleanup order: PASS (8 cases)")
|
||||
Reference in New Issue
Block a user