aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libshiboken/conversions.h45
-rw-r--r--tests/libsample/functions.cpp29
-rw-r--r--tests/libsample/functions.h6
-rwxr-xr-xtests/samplebinding/implicitconv_numerical_test.py134
-rw-r--r--tests/samplebinding/typesystem_sample.xml1
5 files changed, 206 insertions, 9 deletions
diff --git a/libshiboken/conversions.h b/libshiboken/conversions.h
index 301a27212..93d777fcd 100644
--- a/libshiboken/conversions.h
+++ b/libshiboken/conversions.h
@@ -194,6 +194,15 @@ struct Converter<bool>
}
};
+/**
+ * Helper template for checking if a value of SourceT overflows when cast to TargetT
+ */
+template<typename SourceT, typename TargetT>
+inline bool overflowCheck(SourceT value)
+{
+ return value < std::numeric_limits<TargetT>::min() || value > std::numeric_limits<TargetT>::max();
+}
+
template <typename PyIntEquiv>
struct Converter_PyInt
{
@@ -203,12 +212,19 @@ struct Converter_PyInt
}
static PyIntEquiv toCpp(PyObject* pyobj)
{
+ double d_result;
long result;
- if (PyFloat_Check(pyobj))
- result = (long) PyFloat_AS_DOUBLE(pyobj);
- else
- result = PyInt_AS_LONG(pyobj);
- if (result < std::numeric_limits<PyIntEquiv>::min() || result > std::numeric_limits<PyIntEquiv>::max())
+ if (PyFloat_Check(pyobj)) {
+ d_result = PyFloat_AS_DOUBLE(pyobj);
+ // If cast to long directly it could overflow silently
+ if (overflowCheck<double, PyIntEquiv>(d_result))
+ PyErr_SetObject(PyExc_OverflowError, 0);
+ return (PyIntEquiv) d_result;
+ } else {
+ result = PyLong_AsLong(pyobj);
+ }
+
+ if (overflowCheck<long, PyIntEquiv>(result))
PyErr_SetObject(PyExc_OverflowError, 0);
return (PyIntEquiv) result;
}
@@ -232,7 +248,18 @@ struct Converter<unsigned long>
}
static unsigned long toCpp(PyObject* pyobj)
{
- return PyLong_AsUnsignedLong(pyobj);
+ unsigned long result;
+ if (PyFloat_Check(pyobj)) {
+ // Need to check for negatives manually
+ double double_result = PyFloat_AS_DOUBLE(pyobj);
+ if (overflowCheck<double, unsigned long>(double_result))
+ PyErr_SetObject(PyExc_OverflowError, 0);
+ result = (unsigned long) double_result;
+ } else {
+ result = PyLong_AsUnsignedLong(pyobj);
+ }
+
+ return result;
}
};
@@ -271,9 +298,9 @@ struct Converter_PyFloat
}
static PyFloatEquiv toCpp(PyObject* pyobj)
{
- if (PyInt_Check(pyobj))
- return (PyFloatEquiv) PyInt_AS_LONG(pyobj);
- return (PyFloatEquiv) PyFloat_AS_DOUBLE(pyobj);
+ if (PyInt_Check(pyobj) || PyLong_Check(pyobj))
+ return (PyFloatEquiv) PyLong_AsLong(pyobj);
+ return (PyFloatEquiv) PyFloat_AsDouble(pyobj);
}
};
diff --git a/tests/libsample/functions.cpp b/tests/libsample/functions.cpp
index 8a7416bc6..0df75ba90 100644
--- a/tests/libsample/functions.cpp
+++ b/tests/libsample/functions.cpp
@@ -141,3 +141,32 @@ doubleUnsignedInt(unsigned int value)
return value * 2;
}
+int
+acceptInt(int x)
+{
+ return x;
+}
+
+unsigned int
+acceptUInt(unsigned int x)
+{
+ return x;
+}
+
+long
+acceptLong(long x)
+{
+ return x;
+}
+
+unsigned long
+acceptULong(unsigned long x)
+{
+ return x;
+}
+
+double
+acceptDouble(double x)
+{
+ return x;
+}
diff --git a/tests/libsample/functions.h b/tests/libsample/functions.h
index 2629d3907..52a26a7a6 100644
--- a/tests/libsample/functions.h
+++ b/tests/libsample/functions.h
@@ -74,5 +74,11 @@ LIBSAMPLE_API GlobalOverloadFuncEnum overloadedFunc(double val);
LIBSAMPLE_API unsigned int doubleUnsignedInt(unsigned int value);
+LIBSAMPLE_API int acceptInt(int x);
+LIBSAMPLE_API unsigned int acceptUInt(unsigned int x);
+LIBSAMPLE_API long acceptLong(long x);
+LIBSAMPLE_API unsigned long acceptULong(unsigned long x);
+LIBSAMPLE_API double acceptDouble(double x);
+
#endif // FUNCTIONS_H
diff --git a/tests/samplebinding/implicitconv_numerical_test.py b/tests/samplebinding/implicitconv_numerical_test.py
new file mode 100755
index 000000000..d81a882c5
--- /dev/null
+++ b/tests/samplebinding/implicitconv_numerical_test.py
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+# This file is part of the Shiboken Python Bindings Generator project.
+#
+# Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+#
+# Contact: PySide team <contact@pyside.org>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public License
+# version 2.1 as published by the Free Software Foundation. Please
+# review the following information to ensure the GNU Lesser General
+# Public License version 2.1 requirements will be met:
+# http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+# #
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+# 02110-1301 USA
+
+'''Test case for inplicit converting C++ numeric types.'''
+
+import unittest
+import sys
+import sample
+
+
+class NumericTester(unittest.TestCase):
+ '''Helper class for numeric comparison testing'''
+
+ def check_value(self, source, expected, callback, desired_type=None):
+ result = callback(source)
+ self.assertEqual(result, expected)
+
+ if desired_type:
+ self.assertEqual(type(result), desired_type)
+
+
+class FloatImplicitConvert(NumericTester):
+ '''Test case for implicit converting C++ numeric types.'''
+
+ def testFloatAsInt(self):
+ '''Float as Int'''
+ self.check_value(3.14, 3, sample.acceptInt, int)
+ self.assertRaises(OverflowError, sample.acceptInt, sys.maxint + 400)
+
+ def testFloatAsLong(self):
+ '''Float as Long'''
+ #C++ longs are python ints for us
+ self.check_value(3.14, 3, sample.acceptLong, int)
+ self.assertRaises(OverflowError, sample.acceptLong, sys.maxint + 400)
+
+ def testFloatAsUInt(self):
+ '''Float as unsigned Int'''
+ self.check_value(3.14, 3, sample.acceptUInt, int)
+ self.assertRaises(OverflowError, sample.acceptUInt, -3.14)
+
+ def testFloatAsULong(self):
+ '''Float as unsigned Long'''
+ #FIXME Breaking with SystemError "bad argument to internal function"
+ self.check_value(3.14, 3, sample.acceptULong, long)
+ self.assertRaises(OverflowError, sample.acceptULong, -3.14)
+
+ def testFloatAsDouble(self):
+ '''Float as double'''
+ self.check_value(3.14, 3.14, sample.acceptDouble, float)
+
+
+class IntImplicitConvert(NumericTester):
+ '''Test case for implicit converting C++ numeric types.'''
+
+ def testIntAsInt(self):
+ '''Int as Int'''
+ self.check_value(3, 3, sample.acceptInt, int)
+
+ def testIntAsLong(self):
+ '''Int as Long'''
+ self.check_value(3, 3, sample.acceptLong, int)
+
+ # sys.maxint goes here as CPython implements int as a C long
+ self.check_value(sys.maxint, sys.maxint, sample.acceptLong, int)
+ self.check_value(-sys.maxint - 1, -sys.maxint - 1, sample.acceptLong, int)
+
+ def testIntAsUInt(self):
+ '''Int as unsigned Int'''
+ self.check_value(3, 3, sample.acceptUInt, int)
+ self.assertRaises(OverflowError, sample.acceptUInt, -3)
+
+ def testIntAsULong(self):
+ '''Int as unsigned Long'''
+ self.check_value(3, 3, sample.acceptULong, long)
+ self.assertRaises(OverflowError, sample.acceptULong, -3)
+
+ def testFloatAsDouble(self):
+ '''Float as double'''
+ self.check_value(3.14, 3.14, sample.acceptDouble, float)
+
+
+class LongImplicitConvert(NumericTester):
+ '''Test case for implicit converting C++ numeric types.'''
+
+ def testLongAsInt(self):
+ '''Long as Int'''
+ self.check_value(24224l, 24224, sample.acceptInt, int)
+ self.assertRaises(OverflowError, sample.acceptInt, sys.maxint + 20)
+
+ def testLongAsLong(self):
+ '''Long as Long'''
+ self.check_value(2405l, 2405, sample.acceptLong, int)
+ self.assertRaises(OverflowError, sample.acceptLong, sys.maxint + 20)
+
+ def testLongAsUInt(self):
+ '''Long as unsigned Int'''
+ self.check_value(260l, 260, sample.acceptUInt, int)
+ self.assertRaises(OverflowError, sample.acceptUInt, -42)
+
+ def testLongAsULong(self):
+ '''Long as unsigned Long'''
+ self.check_value(128l, 128, sample.acceptULong, long)
+ self.assertRaises(OverflowError, sample.acceptULong, -334l)
+
+ def testLongAsDouble(self):
+ '''Float as double'''
+ self.check_value(42l, 42, sample.acceptDouble, float)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml
index f7b963e93..9dc3d1798 100644
--- a/tests/samplebinding/typesystem_sample.xml
+++ b/tests/samplebinding/typesystem_sample.xml
@@ -7,6 +7,7 @@
<primitive-type name="signed int" />
<primitive-type name="char"/>
<primitive-type name="long"/>
+ <primitive-type name="unsigned long"/>
<primitive-type name="Complex" target-lang-api-name="PyComplex">
<conversion-rule file="complex_conversions.h"/>