Branch data 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 : 2 : for (i = 0; 27 [ + + ]: 132 : 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 : : }