summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_testcapimodule.c173
1 files changed, 158 insertions, 15 deletions
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index a49c60a..06602e9 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -177,28 +177,171 @@ test_dict_iteration(PyObject* self, PyObject* args)
/* Basic sanity checks for PyLong_{As, From}{Unsigned,}LongLong(). */
static PyObject *
+raise_test_longlong_error(const char* msg)
+{
+ return raiseTestError("test_longlong_api", msg);
+}
+
+#define UNBIND(X) Py_DECREF(X); (X) = NULL
+
+static PyObject *
test_longlong_api(PyObject* self, PyObject* args)
{
- /* unsigned LONG_LONG uinput, uoutput; */
- LONG_LONG input, output;
+ const int NBITS = SIZEOF_LONG_LONG * 8;
+ unsigned LONG_LONG base;
PyObject *pyresult;
+ int i;
if (!PyArg_ParseTuple(args, ":test_longlong_api"))
return NULL;
- input = 0;
- pyresult = PyLong_FromLongLong(input);
- if (pyresult == NULL)
- return raiseTestError("test_longlong_api",
- "unexpected null result");
- output = PyLong_AsLongLong(pyresult);
- if (output == (LONG_LONG)-1 && PyErr_Occurred())
- return raiseTestError("test_longlong_api",
- "unexpected -1 result");
- if (output != input)
- return raiseTestError("test_longlong_api",
- "output != input");
- Py_DECREF(pyresult);
+
+ /* Note: This test lets PyObjects leak if an error is raised. Since
+ an error should never be raised, leaks are impossible <wink>. */
+
+ /* Test native -> PyLong -> native roundtrip identity.
+ * Generate all powers of 2, and test them and their negations,
+ * plus the numbers +-1 off from them.
+ */
+ base = 1;
+ for (i = 0;
+ i < NBITS + 1; /* on last, base overflows to 0 */
+ ++i, base <<= 1)
+ {
+ int j;
+ for (j = 0; j < 6; ++j) {
+ LONG_LONG in, out;
+ unsigned LONG_LONG uin, uout;
+
+ /* For 0, 1, 2 use base; for 3, 4, 5 use -base */
+ uin = j < 3 ? base
+ : (unsigned LONG_LONG)(-(LONG_LONG)base);
+
+ /* For 0 & 3, subtract 1.
+ * For 1 & 4, leave alone.
+ * For 2 & 5, add 1.
+ */
+ uin += (unsigned LONG_LONG)(LONG_LONG)(j % 3 - 1);
+
+ pyresult = PyLong_FromUnsignedLongLong(uin);
+ if (pyresult == NULL)
+ return raise_test_longlong_error(
+ "unsigned unexpected null result");
+
+ uout = PyLong_AsUnsignedLongLong(pyresult);
+ if (uout == (unsigned LONG_LONG)-1 && PyErr_Occurred())
+ return raise_test_longlong_error(
+ "unsigned unexpected -1 result");
+ if (uout != uin)
+ return raise_test_longlong_error(
+ "unsigned output != input");
+ UNBIND(pyresult);
+
+ in = (LONG_LONG)uin;
+ pyresult = PyLong_FromLongLong(in);
+ if (pyresult == NULL)
+ return raise_test_longlong_error(
+ "signed unexpected null result");
+
+ out = PyLong_AsLongLong(pyresult);
+ if (out == (LONG_LONG)-1 && PyErr_Occurred())
+ return raise_test_longlong_error(
+ "signed unexpected -1 result");
+ if (out != in)
+ return raise_test_longlong_error(
+ "signed output != input");
+ UNBIND(pyresult);
+ }
+ }
+
+ /* Overflow tests. The loop above ensured that all limit cases that
+ * should not overflow don't overflow, so all we need to do here is
+ * provoke one-over-the-limit cases (not exhaustive, but sharp).
+ */
+ {
+ PyObject *one, *x, *y;
+ LONG_LONG out;
+ unsigned LONG_LONG uout;
+
+ one = PyLong_FromLong(1);
+ if (one == NULL)
+ return raise_test_longlong_error(
+ "unexpected NULL from PyLong_FromLong");
+
+ /* Unsigned complains about -1? */
+ x = PyNumber_Negative(one);
+ if (x == NULL)
+ return raise_test_longlong_error(
+ "unexpected NULL from PyNumber_Negative");
+
+ uout = PyLong_AsUnsignedLongLong(x);
+ if (uout != (unsigned LONG_LONG)-1 || !PyErr_Occurred())
+ return raise_test_longlong_error(
+ "PyLong_AsUnsignedLongLong(-1) didn't "
+ "complain");
+ PyErr_Clear();
+ UNBIND(x);
+
+ /* Unsigned complains about 2**NBITS? */
+ y = PyLong_FromLong((long)NBITS);
+ if (y == NULL)
+ return raise_test_longlong_error(
+ "unexpected NULL from PyLong_FromLong");
+
+ x = PyNumber_Lshift(one, y); /* 1L << NBITS, == 2**NBITS */
+ UNBIND(y);
+ if (x == NULL)
+ return raise_test_longlong_error(
+ "unexpected NULL from PyNumber_Lshift");
+
+ uout = PyLong_AsUnsignedLongLong(x);
+ if (uout != (unsigned LONG_LONG)-1 || !PyErr_Occurred())
+ return raise_test_longlong_error(
+ "PyLong_AsUnsignedLongLong(2**NBITS) didn't "
+ "complain");
+ PyErr_Clear();
+
+ /* Signed complains about 2**(NBITS-1)?
+ x still has 2**NBITS. */
+ y = PyNumber_Rshift(x, one); /* 2**(NBITS-1) */
+ UNBIND(x);
+ if (y == NULL)
+ return raise_test_longlong_error(
+ "unexpected NULL from PyNumber_Rshift");
+
+ out = PyLong_AsLongLong(y);
+ if (out != (LONG_LONG)-1 || !PyErr_Occurred())
+ return raise_test_longlong_error(
+ "PyLong_AsLongLong(2**(NBITS-1)) didn't "
+ "complain");
+ PyErr_Clear();
+
+ /* Signed complains about -2**(NBITS-1)-1?;
+ y still has 2**(NBITS-1). */
+ x = PyNumber_Negative(y); /* -(2**(NBITS-1)) */
+ UNBIND(y);
+ if (x == NULL)
+ return raise_test_longlong_error(
+ "unexpected NULL from PyNumber_Negative");
+
+ y = PyNumber_Subtract(x, one); /* -(2**(NBITS-1))-1 */
+ UNBIND(x);
+ if (y == NULL)
+ return raise_test_longlong_error(
+ "unexpected NULL from PyNumber_Subtract");
+
+ out = PyLong_AsLongLong(y);
+ if (out != (LONG_LONG)-1 || !PyErr_Occurred())
+ return raise_test_longlong_error(
+ "PyLong_AsLongLong(-2**(NBITS-1)-1) didn't "
+ "complain");
+ PyErr_Clear();
+ UNBIND(y);
+
+ Py_XDECREF(x);
+ Py_XDECREF(y);
+ Py_DECREF(one);
+ }
Py_INCREF(Py_None);
return Py_None;