diff options
Diffstat (limited to 'sources/shiboken2/ApiExtractor/tests/testtemplates.cpp')
-rw-r--r-- | sources/shiboken2/ApiExtractor/tests/testtemplates.cpp | 438 |
1 files changed, 438 insertions, 0 deletions
diff --git a/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp new file mode 100644 index 000000000..cb90383db --- /dev/null +++ b/sources/shiboken2/ApiExtractor/tests/testtemplates.cpp @@ -0,0 +1,438 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the test suite of PySide2. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "testtemplates.h" +#include <QtTest/QTest> +#include <QTemporaryFile> +#include "testutil.h" +#include <abstractmetalang.h> +#include <typesystem.h> + +void TestTemplates::testTemplateWithNamespace() +{ + const char cppCode[] = "\n\ + template<typename T> struct QList {}; \n\ + struct Url {\n\ + void name();\n\ + };\n\ + namespace Internet {\n\ + struct Url{};\n\ + struct Bookmarks {\n\ + QList<Url> list();\n\ + };\n\ + }"; + const char xmlCode0[] = "\n\ + <typesystem package='Pakcage.Network'>\n\ + <value-type name='Url'/>\n\ + </typesystem>"; + + QTemporaryFile file; + QVERIFY(file.open()); + file.write(xmlCode0); + file.close(); + + QString xmlCode1 = QString::fromLatin1("\n\ + <typesystem package='Package.Internet'>\n\ + <load-typesystem name='%1' generate='no'/>\n\ + <container-type name='QList' type='list'/>\n\ + <namespace-type name='Internet' generate='no'/>\n\ + <value-type name='Internet::Url'/>\n\ + <value-type name='Internet::Bookmarks'/>\n\ + </typesystem>").arg(file.fileName()); + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, qPrintable(xmlCode1), false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + + AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("Bookmarks")); + QVERIFY(classB); + const AbstractMetaFunction* func = classB->findFunction(QLatin1String("list")); + AbstractMetaType* funcType = func->type(); + QVERIFY(funcType); + QCOMPARE(funcType->cppSignature(), QLatin1String("QList<Internet::Url >")); +} + +void TestTemplates::testTemplateOnContainers() +{ + const char cppCode[] = "\n\ + struct Base {};\n\ + template<typename T> struct QList {}; \n\ + namespace Namespace {\n\ + enum SomeEnum { E1, E2 };\n\ + template<SomeEnum type> struct A {\n\ + A<type> foo(const QList<A<type> >& a);\n\ + };\n\ + typedef A<E1> B;\n\ + }\n\ + "; + const char xmlCode[] = "\n\ + <typesystem package=\"Package\">\n\ + <container-type name='QList' type='list'/>\n\ + <namespace-type name='Namespace'/>\n\ + <enum-type name='Namespace::SomeEnum'/>\n\ + <object-type name='Base'/>\n\ + <object-type name='Namespace::A' generate='no'/>\n\ + <object-type name='Namespace::B'/>\n\ + </typesystem>"; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + + AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classB); + QVERIFY(!classB->baseClass()); + QVERIFY(classB->baseClassName().isNull()); + const AbstractMetaFunction* func = classB->findFunction(QLatin1String("foo")); + AbstractMetaType* argType = func->arguments().first()->type(); + QCOMPARE(argType->instantiations().count(), 1); + QCOMPARE(argType->typeEntry()->qualifiedCppName(), QLatin1String("QList")); + + const AbstractMetaType* instance1 = argType->instantiations().first(); + QCOMPARE(instance1->instantiations().count(), 1); + QCOMPARE(instance1->typeEntry()->qualifiedCppName(), QLatin1String("Namespace::A")); + + const AbstractMetaType* instance2 = instance1->instantiations().first(); + QCOMPARE(instance2->instantiations().count(), 0); + QCOMPARE(instance2->typeEntry()->qualifiedCppName(), QLatin1String("Namespace::E1")); +} + +void TestTemplates::testTemplateValueAsArgument() +{ + const char cppCode[] = "\n\ + template<typename T> struct List {};\n\ + void func(List<int> arg) {}\n\ + "; + + const char xmlCode[] = "\n\ + <typesystem package='Package'>\n\ + <primitive-type name='int'/>\n\ + <container-type name='List' type='list'/>\n\ + <function signature='func(List<int>)'/>\n\ + </typesystem>\n\ + "; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaFunctionList globalFuncs = builder->globalFunctions(); + QCOMPARE(globalFuncs.count(), 1); + + AbstractMetaFunction* func = globalFuncs.first(); + QCOMPARE(func->minimalSignature(), QLatin1String("func(List<int>)")); + QCOMPARE(func->arguments().first()->type()->cppSignature(), QLatin1String("List<int >")); +} + +void TestTemplates::testTemplatePointerAsArgument() +{ + const char cppCode[] = "\n\ + template<typename T> struct List {};\n\ + void func(List<int>* arg) {}\n\ + "; + + const char xmlCode[] = "\n\ + <typesystem package='Package'>\n\ + <primitive-type name='int'/>\n\ + <container-type name='List' type='list'/>\n\ + <function signature='func(List<int>*)'/>\n\ + </typesystem>\n\ + "; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaFunctionList globalFuncs = builder->globalFunctions(); + QCOMPARE(globalFuncs.count(), 1); + + AbstractMetaFunction* func = globalFuncs.first(); + QCOMPARE(func->minimalSignature(), QLatin1String("func(List<int>*)")); + QCOMPARE(func->arguments().first()->type()->cppSignature(), QLatin1String("List<int > *")); +} + +void TestTemplates::testTemplateReferenceAsArgument() +{ + const char cppCode[] = "\n\ + template<typename T> struct List {};\n\ + void func(List<int>& arg) {}\n\ + "; + + const char xmlCode[] = "\n\ + <typesystem package='Package'>\n\ + <primitive-type name='int'/>\n\ + <container-type name='List' type='list'/>\n\ + <function signature='func(List<int>&)'/>\n\ + </typesystem>\n\ + "; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaFunctionList globalFuncs = builder->globalFunctions(); + QCOMPARE(globalFuncs.count(), 1); + + AbstractMetaFunction* func = globalFuncs.first(); + QCOMPARE(func->minimalSignature(), QLatin1String("func(List<int>&)")); + QCOMPARE(func->arguments().first()->type()->cppSignature(), QLatin1String("List<int > &")); +} + +void TestTemplates::testTemplateParameterFixup() +{ + const char cppCode[] = "\n\ + template<typename T>\n\ + struct List {\n\ + struct Iterator {};\n\ + void append(List l);\n\ + void erase(List::Iterator it);\n\ + };\n"; + + const char xmlCode[] = "\n\ + <typesystem package='Package'>\n\ + <container-type name='List' type='list'/>\n\ + <value-type name='List::Iterator'/>\n\ + </typesystem>\n"; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + const AbstractMetaClassList templates = builder->templates(); + + QCOMPARE(templates.count(), 1); + const AbstractMetaClass *list = templates.first(); + // Verify that the parameter of "void append(List l)" gets fixed to "List<T >" + const AbstractMetaFunction *append = list->findFunction(QStringLiteral("append")); + QVERIFY(append); + QCOMPARE(append->arguments().size(), 1); + QCOMPARE(append->arguments().at(0)->type()->cppSignature(), QLatin1String("List<T >")); + // Verify that the parameter of "void erase(Iterator)" is not modified + const AbstractMetaFunction *erase = list->findFunction(QStringLiteral("erase")); + QVERIFY(erase); + QCOMPARE(erase->arguments().size(), 1); + QCOMPARE(erase->arguments().at(0)->type()->cppSignature(), QLatin1String("List::Iterator")); +} + +void TestTemplates::testInheritanceFromContainterTemplate() +{ + const char cppCode[] = "\n\ + template<typename T>\n\ + struct ListContainer {\n\ + inline void push_front(const T& t);\n\ + inline T& front();\n\ + };\n\ + struct FooBar {};\n\ + struct FooBars : public ListContainer<FooBar> {};\n\ + "; + + const char xmlCode[] = "\n\ + <typesystem package='Package'>\n\ + <container-type name='ListContainer' type='list'/>\n\ + <value-type name='FooBar'/>\n\ + <value-type name='FooBars'>\n\ + <modify-function signature='push_front(FooBar)' remove='all'/>\n\ + <modify-function signature='front()' remove='all'/>\n\ + </value-type>\n\ + </typesystem>\n\ + "; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + AbstractMetaClassList templates = builder->templates(); + QCOMPARE(classes.count(), 2); + QCOMPARE(templates.count(), 1); + + const AbstractMetaClass* foobars = AbstractMetaClass::findClass(classes, QLatin1String("FooBars")); + QCOMPARE(foobars->functions().count(), 4); + + const AbstractMetaClass* lc = templates.first(); + QCOMPARE(lc->functions().count(), 2); +} + +void TestTemplates::testTemplateInheritanceMixedWithForwardDeclaration() +{ + const char cppCode[] = "\n\ + enum SomeEnum { E1, E2 };\n\ + template<SomeEnum type> struct Future;\n\ + template<SomeEnum type>\n\ + struct A {\n\ + A();\n\ + void method();\n\ + friend struct Future<type>;\n\ + };\n\ + typedef A<E1> B;\n\ + template<SomeEnum type> struct Future {};\n\ + "; + const char xmlCode[] = "\n\ + <typesystem package='Package'>\n\ + <enum-type name='SomeEnum'/>\n\ + <value-type name='A' generate='no'/>\n\ + <value-type name='B'/>\n\ + <value-type name='Future' generate='no'/>\n\ + </typesystem>"; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + + AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("B")); + QVERIFY(classB); + QVERIFY(!classB->baseClass()); + QVERIFY(classB->baseClassName().isNull()); + // 3 functions: simple constructor, copy constructor and "method()". + QCOMPARE(classB->functions().count(), 3); +} + +void TestTemplates::testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration() +{ + const char cppCode[] = "\n\ + namespace Namespace {\n\ + enum SomeEnum { E1, E2 };\n\ + template<SomeEnum type> struct Future;\n\ + template<SomeEnum type>\n\ + struct A {\n\ + A();\n\ + void method();\n\ + friend struct Future<type>;\n\ + };\n\ + typedef A<E1> B;\n\ + template<SomeEnum type> struct Future {};\n\ + };\n\ + "; + const char xmlCode[] = "\n\ + <typesystem package='Package'>\n\ + <namespace-type name='Namespace'/>\n\ + <enum-type name='Namespace::SomeEnum'/>\n\ + <value-type name='Namespace::A' generate='no'/>\n\ + <value-type name='Namespace::B'/>\n\ + <value-type name='Namespace::Future' generate='no'/>\n\ + </typesystem>"; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + + AbstractMetaClass* classB = AbstractMetaClass::findClass(classes, QLatin1String("Namespace::B")); + QVERIFY(classB); + QVERIFY(!classB->baseClass()); + QVERIFY(classB->baseClassName().isNull()); + // 3 functions: simple constructor, copy constructor and "method()". + QCOMPARE(classB->functions().count(), 3); +} + +void TestTemplates::testTypedefOfInstantiationOfTemplateClass() +{ + const char cppCode[] = "\n\ + namespace NSpace {\n\ + enum ClassType {\n\ + TypeOne\n\ + };\n\ + template<ClassType CLASS_TYPE>\n\ + struct BaseTemplateClass {\n\ + inline ClassType getClassType() const { CLASS_TYPE; }\n\ + };\n\ + typedef BaseTemplateClass<TypeOne> TypeOneClass;\n\ + }\n\ + "; + + const char xmlCode[] = "\n\ + <typesystem package='Package'>\n\ + <namespace-type name='NSpace'>\n\ + <enum-type name='ClassType'/>\n\ + <object-type name='BaseTemplateClass' generate='no'/>\n\ + <object-type name='TypeOneClass'/>\n\ + </namespace-type>\n\ + </typesystem>\n\ + "; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 3); + + const AbstractMetaClass* base = AbstractMetaClass::findClass(classes, QLatin1String("BaseTemplateClass")); + QVERIFY(base); + const AbstractMetaClass* one = AbstractMetaClass::findClass(classes, QLatin1String("TypeOneClass")); + QVERIFY(one); + QCOMPARE(one->templateBaseClass(), base); + QCOMPARE(one->functions().count(), base->functions().count()); + QVERIFY(one->isTypeDef()); + const ComplexTypeEntry* oneType = one->typeEntry(); + const ComplexTypeEntry* baseType = base->typeEntry(); + QCOMPARE(oneType->baseContainerType(), baseType); + QCOMPARE(one->baseClassNames(), QStringList(QLatin1String("BaseTemplateClass<TypeOne>"))); + + QVERIFY(one->hasTemplateBaseClassInstantiations()); + AbstractMetaTypeList instantiations = one->templateBaseClassInstantiations(); + QCOMPARE(instantiations.count(), 1); + const AbstractMetaType* inst = instantiations.first(); + QVERIFY(inst); + QVERIFY(!inst->isEnum()); + QVERIFY(!inst->typeEntry()->isEnum()); + QVERIFY(inst->typeEntry()->isEnumValue()); + QCOMPARE(inst->cppSignature(), QLatin1String("NSpace::TypeOne")); +} + +void TestTemplates::testContainerTypeIncompleteArgument() +{ + const char* cppCode ="\n\ + template<typename T>\n\ + class Vector {\n\ + void method(const Vector& vector);\n\ + Vector otherMethod();\n\ + };\n\ + template <typename T>\n\ + void Vector<T>::method(const Vector<T>& vector) {}\n\ + template <typename T>\n\ + Vector<T> Vector<T>::otherMethod() { return Vector<T>(); }\n\ + typedef Vector<int> IntVector;\n\ + "; + const char* xmlCode = "\n\ + <typesystem package='Foo'>\n\ + <primitive-type name='int'/>\n\ + <container-type name='Vector' type='vector'/>\n\ + <value-type name='IntVector'/>\n\ + </typesystem>"; + + QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true)); + QVERIFY(!builder.isNull()); + AbstractMetaClassList classes = builder->classes(); + QCOMPARE(classes.count(), 1); + + AbstractMetaClass* vector = AbstractMetaClass::findClass(classes, QLatin1String("IntVector")); + QVERIFY(vector); + QVERIFY(vector->typeEntry()->baseContainerType()); + QCOMPARE(reinterpret_cast<const ContainerTypeEntry*>(vector->typeEntry()->baseContainerType())->type(), ContainerTypeEntry::VectorContainer); + QCOMPARE(vector->functions().count(), 4); + + const AbstractMetaFunction* method = vector->findFunction(QLatin1String("method")); + QVERIFY(method); + QCOMPARE(method->signature(), QLatin1String("method(const Vector<int > & vector)")); + + const AbstractMetaFunction* otherMethod = vector->findFunction(QLatin1String("otherMethod")); + QVERIFY(otherMethod); + QCOMPARE(otherMethod->signature(), QLatin1String("otherMethod()")); + QVERIFY(otherMethod->type()); + QCOMPARE(otherMethod->type()->cppSignature(), QLatin1String("Vector<int >")); +} + +QTEST_APPLESS_MAIN(TestTemplates) |