]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
Add tests of PyLong_{As,From}{Unsigned,}Long. These are very much like
authorTim Peters <tim.peters@gmail.com>
Thu, 14 Jun 2001 00:55:41 +0000 (00:55 +0000)
committerTim Peters <tim.peters@gmail.com>
Thu, 14 Jun 2001 00:55:41 +0000 (00:55 +0000)
the new PyLong_{As,From}{Unsigned,}LongLong tests, so the bulk of the
code is in the new #include file testcapi_long.h, which generates
different code depending on how macros are set.  This sucks, but I couldn't
think of anything that sucked less.

UNIX headache?  If we still maintain dependencies by hand, someone who
knows what they're doing should teach whatever needs it that
_testcapimodule.c includes testcapi_long.h.

Modules/_testcapimodule.c
Modules/testcapi_long.h [new file with mode: 0644]

index 06602e93e7b8c9897cb62d7925b673c3a046c429..6e2208eeb67f21d5e8fcdef069b057572e910be5 100644 (file)
@@ -172,9 +172,58 @@ test_dict_iteration(PyObject* self, PyObject* args)
        return Py_None;
 }
 
-#ifdef HAVE_LONG_LONG
 
-/* Basic sanity checks for PyLong_{As, From}{Unsigned,}LongLong(). */
+/* Tests of PyLong_{As, From}{Unsigned,}Long(), and (#ifdef HAVE_LONG_LONG)
+   PyLong_{As, From}{Unsigned,}LongLong()/
+
+   Note that the meat of the test is contained in testcapi_long.h.
+   This is revolting, but delicate code duplication is worse:  "almost
+   exactly the same" code is needed to test LONG_LONG, but the ubiquitous
+   dependence on type names makes it impossible to use a parameterized
+   function.  A giant macro would be even worse than this.  A C++ template
+   would be perfect.
+
+   The "report an error" functions are deliberately not part of the #include
+   file:  if the test fails, you can set a breakpoint in the appropriate
+   error function directly, and crawl back from there in the debugger.
+*/
+
+#define UNBIND(X)  Py_DECREF(X); (X) = NULL
+
+static PyObject *
+raise_test_long_error(const char* msg)
+{
+       return raiseTestError("test_long_api", msg);
+}
+
+#define TESTNAME       test_long_api_inner
+#define TYPENAME       long
+#define F_S_TO_PY      PyLong_FromLong
+#define F_PY_TO_S      PyLong_AsLong
+#define F_U_TO_PY      PyLong_FromUnsignedLong
+#define F_PY_TO_U      PyLong_AsUnsignedLong
+#define F_ERROR                raise_test_long_error
+
+#include "testcapi_long.h"
+
+static PyObject *
+test_long_api(PyObject* self, PyObject* args)
+{
+        if (!PyArg_ParseTuple(args, ":test_long_api"))
+                return NULL;
+
+       return TESTNAME();
+}
+
+#undef TESTNAME
+#undef TYPENAME
+#undef F_S_TO_PY
+#undef F_PY_TO_S
+#undef F_U_TO_PY
+#undef F_PY_TO_U
+#undef F_ERROR
+
+#ifdef HAVE_LONG_LONG
 
 static PyObject *
 raise_test_longlong_error(const char* msg)
@@ -182,177 +231,41 @@ raise_test_longlong_error(const char* msg)
        return raiseTestError("test_longlong_api", msg);
 }
 
-#define UNBIND(X)  Py_DECREF(X); (X) = NULL
+#define TESTNAME       test_longlong_api_inner
+#define TYPENAME       LONG_LONG
+#define F_S_TO_PY      PyLong_FromLongLong
+#define F_PY_TO_S      PyLong_AsLongLong
+#define F_U_TO_PY      PyLong_FromUnsignedLongLong
+#define F_PY_TO_U      PyLong_AsUnsignedLongLong
+#define F_ERROR                raise_test_longlong_error
+
+#include "testcapi_long.h"
 
 static PyObject *
 test_longlong_api(PyObject* self, PyObject* args)
 {
-       const int NBITS = SIZEOF_LONG_LONG * 8;
-       unsigned LONG_LONG base;
-       PyObject *pyresult;
-       int i;
-
         if (!PyArg_ParseTuple(args, ":test_longlong_api"))
                 return NULL;
 
+       return TESTNAME();
+}
 
-       /* 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);
-       }
+#undef TESTNAME
+#undef TYPENAME
+#undef F_S_TO_PY
+#undef F_PY_TO_S
+#undef F_U_TO_PY
+#undef F_PY_TO_U
+#undef F_ERROR
 
-       Py_INCREF(Py_None);
-       return Py_None;
-}
+#endif /* ifdef HAVE_LONG_LONG */
 
-#endif
 
 static PyMethodDef TestMethods[] = {
        {"test_config",         test_config,            METH_VARARGS},
        {"test_list_api",       test_list_api,          METH_VARARGS},
        {"test_dict_iteration", test_dict_iteration,    METH_VARARGS},
+       {"test_long_api",       test_long_api,          METH_VARARGS},
 #ifdef HAVE_LONG_LONG
        {"test_longlong_api",   test_longlong_api,      METH_VARARGS},
 #endif
diff --git a/Modules/testcapi_long.h b/Modules/testcapi_long.h
new file mode 100644 (file)
index 0000000..7c5a7e7
--- /dev/null
@@ -0,0 +1,167 @@
+/* Poor-man's template.  Macros used:
+   TESTNAME    name of the test (like test_long_api_inner)
+   TYPENAME    the signed type (like long)
+   F_S_TO_PY   convert signed to pylong; TYPENAME -> PyObject*
+   F_PY_TO_S   convert pylong to signed; PyObject* -> TYPENAME
+   F_U_TO_PY   convert unsigned to pylong; unsigned TYPENAME -> PyObject*
+   F_PY_TO_U    convert pylong to unsigned; PyObject* -> TypeError
+   F_ERROR     error-report function; char* -> PyObject* (returns NULL)
+*/
+
+static PyObject *
+TESTNAME()
+{
+       const int NBITS = sizeof(TYPENAME) * 8;
+       unsigned TYPENAME base;
+       PyObject *pyresult;
+       int i;
+
+       /* 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) {
+                       TYPENAME in, out;
+                       unsigned TYPENAME uin, uout;
+
+                       /* For 0, 1, 2 use base; for 3, 4, 5 use -base */
+                       uin = j < 3 ? base
+                                   : (unsigned TYPENAME)(-(TYPENAME)base);
+
+                       /* For 0 & 3, subtract 1.
+                        * For 1 & 4, leave alone.
+                        * For 2 & 5, add 1.
+                        */
+                       uin += (unsigned TYPENAME)(TYPENAME)(j % 3 - 1);
+
+                       pyresult = F_U_TO_PY(uin);
+                       if (pyresult == NULL)
+                               return F_ERROR(
+                                "unsigned unexpected null result");
+
+                       uout = F_PY_TO_U(pyresult);
+                       if (uout == (unsigned TYPENAME)-1 && PyErr_Occurred())
+                               return F_ERROR(
+                                       "unsigned unexpected -1 result");
+                       if (uout != uin)
+                               return F_ERROR(
+                                       "unsigned output != input");
+                       UNBIND(pyresult);
+
+                       in = (TYPENAME)uin;
+                       pyresult = F_S_TO_PY(in);
+                       if (pyresult == NULL)
+                               return F_ERROR(
+                                       "signed unexpected null result");
+
+                       out = F_PY_TO_S(pyresult);
+                       if (out == (TYPENAME)-1 && PyErr_Occurred())
+                               return F_ERROR(
+                                       "signed unexpected -1 result");
+                       if (out != in)
+                               return F_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;
+               TYPENAME out;
+               unsigned TYPENAME uout;
+
+               one = PyLong_FromLong(1);
+               if (one == NULL)
+                       return F_ERROR(
+                               "unexpected NULL from PyLong_FromLong");
+
+               /* Unsigned complains about -1? */
+               x = PyNumber_Negative(one);
+               if (x == NULL)
+                       return F_ERROR(
+                               "unexpected NULL from PyNumber_Negative");
+
+               uout = F_PY_TO_U(x);
+               if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred())
+                       return F_ERROR(
+                               "PyLong_AsUnsignedXXX(-1) didn't complain");
+               PyErr_Clear();
+               UNBIND(x);
+
+               /* Unsigned complains about 2**NBITS? */
+               y = PyLong_FromLong((long)NBITS);
+               if (y == NULL)
+                       return F_ERROR(
+                               "unexpected NULL from PyLong_FromLong");
+
+               x = PyNumber_Lshift(one, y); /* 1L << NBITS, == 2**NBITS */
+               UNBIND(y);
+               if (x == NULL)
+                       return F_ERROR(
+                               "unexpected NULL from PyNumber_Lshift");
+
+               uout = F_PY_TO_U(x);
+               if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred())
+                       return F_ERROR(
+                               "PyLong_AsUnsignedXXX(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 F_ERROR(
+                               "unexpected NULL from PyNumber_Rshift");
+
+               out = F_PY_TO_S(y);
+               if (out != (TYPENAME)-1 || !PyErr_Occurred())
+                       return F_ERROR(
+                               "PyLong_AsXXX(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 F_ERROR(
+                               "unexpected NULL from PyNumber_Negative");
+
+               y = PyNumber_Subtract(x, one); /* -(2**(NBITS-1))-1 */
+               UNBIND(x);
+               if (y == NULL)
+                       return F_ERROR(
+                               "unexpected NULL from PyNumber_Subtract");
+
+               out = F_PY_TO_S(y);
+               if (out != (TYPENAME)-1 || !PyErr_Occurred())
+                       return F_ERROR(
+                               "PyLong_AsXXX(-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;
+}