LCOV - code coverage report
Current view: top level - Modules - testcapi_long.h (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 72 97 74.2 %
Date: 2022-07-07 18:19:46 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /* Poor-man's template.  Macros used:
       2             :    TESTNAME     name of the test (like test_long_api_inner)
       3             :    TYPENAME     the signed type (like long)
       4             :    F_S_TO_PY    convert signed to pylong; TYPENAME -> PyObject*
       5             :    F_PY_TO_S    convert pylong to signed; PyObject* -> TYPENAME
       6             :    F_U_TO_PY    convert unsigned to pylong; unsigned TYPENAME -> PyObject*
       7             :    F_PY_TO_U    convert pylong to unsigned; PyObject* -> unsigned TYPENAME
       8             : */
       9             : 
      10             : static PyObject *
      11           2 : TESTNAME(PyObject *error(const char*))
      12             : {
      13           2 :     const int NBITS = sizeof(TYPENAME) * 8;
      14             :     unsigned TYPENAME base;
      15             :     PyObject *pyresult;
      16             :     int i;
      17             : 
      18             :     /* Note:  This test lets PyObjects leak if an error is raised.  Since
      19             :        an error should never be raised, leaks are impossible <wink>. */
      20             : 
      21             :     /* Test native -> PyLong -> native roundtrip identity.
      22             :      * Generate all powers of 2, and test them and their negations,
      23             :      * plus the numbers +-1 off from them.
      24             :      */
      25           2 :     base = 1;
      26         132 :     for (i = 0;
      27             :          i < NBITS + 1;  /* on last, base overflows to 0 */
      28         130 :          ++i, base <<= 1)
      29             :     {
      30             :         int j;
      31         910 :         for (j = 0; j < 6; ++j) {
      32             :             TYPENAME in, out;
      33             :             unsigned TYPENAME uin, uout;
      34             : 
      35             :             /* For 0, 1, 2 use base; for 3, 4, 5 use -base */
      36         780 :             uin = j < 3 ? base : 0U - base;
      37             : 
      38             :             /* For 0 & 3, subtract 1.
      39             :              * For 1 & 4, leave alone.
      40             :              * For 2 & 5, add 1.
      41             :              */
      42         780 :             uin += (unsigned TYPENAME)(TYPENAME)(j % 3 - 1);
      43             : 
      44         780 :             pyresult = F_U_TO_PY(uin);
      45         780 :             if (pyresult == NULL)
      46           0 :                 return error(
      47             :                  "unsigned unexpected null result");
      48             : 
      49         780 :             uout = F_PY_TO_U(pyresult);
      50         780 :             if (uout == (unsigned TYPENAME)-1 && PyErr_Occurred())
      51           0 :                 return error(
      52             :                     "unsigned unexpected -1 result");
      53         780 :             if (uout != uin)
      54           0 :                 return error(
      55             :                     "unsigned output != input");
      56         780 :             UNBIND(pyresult);
      57             : 
      58         780 :             in = (TYPENAME)uin;
      59         780 :             pyresult = F_S_TO_PY(in);
      60         780 :             if (pyresult == NULL)
      61           0 :                 return error(
      62             :                     "signed unexpected null result");
      63             : 
      64         780 :             out = F_PY_TO_S(pyresult);
      65         780 :             if (out == (TYPENAME)-1 && PyErr_Occurred())
      66           0 :                 return error(
      67             :                     "signed unexpected -1 result");
      68         780 :             if (out != in)
      69           0 :                 return error(
      70             :                     "signed output != input");
      71         780 :             UNBIND(pyresult);
      72             :         }
      73             :     }
      74             : 
      75             :     /* Overflow tests.  The loop above ensured that all limit cases that
      76             :      * should not overflow don't overflow, so all we need to do here is
      77             :      * provoke one-over-the-limit cases (not exhaustive, but sharp).
      78             :      */
      79             :     {
      80             :         PyObject *one, *x, *y;
      81             :         TYPENAME out;
      82             :         unsigned TYPENAME uout;
      83             : 
      84           2 :         one = PyLong_FromLong(1);
      85           2 :         if (one == NULL)
      86           0 :             return error(
      87             :                 "unexpected NULL from PyLong_FromLong");
      88             : 
      89             :         /* Unsigned complains about -1? */
      90           2 :         x = PyNumber_Negative(one);
      91           2 :         if (x == NULL)
      92           0 :             return error(
      93             :                 "unexpected NULL from PyNumber_Negative");
      94             : 
      95           2 :         uout = F_PY_TO_U(x);
      96           2 :         if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred())
      97           0 :             return error(
      98             :                 "PyLong_AsUnsignedXXX(-1) didn't complain");
      99           2 :         if (!PyErr_ExceptionMatches(PyExc_OverflowError))
     100           0 :             return error(
     101             :                 "PyLong_AsUnsignedXXX(-1) raised "
     102             :                 "something other than OverflowError");
     103           2 :         PyErr_Clear();
     104           2 :         UNBIND(x);
     105             : 
     106             :         /* Unsigned complains about 2**NBITS? */
     107           2 :         y = PyLong_FromLong((long)NBITS);
     108           2 :         if (y == NULL)
     109           0 :             return error(
     110             :                 "unexpected NULL from PyLong_FromLong");
     111             : 
     112           2 :         x = PyNumber_Lshift(one, y); /* 1L << NBITS, == 2**NBITS */
     113           2 :         UNBIND(y);
     114           2 :         if (x == NULL)
     115           0 :             return error(
     116             :                 "unexpected NULL from PyNumber_Lshift");
     117             : 
     118           2 :         uout = F_PY_TO_U(x);
     119           2 :         if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred())
     120           0 :             return error(
     121             :                 "PyLong_AsUnsignedXXX(2**NBITS) didn't "
     122             :                 "complain");
     123           2 :         if (!PyErr_ExceptionMatches(PyExc_OverflowError))
     124           0 :             return error(
     125             :                 "PyLong_AsUnsignedXXX(2**NBITS) raised "
     126             :                 "something other than OverflowError");
     127           2 :         PyErr_Clear();
     128             : 
     129             :         /* Signed complains about 2**(NBITS-1)?
     130             :            x still has 2**NBITS. */
     131           2 :         y = PyNumber_Rshift(x, one); /* 2**(NBITS-1) */
     132           2 :         UNBIND(x);
     133           2 :         if (y == NULL)
     134           0 :             return error(
     135             :                 "unexpected NULL from PyNumber_Rshift");
     136             : 
     137           2 :         out = F_PY_TO_S(y);
     138           2 :         if (out != (TYPENAME)-1 || !PyErr_Occurred())
     139           0 :             return error(
     140             :                 "PyLong_AsXXX(2**(NBITS-1)) didn't "
     141             :                 "complain");
     142           2 :         if (!PyErr_ExceptionMatches(PyExc_OverflowError))
     143           0 :             return error(
     144             :                 "PyLong_AsXXX(2**(NBITS-1)) raised "
     145             :                 "something other than OverflowError");
     146           2 :         PyErr_Clear();
     147             : 
     148             :         /* Signed complains about -2**(NBITS-1)-1?;
     149             :            y still has 2**(NBITS-1). */
     150           2 :         x = PyNumber_Negative(y);  /* -(2**(NBITS-1)) */
     151           2 :         UNBIND(y);
     152           2 :         if (x == NULL)
     153           0 :             return error(
     154             :                 "unexpected NULL from PyNumber_Negative");
     155             : 
     156           2 :         y = PyNumber_Subtract(x, one); /* -(2**(NBITS-1))-1 */
     157           2 :         UNBIND(x);
     158           2 :         if (y == NULL)
     159           0 :             return error(
     160             :                 "unexpected NULL from PyNumber_Subtract");
     161             : 
     162           2 :         out = F_PY_TO_S(y);
     163           2 :         if (out != (TYPENAME)-1 || !PyErr_Occurred())
     164           0 :             return error(
     165             :                 "PyLong_AsXXX(-2**(NBITS-1)-1) didn't "
     166             :                 "complain");
     167           2 :         if (!PyErr_ExceptionMatches(PyExc_OverflowError))
     168           0 :             return error(
     169             :                 "PyLong_AsXXX(-2**(NBITS-1)-1) raised "
     170             :                 "something other than OverflowError");
     171           2 :         PyErr_Clear();
     172           2 :         UNBIND(y);
     173             : 
     174           2 :         Py_XDECREF(x);
     175           2 :         Py_XDECREF(y);
     176           2 :         Py_DECREF(one);
     177             :     }
     178             : 
     179             :     /* Test F_PY_TO_{S,U} on non-pylong input. This should raise a TypeError. */
     180             :     {
     181             :         TYPENAME out;
     182             :         unsigned TYPENAME uout;
     183             : 
     184           2 :         Py_INCREF(Py_None);
     185             : 
     186           2 :         out = F_PY_TO_S(Py_None);
     187           2 :         if (out != (TYPENAME)-1 || !PyErr_Occurred())
     188           0 :             return error("PyLong_AsXXX(None) didn't complain");
     189           2 :         if (!PyErr_ExceptionMatches(PyExc_TypeError))
     190           0 :             return error("PyLong_AsXXX(None) raised "
     191             :                          "something other than TypeError");
     192           2 :         PyErr_Clear();
     193             : 
     194           2 :         uout = F_PY_TO_U(Py_None);
     195           2 :         if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred())
     196           0 :             return error("PyLong_AsXXX(None) didn't complain");
     197           2 :         if (!PyErr_ExceptionMatches(PyExc_TypeError))
     198           0 :             return error("PyLong_AsXXX(None) raised "
     199             :                          "something other than TypeError");
     200           2 :         PyErr_Clear();
     201             : 
     202           2 :         Py_DECREF(Py_None);
     203             :     }
     204             : 
     205           2 :     Py_INCREF(Py_None);
     206           2 :     return Py_None;
     207             : }

Generated by: LCOV version 1.14