Files
Python3-Win9x/scripts/vc6-rangeobject-index-c89.test.py
T

96 lines
3.5 KiB
Python

#!/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 : &quotient;
}
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 == &quotient);
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)")