Antoine Pitrou schrieb am 04.08.2018 um 15:57:
Le 04/08/2018 à 15:13, Nick Coghlan a écrit :
It'd be *really* nice to at least be able to write some of the C API tests directly in Cython rather than having to fiddle about with splitting the test between the regrtest parts that actually define the test case and the extension module parts that expose the interfaces that we want to test.
Actually, I think testing the C API is precisely the kind of area where you don't want to involve a third-party, especially not a moving target (Cython is actively maintained and generated code will vary after each new Cython release). Besides, Cython itself calls the C API, which means you might end up involuntarily testing the C API against itself.
If anything, testing the C API using ctypes or cffi would probably be more reasonable... assuming we get ctypes / cffi to compile everywhere, which currently isn't the case.
I agree that you would rather not want to let Cython (or another tool) generate the specific code that tests a specific C-API call, but you could still use Cython to get around writing the setup, validation and unittest boilerplate code in C. Basically, a test could then look something like this (probably works, although I didn't test it):
from cpython.object cimport PyObject from cpython.list cimport PyList_Append
def test_PyList_Append_on_empty_list(): # setup code l =  assert len(l) == 0 value = "abc" pyobj_value = <PyObject*> value refcount_before = pyobj_value.ob_refcnt
# conservative test call, translates to the expected C code, # although with exception propagation if it returns -1: errcode = PyList_Append(l, value)
# validation assert errcode == 0 assert len(l) == 1 assert l is value assert pyobj_value.ob_refcnt == refcount_before + 1
If you don't want the exception handling, you can define your own declaration of PyList_Append() that does not have it. But personally, I'd rather use try-except in my test code than manually taking care of cleaning up (unexpected) exceptions.
What we do in Cython, BTW, is write doctests in compiled ".pyx" files. That allows us to execute certain parts of a test in Python (the doctest code) and other parts in Cython (the compiled functions/classes that have the doctests), and thus to do a direct comparison between Python and Cython. An example that you could find in a test ".pyx" file:
def test_times2(x): """ doctest that gets executed by Python:
>>> test_times2(3) == 3 * 2 True """ # Cython compiled code in a compiled function that gets tested: return x * 2
Given that CPython's current "_testcapimodule.c" is only a good 5000 lines long (divide that by the number of public C-API functions and macros!), I'm sure the above could help in improving the unit test coverage of the C-API quite quickly.