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 | TESTNAME(PyObject *error(const char*)) |
12 | { |
13 | 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 | base = 1; |
26 | for (i = 0; |
27 | i < NBITS + 1; /* on last, base overflows to 0 */ |
28 | ++i, base <<= 1) |
29 | { |
30 | int j; |
31 | 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 | 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 | uin += (unsigned TYPENAME)(TYPENAME)(j % 3 - 1); |
43 | |
44 | pyresult = F_U_TO_PY(uin); |
45 | if (pyresult == NULL) |
46 | return error( |
47 | "unsigned unexpected null result" ); |
48 | |
49 | uout = F_PY_TO_U(pyresult); |
50 | if (uout == (unsigned TYPENAME)-1 && PyErr_Occurred()) |
51 | return error( |
52 | "unsigned unexpected -1 result" ); |
53 | if (uout != uin) |
54 | return error( |
55 | "unsigned output != input" ); |
56 | UNBIND(pyresult); |
57 | |
58 | in = (TYPENAME)uin; |
59 | pyresult = F_S_TO_PY(in); |
60 | if (pyresult == NULL) |
61 | return error( |
62 | "signed unexpected null result" ); |
63 | |
64 | out = F_PY_TO_S(pyresult); |
65 | if (out == (TYPENAME)-1 && PyErr_Occurred()) |
66 | return error( |
67 | "signed unexpected -1 result" ); |
68 | if (out != in) |
69 | return error( |
70 | "signed output != input" ); |
71 | 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 | one = PyLong_FromLong(1); |
85 | if (one == NULL) |
86 | return error( |
87 | "unexpected NULL from PyLong_FromLong" ); |
88 | |
89 | /* Unsigned complains about -1? */ |
90 | x = PyNumber_Negative(one); |
91 | if (x == NULL) |
92 | return error( |
93 | "unexpected NULL from PyNumber_Negative" ); |
94 | |
95 | uout = F_PY_TO_U(x); |
96 | if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred()) |
97 | return error( |
98 | "PyLong_AsUnsignedXXX(-1) didn't complain" ); |
99 | if (!PyErr_ExceptionMatches(PyExc_OverflowError)) |
100 | return error( |
101 | "PyLong_AsUnsignedXXX(-1) raised " |
102 | "something other than OverflowError" ); |
103 | PyErr_Clear(); |
104 | UNBIND(x); |
105 | |
106 | /* Unsigned complains about 2**NBITS? */ |
107 | y = PyLong_FromLong((long)NBITS); |
108 | if (y == NULL) |
109 | return error( |
110 | "unexpected NULL from PyLong_FromLong" ); |
111 | |
112 | x = PyNumber_Lshift(one, y); /* 1L << NBITS, == 2**NBITS */ |
113 | UNBIND(y); |
114 | if (x == NULL) |
115 | return error( |
116 | "unexpected NULL from PyNumber_Lshift" ); |
117 | |
118 | uout = F_PY_TO_U(x); |
119 | if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred()) |
120 | return error( |
121 | "PyLong_AsUnsignedXXX(2**NBITS) didn't " |
122 | "complain" ); |
123 | if (!PyErr_ExceptionMatches(PyExc_OverflowError)) |
124 | return error( |
125 | "PyLong_AsUnsignedXXX(2**NBITS) raised " |
126 | "something other than OverflowError" ); |
127 | PyErr_Clear(); |
128 | |
129 | /* Signed complains about 2**(NBITS-1)? |
130 | x still has 2**NBITS. */ |
131 | y = PyNumber_Rshift(x, one); /* 2**(NBITS-1) */ |
132 | UNBIND(x); |
133 | if (y == NULL) |
134 | return error( |
135 | "unexpected NULL from PyNumber_Rshift" ); |
136 | |
137 | out = F_PY_TO_S(y); |
138 | if (out != (TYPENAME)-1 || !PyErr_Occurred()) |
139 | return error( |
140 | "PyLong_AsXXX(2**(NBITS-1)) didn't " |
141 | "complain" ); |
142 | if (!PyErr_ExceptionMatches(PyExc_OverflowError)) |
143 | return error( |
144 | "PyLong_AsXXX(2**(NBITS-1)) raised " |
145 | "something other than OverflowError" ); |
146 | PyErr_Clear(); |
147 | |
148 | /* Signed complains about -2**(NBITS-1)-1?; |
149 | y still has 2**(NBITS-1). */ |
150 | x = PyNumber_Negative(y); /* -(2**(NBITS-1)) */ |
151 | UNBIND(y); |
152 | if (x == NULL) |
153 | return error( |
154 | "unexpected NULL from PyNumber_Negative" ); |
155 | |
156 | y = PyNumber_Subtract(x, one); /* -(2**(NBITS-1))-1 */ |
157 | UNBIND(x); |
158 | if (y == NULL) |
159 | return error( |
160 | "unexpected NULL from PyNumber_Subtract" ); |
161 | |
162 | out = F_PY_TO_S(y); |
163 | if (out != (TYPENAME)-1 || !PyErr_Occurred()) |
164 | return error( |
165 | "PyLong_AsXXX(-2**(NBITS-1)-1) didn't " |
166 | "complain" ); |
167 | if (!PyErr_ExceptionMatches(PyExc_OverflowError)) |
168 | return error( |
169 | "PyLong_AsXXX(-2**(NBITS-1)-1) raised " |
170 | "something other than OverflowError" ); |
171 | PyErr_Clear(); |
172 | UNBIND(y); |
173 | |
174 | Py_XDECREF(x); |
175 | Py_XDECREF(y); |
176 | 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 | Py_INCREF(Py_None); |
185 | |
186 | out = F_PY_TO_S(Py_None); |
187 | if (out != (TYPENAME)-1 || !PyErr_Occurred()) |
188 | return error("PyLong_AsXXX(None) didn't complain" ); |
189 | if (!PyErr_ExceptionMatches(PyExc_TypeError)) |
190 | return error("PyLong_AsXXX(None) raised " |
191 | "something other than TypeError" ); |
192 | PyErr_Clear(); |
193 | |
194 | uout = F_PY_TO_U(Py_None); |
195 | if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred()) |
196 | return error("PyLong_AsXXX(None) didn't complain" ); |
197 | if (!PyErr_ExceptionMatches(PyExc_TypeError)) |
198 | return error("PyLong_AsXXX(None) raised " |
199 | "something other than TypeError" ); |
200 | PyErr_Clear(); |
201 | |
202 | Py_DECREF(Py_None); |
203 | } |
204 | |
205 | Py_INCREF(Py_None); |
206 | return Py_None; |
207 | } |
208 | |