Petr Machata f94892
Index: /trunk/libs/python/test/test_builtin_converters.py
Petr Machata f94892
===================================================================
Petr Machata f94892
--- /trunk/libs/python/test/test_builtin_converters.py (revision 40714)
Petr Machata f94892
+++ /trunk/libs/python/test/test_builtin_converters.py (revision 54919)
Petr Machata f94892
@@ -4,4 +4,22 @@
Petr Machata f94892
 r"""
Petr Machata f94892
 >>> from builtin_converters_ext import *
Petr Machata f94892
+
Petr Machata f94892
+# Use ctypes to get native C type sizes
Petr Machata f94892
+>>> from ctypes import sizeof, c_char, c_short, c_int, c_long, c_longlong
Petr Machata f94892
+>>> def test_values_signed(t):
Petr Machata f94892
+...     base = 2 ** (8 * sizeof(t) - 1)
Petr Machata f94892
+...     return [[-base, -1, 1, base - 1], [-base - 1, base]]
Petr Machata f94892
+>>> def test_values_unsigned(t):
Petr Machata f94892
+...     base = 2 ** (8 * sizeof(t))
Petr Machata f94892
+...     return [[1, base - 1], [-1L, -1, base]]
Petr Machata f94892
+>>> def should_pass(method, values):
Petr Machata f94892
+...     result = map(method, values)
Petr Machata f94892
+...     if result != values:
Petr Machata f94892
+...         print "Got %s but expected %s" % (result, values)
Petr Machata f94892
+>>> def test_overflow(method, values):
Petr Machata f94892
+...     for v in values:
Petr Machata f94892
+...         try: method(v)
Petr Machata f94892
+...         except OverflowError: pass
Petr Machata f94892
+...         else: print "OverflowError expected"
Petr Machata f94892
 
Petr Machata f94892
 # Synthesize idendity functions in case long long not supported
Petr Machata f94892
@@ -63,13 +81,35 @@
Petr Machata f94892
 
Petr Machata f94892
    show that we have range checking. 
Petr Machata f94892
- 
Petr Machata f94892
->>> try: rewrap_value_unsigned_short(-42)
Petr Machata f94892
-... except OverflowError: pass
Petr Machata f94892
-... else: print 'expected an OverflowError!'
Petr Machata f94892
-
Petr Machata f94892
->>> try: rewrap_value_int(sys.maxint * 2)
Petr Machata f94892
-... except OverflowError: pass
Petr Machata f94892
-... else: print 'expected an OverflowError!'
Petr Machata f94892
-
Petr Machata f94892
+
Petr Machata f94892
+>>> should_pass(rewrap_value_signed_char, test_values_signed(c_char)[0])
Petr Machata f94892
+>>> should_pass(rewrap_value_short, test_values_signed(c_short)[0])
Petr Machata f94892
+>>> should_pass(rewrap_value_int, test_values_signed(c_int)[0])
Petr Machata f94892
+>>> should_pass(rewrap_value_long, test_values_signed(c_long)[0])
Petr Machata f94892
+>>> should_pass(rewrap_value_long_long, test_values_signed(c_longlong)[0])
Petr Machata f94892
+
Petr Machata f94892
+>>> should_pass(rewrap_value_unsigned_char, test_values_unsigned(c_char)[0])
Petr Machata f94892
+>>> should_pass(rewrap_value_unsigned_short, test_values_unsigned(c_short)[0])
Petr Machata f94892
+>>> should_pass(rewrap_value_unsigned_int, test_values_unsigned(c_int)[0])
Petr Machata f94892
+>>> should_pass(rewrap_value_unsigned_long, test_values_unsigned(c_long)[0])
Petr Machata f94892
+>>> should_pass(rewrap_value_unsigned_long_long,
Petr Machata f94892
+...     test_values_unsigned(c_longlong)[0])
Petr Machata f94892
+
Petr Machata f94892
+>>> test_overflow(rewrap_value_signed_char, test_values_signed(c_char)[1])
Petr Machata f94892
+>>> test_overflow(rewrap_value_short, test_values_signed(c_short)[1])
Petr Machata f94892
+>>> test_overflow(rewrap_value_int, test_values_signed(c_int)[1])
Petr Machata f94892
+>>> test_overflow(rewrap_value_long, test_values_signed(c_long)[1])
Petr Machata f94892
+>>> test_overflow(rewrap_value_long_long, test_values_signed(c_longlong)[1])
Petr Machata f94892
+
Petr Machata f94892
+>>> test_overflow(rewrap_value_unsigned_char, test_values_unsigned(c_char)[1])
Petr Machata f94892
+>>> test_overflow(rewrap_value_unsigned_short, test_values_unsigned(c_short)[1])
Petr Machata f94892
+>>> test_overflow(rewrap_value_unsigned_int, test_values_unsigned(c_int)[1])
Petr Machata f94892
+>>> test_overflow(rewrap_value_unsigned_long, test_values_unsigned(c_long)[1])
Petr Machata f94892
+
Petr Machata f94892
+# Exceptionally for PyLong_AsUnsignedLongLong(), a negative value raises
Petr Machata f94892
+# TypeError on Python versions prior to 2.7
Petr Machata f94892
+>>> for v in test_values_unsigned(c_longlong)[1]:
Petr Machata f94892
+...     try: rewrap_value_unsigned_long_long(v)
Petr Machata f94892
+...     except (OverflowError, TypeError): pass
Petr Machata f94892
+...     else: print "OverflowError or TypeError expected"
Petr Machata f94892
 
Petr Machata f94892
 >>> assert abs(rewrap_value_float(4.2) - 4.2) < .000001
Petr Machata f94892
Index: /trunk/libs/python/src/converter/builtin_converters.cpp
Petr Machata f94892
===================================================================
Petr Machata f94892
--- /trunk/libs/python/src/converter/builtin_converters.cpp (revision 52299)
Petr Machata f94892
+++ /trunk/libs/python/src/converter/builtin_converters.cpp (revision 54919)
Petr Machata f94892
@@ -156,8 +156,25 @@
Petr Machata f94892
       static T extract(PyObject* intermediate)
Petr Machata f94892
       {
Petr Machata f94892
-          return numeric_cast<T>(
Petr Machata f94892
-              PyLong_Check(intermediate)
Petr Machata f94892
-              ? PyLong_AsUnsignedLong(intermediate)
Petr Machata f94892
-              : PyInt_AS_LONG(intermediate));
Petr Machata f94892
+          if (PyLong_Check(intermediate)) {
Petr Machata f94892
+              // PyLong_AsUnsignedLong() checks for negative overflow, so no
Petr Machata f94892
+              // need to check it here.
Petr Machata f94892
+              unsigned long result = PyLong_AsUnsignedLong(intermediate);
Petr Machata f94892
+              if (PyErr_Occurred())
Petr Machata f94892
+                  throw_error_already_set();
Petr Machata f94892
+              return numeric_cast<T>(result);
Petr Machata f94892
+          } else {
Petr Machata f94892
+              // None of PyInt_AsUnsigned*() functions check for negative
Petr Machata f94892
+              // overflow, so use PyInt_AS_LONG instead and check if number is
Petr Machata f94892
+              // negative, issuing the exception appropriately.
Petr Machata f94892
+              long result = PyInt_AS_LONG(intermediate);
Petr Machata f94892
+              if (PyErr_Occurred())
Petr Machata f94892
+                  throw_error_already_set();
Petr Machata f94892
+              if (result < 0) {
Petr Machata f94892
+                  PyErr_SetString(PyExc_OverflowError, "can't convert negative"
Petr Machata f94892
+                                  " value to unsigned");
Petr Machata f94892
+                  throw_error_already_set();
Petr Machata f94892
+              }
Petr Machata f94892
+              return numeric_cast<T>(result);
Petr Machata f94892
+          }
Petr Machata f94892
       }
Petr Machata f94892
   };