[Python-checkins] CVS: python/dist/src/Modules testcapi_long.h,NONE,1.1 _testcapimodule.c,1.5,1.6

Tim Peters tim_one@users.sourceforge.net
Wed, 13 Jun 2001 17:55:43 -0700


Update of /cvsroot/python/python/dist/src/Modules
In directory usw-pr-cvs1:/tmp/cvs-serv9814/python/dist/src/Modules

Modified Files:
	_testcapimodule.c 
Added Files:
	testcapi_long.h 
Log Message:
Add tests of PyLong_{As,From}{Unsigned,}Long.  These are very much like
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.


--- NEW FILE: testcapi_long.h ---
/* 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;
}

Index: _testcapimodule.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/_testcapimodule.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -C2 -r1.5 -r1.6
*** _testcapimodule.c	2001/06/13 00:35:57	1.5
--- _testcapimodule.c	2001/06/14 00:55:41	1.6
***************
*** 173,181 ****
  }
  
! #ifdef HAVE_LONG_LONG
  
! /* Basic sanity checks for PyLong_{As, From}{Unsigned,}LongLong(). */
  
  static PyObject *
  raise_test_longlong_error(const char* msg)
  {
--- 173,230 ----
  }
  
! 
! /* 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)
  {
***************
*** 183,352 ****
  }
  
! #define UNBIND(X)  Py_DECREF(X); (X) = NULL
  
  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;
  
! 
! 	/* 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);
! 	}
  
! 	Py_INCREF(Py_None);
! 	return Py_None;
! }
  
- #endif
  
  static PyMethodDef TestMethods[] = {
--- 232,264 ----
  }
  
! #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)
  {
          if (!PyArg_ParseTuple(args, ":test_longlong_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
  
! #endif	/* ifdef HAVE_LONG_LONG */
  
  
  static PyMethodDef TestMethods[] = {
***************
*** 354,357 ****
--- 266,270 ----
  	{"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},