port: advance VC6 typeobject frontier and preserve regression coverage
This commit is contained in:
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compile the exact range_index body as C89 and check evaluation 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 \*\nrange_index\([^\n]+\)\n\{.*?\n\}", source, re.S
|
||||
)
|
||||
assert match, "range_index not found"
|
||||
harness = r'''
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
typedef long Py_ssize_t;
|
||||
typedef struct { int unused; } PyObject;
|
||||
typedef struct { PyObject *start, *step; } rangeobject;
|
||||
#define PY_ITERSEARCH_INDEX 2
|
||||
static int PyExc_ValueError = 1;
|
||||
static int scenario;
|
||||
static char events[16];
|
||||
static PyObject ob, start, step, one, idx, quotient, converted;
|
||||
static rangeobject range;
|
||||
static void event(char c) {
|
||||
size_t n = strlen(events);
|
||||
assert(n + 1 < sizeof(events));
|
||||
events[n] = c; events[n + 1] = '\0';
|
||||
}
|
||||
static int PyLong_CheckExact(PyObject *obj) {
|
||||
assert(obj == &ob); return scenario != 0 && scenario != 1 && scenario != 8;
|
||||
}
|
||||
static int PyBool_Check(PyObject *obj) {
|
||||
assert(obj == &ob); return scenario == 8;
|
||||
}
|
||||
static Py_ssize_t _PySequence_IterSearch(PyObject *obj, PyObject *value, int op) {
|
||||
assert(obj == (PyObject *)&range && value == &ob && op == PY_ITERSEARCH_INDEX);
|
||||
event('I'); return scenario == 0 ? -1 : 3;
|
||||
}
|
||||
static PyObject *PyLong_FromSsize_t(Py_ssize_t value) {
|
||||
assert(value == 3); event('L'); return &converted;
|
||||
}
|
||||
static int range_contains_long(rangeobject *r, PyObject *value) {
|
||||
assert(r == &range && value == &ob); event('C');
|
||||
return scenario == 2 ? -1 : scenario != 3;
|
||||
}
|
||||
static PyObject *PyNumber_Subtract(PyObject *value, PyObject *first) {
|
||||
assert(value == &ob && first == &start); event('S');
|
||||
return scenario == 4 ? NULL : &idx;
|
||||
}
|
||||
static PyObject *_PyLong_GetOne(void) { event('O'); return &one; }
|
||||
static PyObject *PyNumber_FloorDivide(PyObject *value, PyObject *divisor) {
|
||||
assert(value == &idx && divisor == &step); event('F');
|
||||
return scenario == 6 ? NULL : "ient;
|
||||
}
|
||||
static void Py_DECREF(PyObject *value) { assert(value == &idx); event('D'); }
|
||||
static void PyErr_Format(int exc, const char *format, PyObject *value) {
|
||||
assert(exc == PyExc_ValueError && value == &ob);
|
||||
assert(strcmp(format, "%R is not in range") == 0); event('E');
|
||||
}
|
||||
'''
|
||||
harness += match.group(0)
|
||||
harness += r'''
|
||||
int main(void) {
|
||||
static const char *expected[] = {
|
||||
"I", "IL", "C", "CE", "CS", "CSO", "CSOFD", "CSOFD", "CSOFD"
|
||||
};
|
||||
PyObject *result;
|
||||
for (scenario = 0; scenario < 9; ++scenario) {
|
||||
range.start = &start;
|
||||
range.step = scenario == 5 ? &one : &step;
|
||||
events[0] = '\0';
|
||||
result = range_index(&range, &ob);
|
||||
assert(strcmp(events, expected[scenario]) == 0);
|
||||
if (scenario == 1) assert(result == &converted);
|
||||
else if (scenario == 5) assert(result == &idx);
|
||||
else if (scenario == 7 || scenario == 8) assert(result == "ient);
|
||||
else assert(result == NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
'''
|
||||
with tempfile.TemporaryDirectory(prefix="vc6-rangeobject-index-") 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("range_index C89 compile and evaluation/cleanup order: PASS (9 cases)")
|
||||
Reference in New Issue
Block a user