summaryrefslogtreecommitdiffstats
path: root/Modules/testcapi_long.h
blob: 8ed6b021ea45ef546ce65e593b6ebd68950d29f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/* 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* -> unsigned TYPENAME
*/

static PyObject *
TESTNAME(PyObject *error(const char*))
{
	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 error(
				 "unsigned unexpected null result");

			uout = F_PY_TO_U(pyresult);
			if (uout == (unsigned TYPENAME)-1 && PyErr_Occurred())
				return error(
					"unsigned unexpected -1 result");
			if (uout != uin)
				return error(
					"unsigned output != input");
			UNBIND(pyresult);

			in = (TYPENAME)uin;
			pyresult = F_S_TO_PY(in);
			if (pyresult == NULL)
				return error(
					"signed unexpected null result");

			out = F_PY_TO_S(pyresult);
			if (out == (TYPENAME)-1 && PyErr_Occurred())
				return error(
					"signed unexpected -1 result");
			if (out != in)
				return 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 error(
				"unexpected NULL from PyLong_FromLong");

		/* Unsigned complains about -1? */
		x = PyNumber_Negative(one);
		if (x == NULL)
			return error(
				"unexpected NULL from PyNumber_Negative");

		uout = F_PY_TO_U(x);
		if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred())
			return 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 error(
				"unexpected NULL from PyLong_FromLong");

		x = PyNumber_Lshift(one, y); /* 1L << NBITS, == 2**NBITS */
		UNBIND(y);
		if (x == NULL)
			return error(
				"unexpected NULL from PyNumber_Lshift");

  		uout = F_PY_TO_U(x);
		if (uout != (unsigned TYPENAME)-1 || !PyErr_Occurred())
			return 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 error(
				"unexpected NULL from PyNumber_Rshift");

		out = F_PY_TO_S(y);
		if (out != (TYPENAME)-1 || !PyErr_Occurred())
			return 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 error(
				"unexpected NULL from PyNumber_Negative");

		y = PyNumber_Subtract(x, one); /* -(2**(NBITS-1))-1 */
		UNBIND(x);
		if (y == NULL)
			return error(
				"unexpected NULL from PyNumber_Subtract");

		out = F_PY_TO_S(y);
		if (out != (TYPENAME)-1 || !PyErr_Occurred())
			return 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;
}