From 04d571f872a8cada531646f15b2d4440b20d0d53 Mon Sep 17 00:00:00 2001 From: Marcelo Lira Date: Fri, 15 Apr 2011 16:39:33 -0300 Subject: Overload decisor was improved to consider PySequences on modified function signatures. Unit tests were added as usual. Reviewer: Hugo Parente Renato Araujo --- generator/overloaddata.cpp | 26 ++++++++++-- tests/libsample/overload.h | 8 ++++ tests/samplebinding/overload_test.py | 68 +++++++++++++++++++++++++++---- tests/samplebinding/typesystem_sample.xml | 26 ++++++++++++ 4 files changed, 116 insertions(+), 12 deletions(-) diff --git a/generator/overloaddata.cpp b/generator/overloaddata.cpp index 7e3f608cd..1390eea08 100644 --- a/generator/overloaddata.cpp +++ b/generator/overloaddata.cpp @@ -156,6 +156,8 @@ void OverloadData::sortNextOverloads() OverloadSortData sortData; bool checkPyObject = false; int pyobjectIndex = 0; + bool checkPySequence = false; + int pySeqIndex = 0; bool checkQString = false; int qstringIndex = 0; bool checkQVariant = false; @@ -188,6 +190,9 @@ void OverloadData::sortNextOverloads() if (!checkPyObject && typeName.contains("PyObject")) { checkPyObject = true; pyobjectIndex = sortData.lastProcessedItemId(); + } else if (!checkPySequence && typeName == "PySequence") { + checkPySequence = true; + pySeqIndex = sortData.lastProcessedItemId(); } else if (!checkQVariant && typeName == "QVariant") { checkQVariant = true; qvariantIndex = sortData.lastProcessedItemId(); @@ -238,6 +243,9 @@ void OverloadData::sortNextOverloads() for (int i = 0; i < numPrimitives; ++i) hasPrimitive[i] = sortData.map.contains(primitiveTypes[i]); + if (checkPySequence && checkPyObject) + graph.addEdge(pySeqIndex, pyobjectIndex); + QStringList classesWithIntegerImplicitConversion; foreach(OverloadData* ov, m_nextOverloadData) { @@ -305,13 +313,23 @@ void OverloadData::sortNextOverloads() } } - /* Add dependency on PyObject, so its check is the last one (too generic) */ - if (checkPyObject && !targetTypeEntryName.contains("PyObject")) { - graph.addEdge(targetTypeId, pyobjectIndex); + + if ((checkPySequence || checkPyObject) + && !targetTypeEntryName.contains("PyObject") + && !targetTypeEntryName.contains("PySequence")) { + if (checkPySequence) { + // PySequence will be checked after all more specific types, but before PyObject. + graph.addEdge(targetTypeId, pySeqIndex); + } else { + // Add dependency on PyObject, so its check is the last one (too generic). + graph.addEdge(targetTypeId, pyobjectIndex); + } } else if (checkQVariant && targetTypeEntryName != "QVariant") { if (!graph.containsEdge(qvariantIndex, targetTypeId)) // Avoid cyclic dependency. graph.addEdge(targetTypeId, qvariantIndex); - } else if (checkQString && ov->argType()->indirections() > 0 && targetTypeEntryName != "QString" && targetTypeEntryName != "QByteArray") { + } else if (checkQString && ov->argType()->indirections() > 0 + && targetTypeEntryName != "QString" + && targetTypeEntryName != "QByteArray") { if (!graph.containsEdge(qstringIndex, targetTypeId)) // Avoid cyclic dependency. graph.addEdge(targetTypeId, qstringIndex); } diff --git a/tests/libsample/overload.h b/tests/libsample/overload.h index a0682fe18..bbac9afa4 100644 --- a/tests/libsample/overload.h +++ b/tests/libsample/overload.h @@ -106,6 +106,14 @@ public: // Another simpler variant of the one similar to QPainter::drawText(...) FunctionEnum drawText4(int a0, int a1, int a2) { return Function0; } FunctionEnum drawText4(int a0, int a1, int a2, int a3, int a4) { return Function1; } + + FunctionEnum acceptSequence() { return Function0; } + FunctionEnum acceptSequence(int a0, int a1) { return Function1; } + FunctionEnum acceptSequence(const Str& a0, ParamEnum a1 = Param0) { return Function2; } + FunctionEnum acceptSequence(const Size& a0) { return Function3; } + // The type must be changed to PySequence. + FunctionEnum acceptSequence(const char* const a0[]) { return Function4; } + FunctionEnum acceptSequence(void* a0) { return Function5; } }; class LIBSAMPLE_API Overload2 : public Overload diff --git a/tests/samplebinding/overload_test.py b/tests/samplebinding/overload_test.py index e165ef854..3c3fa2751 100644 --- a/tests/samplebinding/overload_test.py +++ b/tests/samplebinding/overload_test.py @@ -27,9 +27,23 @@ '''Test cases for Overload class''' import unittest - from sample import Echo, Overload, Point, PointF, Polygon, Rect, RectF, Size, Str + +def raisesWithErrorMessage(func, arguments, errorType, errorMsg): + '''NOTE: Using 'try' because assertRaisesRegexp is not available + to check the error message.''' + try: + func(*arguments) + return False + except Exception as err: + if type(err) != TypeError: + return False + if not errorMsg in str(err): + return False + return True + + class OverloadTest(unittest.TestCase): '''Test case for Overload class''' @@ -133,19 +147,57 @@ class OverloadTest(unittest.TestCase): def testDrawText3Exception(self): overload = Overload() - # NOTE: Using 'try' because assertRaisesRegexp is not available. - # to check the error text. - try: - overload.drawText3(Str(), Str(), Str(), 4, 5) - except Exception as err: - self.assertEqual(type(err), TypeError) - self.assertTrue('called with wrong argument types:' in str(err)) + args = (Str(), Str(), Str(), 4, 5) + result = raisesWithErrorMessage(overload.drawText3, args, + TypeError, 'called with wrong argument types:') + self.assert_(result) def testDrawText4(self): overload = Overload() self.assertEqual(overload.drawText4(1, 2, 3), Overload.Function0) self.assertEqual(overload.drawText4(1, 2, 3, 4, 5), Overload.Function1) + def testAcceptSequence(self): + # Overload.acceptSequence() + overload = Overload() + self.assertEqual(overload.acceptSequence(), Overload.Function0) + + def testAcceptSequenceIntInt(self): + # Overload.acceptSequence(int,int) + overload = Overload() + self.assertEqual(overload.acceptSequence(1, 2), Overload.Function1) + + def testAcceptSequenceStrParamEnum(self): + # Overload.acceptSequence(Str,Overload::ParamEnum) + overload = Overload() + self.assertEqual(overload.acceptSequence(''), Overload.Function2) + self.assertEqual(overload.acceptSequence('', Overload.Param0), Overload.Function2) + self.assertEqual(overload.acceptSequence(Str('')), Overload.Function2) + self.assertEqual(overload.acceptSequence(Str(''), Overload.Param0), Overload.Function2) + + def testAcceptSequenceSize(self): + # Overload.acceptSequence(Size) + overload = Overload() + self.assertEqual(overload.acceptSequence(Size()), Overload.Function3) + + def testAcceptSequenceStringList(self): + # Overload.acceptSequence(const char**) + overload = Overload() + strings = ['line 1', 'line 2'] + self.assertEqual(overload.acceptSequence(strings), Overload.Function4) + args = (['line 1', 2], ) + result = raisesWithErrorMessage(overload.acceptSequence, args, + TypeError, 'The argument must be a sequence of strings.') + self.assert_(result) + + def testAcceptSequencePyObject(self): + # Overload.acceptSequence(void*) + overload = Overload() + class Foo(object): + pass + foo = Foo() + self.assertEqual(overload.acceptSequence(foo), Overload.Function5) + if __name__ == '__main__': unittest.main() diff --git a/tests/samplebinding/typesystem_sample.xml b/tests/samplebinding/typesystem_sample.xml index e1837bbd3..eeaf3c218 100644 --- a/tests/samplebinding/typesystem_sample.xml +++ b/tests/samplebinding/typesystem_sample.xml @@ -1203,6 +1203,32 @@ + + + + + { + Shiboken::AutoDecRef strList(PySequence_Fast(%PYARG_1, "The argument must be a sequence.")); + int lineCount = PySequence_Fast_GET_SIZE(strList.object()); + for (int line = 0; line < lineCount; ++line) { + if (!PyString_Check(PySequence_Fast_GET_ITEM(strList.object(), line))) { + PyErr_SetString(PyExc_TypeError, "The argument must be a sequence of strings."); + break; + } + } + } + const char** %out = 0; + + + + + + + + void* %out = 0; + + +