aboutsummaryrefslogtreecommitdiffstats
path: root/sources/shiboken6/ApiExtractor/tests
diff options
context:
space:
mode:
Diffstat (limited to 'sources/shiboken6/ApiExtractor/tests')
-rw-r--r--sources/shiboken6/ApiExtractor/tests/CMakeLists.txt66
-rw-r--r--sources/shiboken6/ApiExtractor/tests/a.xml14
-rw-r--r--sources/shiboken6/ApiExtractor/tests/injectedcode.txt5
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp778
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h38
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testabstractmetatype.cpp229
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testabstractmetatype.h24
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp522
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testaddfunction.h31
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testarrayargument.cpp155
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testarrayargument.h18
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp164
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testcodeinjection.h23
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testcodeinjection.qrc6
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testcontainer.cpp84
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testcontainer.h16
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testconversionoperator.cpp178
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testconversionoperator.h19
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp240
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testconversionruletag.h19
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testctorinformation.cpp57
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testctorinformation.h19
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testdroptypeentries.cpp228
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testdroptypeentries.h22
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testdtorinformation.cpp158
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testdtorinformation.h22
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testenum.cpp577
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testenum.h25
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testextrainclude.cpp62
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testextrainclude.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testfunctiontag.cpp79
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testfunctiontag.h18
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testimplicitconversions.cpp142
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testimplicitconversions.h21
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testinserttemplate.cpp63
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testinserttemplate.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp117
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.qrc5
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmodifyfunction.cpp480
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmodifyfunction.h26
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.cpp50
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.h18
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testnamespace.cpp77
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testnamespace.h19
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testnestedtypes.cpp115
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testnestedtypes.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.cpp90
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.cpp40
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.h16
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testrefcounttag.cpp84
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testrefcounttag.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testreferencetopointer.cpp37
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testreferencetopointer.h16
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testremovefield.cpp76
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testremovefield.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testremoveimplconv.cpp48
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testremoveimplconv.h16
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.cpp98
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.h16
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp281
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testresolvetype.h21
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp129
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testreverseoperators.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testtemplates.cpp628
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testtemplates.h30
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testtoposort.cpp61
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testtoposort.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testtyperevision.cpp92
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testtyperevision.h19
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testutil.h65
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.cpp39
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.h16
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testvoidarg.cpp67
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testvoidarg.h17
-rw-r--r--sources/shiboken6/ApiExtractor/tests/utf8code.txt1
77 files changed, 7185 insertions, 0 deletions
diff --git a/sources/shiboken6/ApiExtractor/tests/CMakeLists.txt b/sources/shiboken6/ApiExtractor/tests/CMakeLists.txt
new file mode 100644
index 000000000..76c014fbb
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/CMakeLists.txt
@@ -0,0 +1,66 @@
+# Copyright (C) 2023 The Qt Company Ltd.
+# SPDX-License-Identifier: BSD-3-Clause
+
+set(CMAKE_AUTORCC ON)
+
+macro(declare_test testname)
+ # gone: qt4_automoc("${testname}.cpp")
+ set(SOURCES "${testname}.cpp")
+ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${testname}.h")
+ list(APPEND SOURCES "${testname}.h")
+ endif ()
+ if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${testname}.qrc")
+ list(APPEND SOURCES "${testname}.qrc")
+ endif ()
+
+ add_executable(${testname} ${SOURCES})
+ target_include_directories(${testname} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
+ ${CMAKE_CURRENT_BINARY_DIR}
+ ${apiextractor_SOURCE_DIR}
+ )
+ target_link_libraries(${testname} PRIVATE apiextractor Qt::Test)
+ add_test(${testname} ${testname})
+ if (INSTALL_TESTS)
+ install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/${testname}
+ DESTINATION share/apiextractor${apiextractor_SUFFIX}/tests)
+ endif()
+endmacro(declare_test testname)
+
+declare_test(testabstractmetaclass)
+declare_test(testabstractmetatype)
+declare_test(testaddfunction)
+declare_test(testarrayargument)
+declare_test(testcodeinjection)
+declare_test(testcontainer)
+declare_test(testconversionoperator)
+declare_test(testconversionruletag)
+declare_test(testctorinformation)
+declare_test(testdroptypeentries)
+declare_test(testdtorinformation)
+declare_test(testenum)
+declare_test(testextrainclude)
+declare_test(testfunctiontag)
+declare_test(testimplicitconversions)
+declare_test(testinserttemplate)
+declare_test(testmodifyfunction)
+declare_test(testmultipleinheritance)
+declare_test(testnamespace)
+declare_test(testnestedtypes)
+declare_test(testnumericaltypedef)
+declare_test(testprimitivetypetag)
+declare_test(testrefcounttag)
+declare_test(testreferencetopointer)
+declare_test(testremovefield)
+declare_test(testremoveimplconv)
+declare_test(testremoveoperatormethod)
+declare_test(testresolvetype)
+declare_test(testreverseoperators)
+declare_test(testtemplates)
+declare_test(testtoposort)
+declare_test(testvaluetypedefaultctortag)
+declare_test(testvoidarg)
+declare_test(testtyperevision)
+if (NOT DISABLE_DOCSTRINGS)
+ declare_test(testmodifydocumentation)
+endif()
+
diff --git a/sources/shiboken6/ApiExtractor/tests/a.xml b/sources/shiboken6/ApiExtractor/tests/a.xml
new file mode 100644
index 000000000..3c09d3800
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/a.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" ?>
+<!-- Sample for testModifyDocumentation -->
+<WebXML>
+ <document>
+ <class name="A">
+ <description>oi
+ <brief>Brief description</brief>
+ <para>Paragraph number 1</para>
+ <para>Paragraph number 2</para>
+ <para>Paragraph number 3</para>
+ </description>
+ </class>
+ </document>
+</WebXML>
diff --git a/sources/shiboken6/ApiExtractor/tests/injectedcode.txt b/sources/shiboken6/ApiExtractor/tests/injectedcode.txt
new file mode 100644
index 000000000..872898810
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/injectedcode.txt
@@ -0,0 +1,5 @@
+// Bla
+// @snippet label
+code line
+// @snippet label
+// Bla
diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp
new file mode 100644
index 000000000..4b5da0c3a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.cpp
@@ -0,0 +1,778 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testabstractmetaclass.h"
+#include "abstractmetabuilder.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <usingmember.h>
+#include <typesystem.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestAbstractMetaClass::testClassName()
+{
+ const char cppCode[] = "class ClassName {};";
+ const char xmlCode[] = R"(<typesystem package="Foo">
+ <value-type name="ClassName"/>
+</typesystem>)";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ QCOMPARE(classes[0]->name(), u"ClassName");
+}
+
+void TestAbstractMetaClass::testClassNameUnderNamespace()
+{
+ const char cppCode[] = "namespace Namespace { class ClassName {}; }\n";
+ const char xmlCode[] = R"XML(
+ <typesystem package="Foo">
+ <namespace-type name="Namespace">
+ <value-type name="ClassName"/>
+ </namespace-type>
+ </typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2); // 1 namespace + 1 class
+ if (classes.constFirst()->name() != u"ClassName")
+ qSwap(classes[0], classes[1]);
+
+ QCOMPARE(classes[0]->name(), u"ClassName");
+ QCOMPARE(classes[0]->qualifiedCppName(), u"Namespace::ClassName");
+ QCOMPARE(classes[1]->name(), u"Namespace");
+ QVERIFY(classes[1]->isNamespace());
+
+ // Check ctors info
+ QVERIFY(classes[0]->hasConstructors());
+ QCOMPARE(classes[0]->functions().size(), 2); // default ctor + copy ctor
+
+ auto ctors = classes[0]->queryFunctions(FunctionQueryOption::AnyConstructor);
+ QCOMPARE(ctors.size(), 2);
+ if (ctors.constFirst()->minimalSignature() != u"ClassName()")
+ qSwap(ctors[0], ctors[1]);
+
+ QCOMPARE(ctors[0]->arguments().size(), 0);
+ QCOMPARE(ctors[0]->minimalSignature(), u"ClassName()");
+ QCOMPARE(ctors[1]->arguments().size(), 1);
+ QCOMPARE(ctors[1]->minimalSignature(), u"ClassName(Namespace::ClassName)");
+
+ QVERIFY(!classes[0]->hasPrivateDestructor());
+ QVERIFY(classes[0]->isCopyConstructible()); // implicit default copy ctor
+
+ // This method is buggy and nobody wants to fix it or needs it fixed :-/
+ // QVERIFY(classes[0]->hasNonPrivateConstructor());
+}
+
+static AbstractMetaFunctionCList virtualFunctions(const AbstractMetaClassCPtr &c)
+{
+ AbstractMetaFunctionCList result;
+ const auto &functions = c->functions();
+ for (const auto &f : functions) {
+ if (f->isVirtual())
+ result.append(f);
+ }
+ return result;
+}
+
+void TestAbstractMetaClass::testVirtualMethods()
+{
+ const char cppCode[] =R"CPP(
+class A {
+public:
+ virtual int pureVirtual() const = 0;
+};
+class B : public A {};
+class C : public B {
+public:
+ int pureVirtual() const override { return 0; }
+};
+class F final : public C {
+public:
+ int pureVirtual() const final { return 1; }
+};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package="Foo">
+ <primitive-type name='int'/>
+ <object-type name='A'/>
+ <object-type name='B'/>
+ <object-type name='C'/>
+ <object-type name='F'/>
+</typesystem>
+)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 4);
+ const auto a = AbstractMetaClass::findClass(classes, "A");
+ const auto b = AbstractMetaClass::findClass(classes, "B");
+ const auto c = AbstractMetaClass::findClass(classes, "C");
+ const auto f = AbstractMetaClass::findClass(classes, "F");
+ QVERIFY(f);
+
+ QCOMPARE(a->baseClass(), nullptr);
+ QCOMPARE(b->baseClass(), a);
+ QCOMPARE(c->baseClass(), b);
+ QCOMPARE(f->baseClass(), c);
+
+ QCOMPARE(a->functions().size(), 2); // default ctor + the pure virtual method
+ QCOMPARE(b->functions().size(), 2);
+ QCOMPARE(c->functions().size(), 2);
+ QCOMPARE(f->functions().size(), 2);
+ QVERIFY(f->attributes().testFlag(AbstractMetaClass::FinalCppClass));
+
+ // implementing class, ownclass, declaringclass
+ const auto ctorA = a->queryFunctions(FunctionQueryOption::Constructors).constFirst();
+ const auto ctorB = b->queryFunctions(FunctionQueryOption::Constructors).constFirst();
+ const auto ctorC = c->queryFunctions(FunctionQueryOption::Constructors).constFirst();
+ QVERIFY(ctorA->isConstructor());
+ QVERIFY(!ctorA->isVirtual());
+ QVERIFY(ctorB->isConstructor());
+ QVERIFY(!ctorB->isVirtual());
+ QVERIFY(ctorC->isConstructor());
+ QVERIFY(!ctorC->isVirtual());
+ QCOMPARE(ctorA->implementingClass(), a);
+ QCOMPARE(ctorA->ownerClass(), a);
+ QCOMPARE(ctorA->declaringClass(), a);
+
+ const auto virtualFunctionsA = virtualFunctions(a);
+ const auto virtualFunctionsB = virtualFunctions(b);
+ const auto virtualFunctionsC = virtualFunctions(c);
+ const auto virtualFunctionsF = virtualFunctions(f);
+ QCOMPARE(virtualFunctionsA.size(), 1); // Add a pureVirtualMethods method !?
+ QCOMPARE(virtualFunctionsB.size(), 1);
+ QCOMPARE(virtualFunctionsC.size(), 1);
+ QCOMPARE(virtualFunctionsF.size(), 1);
+
+ const auto funcA = virtualFunctionsA.constFirst();
+ const auto funcB = virtualFunctionsB.constFirst();
+ const auto funcC = virtualFunctionsC.constFirst();
+ const auto funcF = virtualFunctionsF.constFirst();
+
+ QCOMPARE(funcA->ownerClass(), a);
+ QVERIFY(funcC->isVirtual());
+ QCOMPARE(funcB->ownerClass(), b);
+ QCOMPARE(funcC->ownerClass(), c);
+ QVERIFY(funcC->cppAttributes().testFlag(FunctionAttribute::Override));
+ QVERIFY(funcF->cppAttributes().testFlag(FunctionAttribute::Final));
+
+ QCOMPARE(funcA->declaringClass(), a);
+ QCOMPARE(funcB->declaringClass(), a);
+ QCOMPARE(funcC->declaringClass(), a);
+
+ // The next two tests could return null, because it makes more sense.
+ // But we have too many code written relying on this behaviour where
+ // implementingClass is equals to declaringClass on pure virtual functions
+ QCOMPARE(funcA->implementingClass(), a);
+ QCOMPARE(funcB->implementingClass(), a);
+ QCOMPARE(funcC->implementingClass(), c);
+}
+
+void TestAbstractMetaClass::testVirtualBase()
+{
+ const char cppCode[] =R"CPP(
+class Base {
+public:
+ virtual ~Base() = default;
+};
+class Derived : public Base {};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package="Foo">
+ <object-type name='Base'/>
+ <object-type name='Derived'/>
+</typesystem>
+)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto base = AbstractMetaClass::findClass(classes, "Base");
+ QVERIFY(base);
+ QVERIFY(base->isPolymorphic());
+ const auto derived = AbstractMetaClass::findClass(classes, "Derived");
+ QVERIFY(derived);
+ QVERIFY(derived->isPolymorphic());
+}
+
+void TestAbstractMetaClass::testDefaultValues()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ class B {};\n\
+ void method(B b = B());\n\
+ };\n";
+ const char xmlCode[] = R"XML(
+ <typesystem package="Foo">
+ <value-type name='A'>
+ <value-type name='B'/>
+ </value-type>
+ </typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto candidates = classA->queryFunctionsByName(u"method"_s);
+ QCOMPARE(candidates.size(), 1);
+ const auto &method = candidates.constFirst();
+ const AbstractMetaArgument &arg = method->arguments().constFirst();
+ QCOMPARE(arg.defaultValueExpression(), arg.originalDefaultValueExpression());
+}
+
+void TestAbstractMetaClass::testModifiedDefaultValues()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ class B {};\n\
+ void method(B b = B());\n\
+ };\n";
+ const char xmlCode[] = R"XML(
+ <typesystem package="Foo">
+ <value-type name='A'>
+ <modify-function signature='method(A::B)'>
+ <modify-argument index='1'>
+ <replace-default-expression with='Hello'/>
+ </modify-argument>
+ </modify-function>
+ <value-type name='B'/>
+ </value-type>
+ </typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto methodMatches = classA->queryFunctionsByName(u"method"_s);
+ QCOMPARE(methodMatches.size(), 1);
+ const auto method = methodMatches.constFirst();
+ const AbstractMetaArgument &arg = method->arguments().constFirst();
+ QCOMPARE(arg.defaultValueExpression(), u"Hello");
+ QCOMPARE(arg.originalDefaultValueExpression(), u"A::B()");
+}
+
+void TestAbstractMetaClass::testInnerClassOfAPolymorphicOne()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ class B {};\n\
+ virtual void method();\n\
+ };\n";
+ const char xmlCode[] = R"XML(
+ <typesystem package="Foo">
+ <object-type name='A'>
+ <value-type name='B'/>
+ </object-type>
+ </typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QVERIFY(classA->isPolymorphic());
+ const auto classB = AbstractMetaClass::findClass(classes, "A::B");
+ QVERIFY(classB);
+ QVERIFY(!classB->isPolymorphic());
+}
+
+void TestAbstractMetaClass::testForwardDeclaredInnerClass()
+{
+ const char cppCode[] ="\
+ class A {\n\
+ class B;\n\
+ };\n\
+ class A::B {\n\
+ public:\n\
+ void foo();\n\
+ };\n";
+ const char xmlCode[] = R"XML(
+ <typesystem package="Foo">
+ <value-type name='A'>
+ <value-type name='B'/>
+ </value-type>
+ </typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto classB = AbstractMetaClass::findClass(classes, "A::B");
+ QVERIFY(classB);
+ const auto fooF = classB->findFunction("foo");
+ QVERIFY(fooF);
+}
+
+void TestAbstractMetaClass::testSpecialFunctions()
+{
+ const char cppCode[] ="\
+ struct A {\n\
+ A();\n\
+ A(const A&);\n\
+ A &operator=(const A&);\n\
+ };\n\
+ struct B {\n\
+ B();\n\
+ B(const B &);\n\
+ B &operator=(B);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ auto ctors = classA->queryFunctions(FunctionQueryOption::AnyConstructor);
+ QCOMPARE(ctors.size(), 2);
+ QCOMPARE(ctors.constFirst()->functionType(), AbstractMetaFunction::ConstructorFunction);
+ QCOMPARE(ctors.at(1)->functionType(), AbstractMetaFunction::CopyConstructorFunction);
+ auto assigmentOps = classA->queryFunctionsByName(u"operator="_s);
+ QCOMPARE(assigmentOps.size(), 1);
+ QCOMPARE(assigmentOps.constFirst()->functionType(),
+ AbstractMetaFunction::AssignmentOperatorFunction);
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ ctors = classB->queryFunctions(FunctionQueryOption::AnyConstructor);
+ QCOMPARE(ctors.size(), 2);
+ QCOMPARE(ctors.constFirst()->functionType(), AbstractMetaFunction::ConstructorFunction);
+ QCOMPARE(ctors.at(1)->functionType(), AbstractMetaFunction::CopyConstructorFunction);
+ assigmentOps = classA->queryFunctionsByName(u"operator="_s);
+ QCOMPARE(assigmentOps.size(), 1);
+ QCOMPARE(assigmentOps.constFirst()->functionType(), AbstractMetaFunction::AssignmentOperatorFunction);
+}
+
+void TestAbstractMetaClass::testClassDefaultConstructors()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ \n\
+ struct B {\n\
+ B();\n\
+ private: \n\
+ B(const B&);\n\
+ };\n\
+ \n\
+ struct C {\n\
+ C(const C&);\n\
+ };\n\
+ \n\
+ struct D {\n\
+ private: \n\
+ D(const D&);\n\
+ };\n\
+ \n\
+ struct E {\n\
+ private: \n\
+ ~E();\n\
+ };\n\
+ \n\
+ struct F {\n\
+ F(int, int);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'/>\n\
+ <object-type name='B'/>\n\
+ <value-type name='C'/>\n\
+ <object-type name='D'/>\n\
+ <object-type name='E'/>\n\
+ <value-type name='F'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 6);
+
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().size(), 2);
+
+ auto ctors = classA->queryFunctions(FunctionQueryOption::AnyConstructor);
+ QCOMPARE(ctors.size(), 2);
+ if (ctors.constFirst()->minimalSignature() != u"A()")
+ qSwap(ctors[0], ctors[1]);
+
+ QCOMPARE(ctors[0]->arguments().size(), 0);
+ QCOMPARE(ctors[0]->minimalSignature(), u"A()");
+ QCOMPARE(ctors[1]->arguments().size(), 1);
+ QCOMPARE(ctors[1]->minimalSignature(), u"A(A)");
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ QCOMPARE(classB->functions().size(), 2);
+ QCOMPARE(classB->functions().constFirst()->minimalSignature(), u"B()");
+
+ const auto classC = AbstractMetaClass::findClass(classes, "C");
+ QVERIFY(classC);
+ QCOMPARE(classC->functions().size(), 1);
+ QCOMPARE(classC->functions().constFirst()->minimalSignature(), u"C(C)");
+
+ const auto classD = AbstractMetaClass::findClass(classes, "D");
+ QVERIFY(classD);
+ QCOMPARE(classD->functions().size(), 1);
+ QCOMPARE(classD->functions().constFirst()->minimalSignature(), u"D(D)");
+ QVERIFY(classD->functions().constFirst()->isPrivate());
+
+ const auto classE = AbstractMetaClass::findClass(classes, "E");
+ QVERIFY(classE);
+ QVERIFY(classE->hasPrivateDestructor());
+ QCOMPARE(classE->functions().size(), 0);
+
+ const auto classF = AbstractMetaClass::findClass(classes, "F");
+ QVERIFY(classF);
+
+ ctors = classF->queryFunctions(FunctionQueryOption::AnyConstructor);
+ QCOMPARE(ctors.size(), 2);
+ if (ctors.constFirst()->minimalSignature() != u"F(int,int)")
+ qSwap(ctors[0], ctors[1]);
+
+ QCOMPARE(ctors[0]->arguments().size(), 2);
+ QCOMPARE(ctors[0]->minimalSignature(), u"F(int,int)");
+ QCOMPARE(ctors[1]->arguments().size(), 1);
+ QCOMPARE(ctors[1]->minimalSignature(), u"F(F)");
+}
+
+void TestAbstractMetaClass::testClassInheritedDefaultConstructors()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ A();\n\
+ private: \n\
+ A(const A&);\n\
+ };\n\
+ struct B : public A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+
+ auto ctors = classA->queryFunctions(FunctionQueryOption::AnyConstructor);
+ QCOMPARE(ctors.size(), 2);
+ if (ctors.constFirst()->minimalSignature() != u"A()")
+ qSwap(ctors[0], ctors[1]);
+
+ QCOMPARE(ctors[0]->arguments().size(), 0);
+ QCOMPARE(ctors[0]->minimalSignature(), u"A()");
+ QCOMPARE(ctors[1]->arguments().size(), 1);
+ QCOMPARE(ctors[1]->minimalSignature(), u"A(A)");
+ QVERIFY(ctors[1]->isPrivate());
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+
+ ctors = classB->queryFunctions(FunctionQueryOption::Constructors);
+ QCOMPARE(ctors.size(), 1);
+ QCOMPARE(ctors.constFirst()->arguments().size(), 0);
+ QCOMPARE(ctors.constFirst()->minimalSignature(), u"B()");
+}
+
+void TestAbstractMetaClass::testAbstractClassDefaultConstructors()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ virtual void method() = 0;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+
+ const auto ctors = classA->queryFunctions(FunctionQueryOption::Constructors);
+ QCOMPARE(ctors.size(), 1);
+ QCOMPARE(ctors.constFirst()->arguments().size(), 0);
+ QCOMPARE(ctors.constFirst()->minimalSignature(), u"A()");
+}
+
+void TestAbstractMetaClass::testObjectTypesMustNotHaveCopyConstructors()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+
+ const auto ctors = classA->queryFunctions(FunctionQueryOption::Constructors);
+ QCOMPARE(ctors.size(), 1);
+ QCOMPARE(ctors.constFirst()->arguments().size(), 0);
+ QCOMPARE(ctors.constFirst()->minimalSignature(), u"A()");
+}
+
+void TestAbstractMetaClass::testIsPolymorphic()
+{
+ const char cppCode[] = "\
+ class A\n\
+ {\n\
+ public:\n\
+ A();\n\
+ inline bool abc() const { return false; }\n\
+ };\n\
+ \n\
+ class B : public A\n\
+ {\n\
+ public:\n\
+ B();\n\
+ inline bool abc() const { return false; }\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='bool'/>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto b = AbstractMetaClass::findClass(classes, "A");
+
+ QVERIFY(!b->isPolymorphic());
+ const auto a = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(!a->isPolymorphic());
+}
+
+void TestAbstractMetaClass::testClassTypedefedBaseClass()
+{
+ const char cppCode[] =R"CPP(
+class Base {
+};
+
+using BaseAlias1 = Base;
+using BaseAlias2 = BaseAlias1;
+
+class Derived : public BaseAlias2 {
+};
+)CPP";
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <object-type name='Base'/>
+ <object-type name='Derived'/>
+</typesystem>
+)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto base = AbstractMetaClass::findClass(classes, "Base");
+ QVERIFY(base);
+ const auto derived = AbstractMetaClass::findClass(classes, "Derived");
+ QVERIFY(derived);
+ QCOMPARE(derived->baseClasses().value(0), base);
+}
+
+void TestAbstractMetaClass::testFreeOperators_data()
+{
+ QTest::addColumn<QByteArray>("code");
+
+ const QByteArray classHeader(R"CPP(
+class Value
+{
+public:
+ Value(int v) : m_value(v) {}
+ int value() const { return m_value; }
+)CPP");
+
+ const QByteArray classFooter(R"CPP(
+private:
+ int m_value;
+};
+)CPP");
+
+ const QByteArray multOperatorSignature("Value operator*(const Value &v1, const Value &v2)");
+ const QByteArray multOperatorBody("{ return Value(v1.value() * v2.value()); }");
+ const QByteArray multOperator = multOperatorSignature + '\n' + multOperatorBody;
+
+ QTest::newRow("free")
+ << (classHeader + classFooter + "\ninline " + multOperator);
+ QTest::newRow("free-friend-declared")
+ << (classHeader + "\n friend " + multOperatorSignature + ";\n" + classFooter
+ + "\ninline " + multOperator);
+ QTest::newRow("hidden friend")
+ << (classHeader + " friend inline " + multOperator + classFooter);
+};
+
+void TestAbstractMetaClass::testFreeOperators()
+{
+ QFETCH(QByteArray, code);
+ const char xmlCode[] = R"XML(
+ <typesystem package="Foo">
+ <primitive-type name="int"/>
+ <value-type name="Value"/>
+ </typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(code.constData(), xmlCode));
+ QVERIFY(builder);
+ const auto classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ QVERIFY(classes.constFirst()->hasArithmeticOperatorOverload());
+ FunctionQueryOptions opts(FunctionQueryOption::OperatorOverloads);
+ QCOMPARE(classes.constFirst()->queryFunctions(opts).size(), 1);
+}
+
+void TestAbstractMetaClass::testUsingMembers()
+{
+ const char cppCode[] =R"CPP(
+class Base {
+public:
+ explicit Base(int);
+
+protected:
+ void member();
+};
+
+class Derived : public Base {
+public:
+ using Base::Base;
+ using Base::member;
+};
+)CPP";
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='Derived'/>
+</typesystem>
+)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto base = AbstractMetaClass::findClass(classes, "Base");
+ QVERIFY(base);
+ const auto derived = AbstractMetaClass::findClass(classes, "Derived");
+ QVERIFY(derived);
+ const auto usingMembers = derived->usingMembers();
+ QCOMPARE(usingMembers.size(), 2);
+ for (const auto &um : usingMembers) {
+ QCOMPARE(um.access, Access::Public);
+ QCOMPARE(um.baseClass, base);
+ QVERIFY(um.memberName == u"Base" || um.memberName == u"member");
+ }
+}
+
+void TestAbstractMetaClass::testUsingTemplateMembers_data()
+{
+ const QByteArray cppCode(R"CPP(
+struct Value {
+ int value = 0;
+};
+
+template <class T> class List {
+public:
+ List();
+ void append(const T &t);
+};
+
+class ValueList : public List<Value> {
+public:
+ void append(const Value &v1, const Value &v2);
+)CPP");
+
+ QTest::addColumn<QByteArray>("code");
+ QTest::newRow("simple")
+ << (cppCode + "using List::append;\n};\n");
+ QTest::newRow("with-template-params")
+ << (cppCode + "using List<Value>::append;\n};\n");
+}
+
+void TestAbstractMetaClass::testUsingTemplateMembers()
+{
+ QFETCH(QByteArray, code);
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <value-type name='Value'/>
+ <container-type name='List' type='list'/>
+ <value-type name='ValueList'/>
+</typesystem>
+)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(code.constData(), xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto valueList = AbstractMetaClass::findClass(classes, "ValueList");
+ QVERIFY(valueList);
+ auto list = valueList->templateBaseClass();
+ QVERIFY(valueList->isUsingMember(list, u"append"_s, Access::Public));
+ QCOMPARE(valueList->queryFunctionsByName(u"append"_s).size(), 2);
+}
+
+void TestAbstractMetaClass::testGenerateFunctions()
+{
+ const char cppCode[] = R"CPP(
+class TestClass {
+public:
+ TestClass();
+
+ void alpha(int);
+ void beta(int);
+ void beta(double);
+ void gamma(int);
+};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <object-type name='TestClass' generate-functions='beta(double);gamma'/>
+</typesystem>
+)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto tc = AbstractMetaClass::findClass(classes, "TestClass");
+ // Verify that the constructor and 2 functions are generated.
+ const auto &functions = tc->functions();
+ QCOMPARE(functions.size(), 5);
+ const auto generateCount =
+ std::count_if(functions.cbegin(), functions.cend(),
+ [](const auto &af) { return af->generateBinding(); });
+ QCOMPARE(generateCount, 3);
+}
+
+QTEST_APPLESS_MAIN(TestAbstractMetaClass)
diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h
new file mode 100644
index 000000000..a6bd2bf06
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetaclass.h
@@ -0,0 +1,38 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTABSTRACTMETACLASS_H
+#define TESTABSTRACTMETACLASS_H
+
+#include <QtCore/QObject>
+
+class AbstractMetaBuilder;
+
+class TestAbstractMetaClass : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testClassName();
+ void testClassNameUnderNamespace();
+ void testVirtualMethods();
+ void testVirtualBase();
+ void testDefaultValues();
+ void testModifiedDefaultValues();
+ void testInnerClassOfAPolymorphicOne();
+ void testForwardDeclaredInnerClass();
+ void testSpecialFunctions();
+ void testClassDefaultConstructors();
+ void testClassInheritedDefaultConstructors();
+ void testAbstractClassDefaultConstructors();
+ void testObjectTypesMustNotHaveCopyConstructors();
+ void testIsPolymorphic();
+ void testClassTypedefedBaseClass();
+ void testFreeOperators_data();
+ void testFreeOperators();
+ void testUsingMembers();
+ void testUsingTemplateMembers_data();
+ void testUsingTemplateMembers();
+ void testGenerateFunctions();
+};
+
+#endif // TESTABSTRACTMETACLASS_H
diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.cpp b/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.cpp
new file mode 100644
index 000000000..2c320c874
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.cpp
@@ -0,0 +1,229 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testabstractmetatype.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <typesystem.h>
+#include <parser/codemodel.h>
+#include <typeparser.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestAbstractMetaType::parsing_data()
+{
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<QString>("output");
+ QTest::newRow("primitive")
+ << QString::fromLatin1("int") << QString::fromLatin1("int");
+ QTest::newRow("ref")
+ << QString::fromLatin1("int &") << QString::fromLatin1("int&");
+ QTest::newRow("pointer")
+ << QString::fromLatin1("int **") << QString::fromLatin1("int**");
+ QTest::newRow("const ref")
+ << QString::fromLatin1("const int &") << QString::fromLatin1("const int&");
+ QTest::newRow("const pointer")
+ << QString::fromLatin1("const int **") << QString::fromLatin1("const int**");
+ QTest::newRow("const pointer const")
+ << QString::fromLatin1("const int *const*") << QString::fromLatin1("const int*const*");
+}
+
+void TestAbstractMetaType::parsing()
+{
+ QFETCH(QString, input);
+ QFETCH(QString, output);
+ QString errorMessage;
+ const TypeInfo ti = TypeParser::parse(input, &errorMessage);
+ QVERIFY2(errorMessage.isEmpty(), qPrintable(errorMessage));
+ const QString actual = ti.toString();
+ QCOMPARE(actual, output);
+}
+
+void TestAbstractMetaType::testConstCharPtrType()
+{
+ const char cppCode[] = "const char* justAtest();\n";
+ const char xmlCode[] = "<typesystem package=\"Foo\">\n\
+ <primitive-type name='char'/>\n\
+ <function signature='justAtest()' />\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ QCOMPARE(builder->globalFunctions().size(), 1);
+ const auto func = builder->globalFunctions().constFirst();
+ AbstractMetaType rtype = func->type();
+ // Test properties of const char*
+ QVERIFY(!rtype.isVoid());
+ QCOMPARE(rtype.package(), u"Foo");
+ QCOMPARE(rtype.name(), u"char");
+ QVERIFY(rtype.isConstant());
+ QVERIFY(!rtype.isArray());
+ QVERIFY(!rtype.isContainer());
+ QVERIFY(!rtype.isObject());
+ QVERIFY(!rtype.isPrimitive()); // const char* differs from char, so it's not considered a primitive type by apiextractor
+ QVERIFY(rtype.isNativePointer());
+ QCOMPARE(rtype.referenceType(), NoReference);
+ QVERIFY(!rtype.isValue());
+ QVERIFY(!rtype.isValuePointer());
+}
+
+void TestAbstractMetaType::testApiVersionSupported()
+{
+ const char cppCode[] = "class foo {}; class foo2 {};\n\
+ void justAtest(); void justAtest3();\n";
+ const char xmlCode[] = "<typesystem package='Foo'>\n\
+ <value-type name='foo' since='0.1'/>\n\
+ <value-type name='foo2' since='1.0'/>\n\
+ <value-type name='foo3' since='1.1'/>\n\
+ <function signature='justAtest()' since='0.1'/>\n\
+ <function signature='justAtest2()' since='1.1'/>\n\
+ <function signature='justAtest3()'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, u"1.0"_s));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+
+
+ QCOMPARE(builder->globalFunctions().size(), 2);
+}
+
+
+void TestAbstractMetaType::testApiVersionNotSupported()
+{
+ const char cppCode[] = "class object {};\n";
+ const char xmlCode[] = "<typesystem package='Foo'>\n\
+ <value-type name='object' since='0.1'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, u"0.1"_s));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+}
+
+void TestAbstractMetaType::testCharType()
+{
+ const char cppCode[] = "char justAtest(); class A {};\n";
+ const char xmlCode[] = "<typesystem package=\"Foo\">\n\
+ <primitive-type name='char'/>\n\
+ <value-type name='A'/>\n\
+ <function signature='justAtest()'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ QCOMPARE(classes.constFirst()->package(), u"Foo");
+
+ const auto functions = builder->globalFunctions();
+ QCOMPARE(functions.size(), 1);
+ const auto func = functions.constFirst();
+ AbstractMetaType rtype = func->type();
+ // Test properties of const char*
+ QVERIFY(!rtype.isVoid());
+ QCOMPARE(rtype.package(), u"Foo");
+ QCOMPARE(rtype.name(), u"char");
+ QVERIFY(!rtype.isConstant());
+ QVERIFY(!rtype.isArray());
+ QVERIFY(!rtype.isContainer());
+ QVERIFY(!rtype.isObject());
+ QVERIFY(rtype.isPrimitive());
+ QVERIFY(!rtype.isNativePointer());
+ QCOMPARE(rtype.referenceType(), NoReference);
+ QVERIFY(!rtype.isValue());
+ QVERIFY(!rtype.isValuePointer());
+}
+
+void TestAbstractMetaType::testTypedef()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ void someMethod();\n\
+ };\n\
+ typedef A B;\n\
+ typedef B C;\n";
+ const char xmlCode[] = "<typesystem package=\"Foo\">\n\
+ <value-type name='C' />\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto c = AbstractMetaClass::findClass(classes, "C");
+ QVERIFY(c);
+ QVERIFY(c->isTypeDef());
+}
+
+void TestAbstractMetaType::testTypedefWithTemplates()
+{
+ const char cppCode[] = "\
+ template<typename T>\n\
+ class A {};\n\
+ \n\
+ class B {};\n\
+ typedef A<B> C;\n\
+ \n\
+ void func(C c);\n";
+ const char xmlCode[] = "<typesystem package=\"Foo\">\n\
+ <container-type name='A' type='list'/>\n\
+ <value-type name='B' />\n\
+ <function signature='func(A&lt;B&gt;)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto functions = builder->globalFunctions();
+ QCOMPARE(functions.size(), 1);
+ const auto function = functions.constFirst();
+ AbstractMetaArgumentList args = function->arguments();
+ QCOMPARE(args.size(), 1);
+ const AbstractMetaArgument &arg = args.constFirst();
+ AbstractMetaType metaType = arg.type();
+ QCOMPARE(metaType.cppSignature(), u"A<B>");
+}
+
+
+void TestAbstractMetaType::testObjectTypeUsedAsValue()
+{
+ const char cppCode[] = "\
+ class A {\n\
+ void method(A);\n\
+ };\n";
+ const char xmlCode[] = "<typesystem package='Foo'>\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto overloads = classA->queryFunctionsByName(u"method"_s);
+ QCOMPARE(overloads.size(), 1);
+ const auto method = overloads.constFirst();
+ QVERIFY(method);
+ AbstractMetaArgumentList args = method->arguments();
+ QCOMPARE(args.size(), 1);
+ const AbstractMetaArgument &arg = args.constFirst();
+ AbstractMetaType metaType = arg.type();
+ QCOMPARE(metaType.cppSignature(), u"A");
+ QVERIFY(metaType.isValue());
+ QVERIFY(metaType.typeEntry()->isObject());
+}
+
+QTEST_APPLESS_MAIN(TestAbstractMetaType)
diff --git a/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.h b/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.h
new file mode 100644
index 000000000..fdcf0c787
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testabstractmetatype.h
@@ -0,0 +1,24 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTABSTRACTMETATYPE_H
+#define TESTABSTRACTMETATYPE_H
+
+#include <QtCore/QObject>
+
+class TestAbstractMetaType : public QObject
+{
+ Q_OBJECT
+private slots:
+ void parsing_data();
+ void parsing();
+ void testConstCharPtrType();
+ void testCharType();
+ void testTypedef();
+ void testTypedefWithTemplates();
+ void testApiVersionSupported();
+ void testApiVersionNotSupported();
+ void testObjectTypeUsedAsValue();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp b/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp
new file mode 100644
index 000000000..a891e1e28
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp
@@ -0,0 +1,522 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testaddfunction.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <codesnip.h>
+#include <addedfunction.h>
+#include <addedfunction_p.h>
+#include <complextypeentry.h>
+#include <primitivetypeentry.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+static constexpr auto voidT = "void"_L1;
+
+void TestAddFunction::testParsingFuncNameAndConstness()
+{
+ // generic test...
+ static constexpr auto sig1 = "func(type1, const type2, const type3* const)"_L1;
+ QString errorMessage;
+ auto f1 = AddedFunction::createAddedFunction(sig1, voidT, &errorMessage);
+ QVERIFY2(f1, qPrintable(errorMessage));
+ QCOMPARE(f1->name(), u"func");
+ QCOMPARE(f1->arguments().size(), 3);
+ TypeInfo retval = f1->returnType();
+ QCOMPARE(retval.qualifiedName(), QStringList{voidT});
+ QCOMPARE(retval.indirections(), 0);
+ QCOMPARE(retval.isConstant(), false);
+ QCOMPARE(retval.referenceType(), NoReference);
+
+ // test with a ugly template as argument and other ugly stuff
+ static constexpr auto sig2 =
+ " _fu__nc_ ( type1, const type2, const Abc<int& , C<char*> * >"
+ " * *@my_name@, const type3* const ) const "_L1;
+ auto f2 = AddedFunction::createAddedFunction(sig2,
+ u"const Abc<int& , C<char*> * > * *"_s,
+ &errorMessage);
+ QVERIFY2(f2, qPrintable(errorMessage));
+ QCOMPARE(f2->name(), u"_fu__nc_");
+ const auto &args = f2->arguments();
+ QCOMPARE(args.size(), 4);
+ retval = f2->returnType();
+ QCOMPARE(retval.qualifiedName(), QStringList{u"Abc"_s});
+ QCOMPARE(retval.instantiations().size(), 2);
+ QCOMPARE(retval.toString(), u"const Abc<int&, C<char*>*>**");
+ QCOMPARE(retval.indirections(), 2);
+ QCOMPARE(retval.isConstant(), true);
+ QCOMPARE(retval.referenceType(), NoReference);
+ QVERIFY(args.at(0).name.isEmpty());
+ QVERIFY(args.at(1).name.isEmpty());
+
+ QCOMPARE(args.at(2).name, u"my_name");
+ auto arg2Type = args.at(2).typeInfo;
+ QCOMPARE(arg2Type.qualifiedName(), QStringList{u"Abc"_s});
+ QCOMPARE(arg2Type.instantiations().size(), 2);
+ QCOMPARE(arg2Type.toString(), u"const Abc<int&, C<char*>*>**");
+ QCOMPARE(arg2Type.indirections(), 2);
+ QCOMPARE(arg2Type.isConstant(), true);
+ QCOMPARE(arg2Type.referenceType(), NoReference);
+
+ QVERIFY(args.at(3).name.isEmpty());
+
+ // function with no args.
+ auto f3 = AddedFunction::createAddedFunction("func()"_L1, voidT, &errorMessage);
+ QVERIFY2(f3, qPrintable(errorMessage));
+ QCOMPARE(f3->name(), u"func");
+ QCOMPARE(f3->arguments().size(), 0);
+
+ // const call operator
+ auto f4 = AddedFunction::createAddedFunction("operator()(int)const"_L1,
+ "int"_L1, &errorMessage);
+ QVERIFY2(f4, qPrintable(errorMessage));
+ QCOMPARE(f4->name(), u"operator()");
+ QCOMPARE(f4->arguments().size(), 1);
+ QVERIFY(f4->isConstant());
+}
+
+void TestAddFunction::testAddFunction()
+{
+ const char cppCode[] = R"CPP(
+struct B {};
+struct A {
+ void a(int);
+};)CPP";
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <primitive-type name='float'/>
+ <value-type name='B'/>
+ <value-type name='A'>
+ <add-function signature='b(int, float = 4.6, const B&amp;)' return-type='int' access='protected'/>
+ <add-function signature='operator()(int)' return-type='int' access='public'/>
+ </value-type>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ auto *typeDb = TypeDatabase::instance();
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ // default ctor, default copy ctor, func a() and the added functions
+ QCOMPARE(classA->functions().size(), 5);
+
+ auto addedFunc = classA->findFunction("b");
+ QVERIFY(addedFunc);
+ QCOMPARE(addedFunc->access(), Access::Protected);
+ QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction);
+ QVERIFY(addedFunc->isUserAdded());
+ QCOMPARE(addedFunc->ownerClass(), classA);
+ QCOMPARE(addedFunc->implementingClass(), classA);
+ QCOMPARE(addedFunc->declaringClass(), classA);
+ QVERIFY(!addedFunc->isVirtual());
+ QVERIFY(!addedFunc->isSignal());
+ QVERIFY(!addedFunc->isSlot());
+ QVERIFY(!addedFunc->isStatic());
+
+ AbstractMetaType returnType = addedFunc->type();
+ QCOMPARE(returnType.typeEntry(), typeDb->findPrimitiveType(u"int"_s));
+ const AbstractMetaArgumentList &args = addedFunc->arguments();
+ QCOMPARE(args.size(), 3);
+ QCOMPARE(args.at(0).type().typeEntry(), returnType.typeEntry());
+ QCOMPARE(args.at(1).defaultValueExpression(), u"4.6");
+ QCOMPARE(args.at(2).type().typeEntry(), typeDb->findType(u"B"_s));
+
+ auto addedCallOperator = classA->findFunction("operator()");
+ QVERIFY(addedCallOperator);
+}
+
+void TestAddFunction::testAddFunctionConstructor()
+{
+ const char cppCode[] = "struct A { A() {} };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='A(int)'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().size(), 3); // default and added ctors
+ const auto addedFunc = classA->functions().constLast();
+ QCOMPARE(addedFunc->access(), Access::Public);
+ QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::ConstructorFunction);
+ QCOMPARE(addedFunc->arguments().size(), 1);
+ QVERIFY(addedFunc->isUserAdded());
+ QVERIFY(addedFunc->isVoid());
+}
+
+void TestAddFunction::testAddFunctionTagDefaultValues()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func()'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ // default ctor, default copy ctor and the added function
+ QCOMPARE(classA->functions().size(), 3);
+ const auto addedFunc = classA->functions().constLast();
+ QCOMPARE(addedFunc->access(), Access::Public);
+ QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction);
+ QVERIFY(addedFunc->isUserAdded());
+ QVERIFY(addedFunc->isVoid());
+}
+
+void TestAddFunction::testAddFunctionCodeSnippets()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func()'>\n\
+ <inject-code class='target' position='end'>Hi!, I am the code.</inject-code>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->functions().constLast();
+ QVERIFY(addedFunc->hasInjectedCode());
+}
+
+void TestAddFunction::testAddFunctionWithoutParenteses()
+{
+ static constexpr auto sig1 = "func"_L1;
+ QString errorMessage;
+ auto f1 = AddedFunction::createAddedFunction(sig1, voidT, &errorMessage);
+ QVERIFY2(f1, qPrintable(errorMessage));
+ QCOMPARE(f1->name(), u"func");
+ QCOMPARE(f1->arguments().size(), 0);
+ QCOMPARE(f1->isConstant(), false);
+
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func'>\n\
+ <inject-code class='target' position='end'>Hi!, I am the code.</inject-code>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction(sig1);
+ QVERIFY(addedFunc);
+ QVERIFY(addedFunc->hasInjectedCode());
+ const auto snips = addedFunc->injectedCodeSnips(TypeSystem::CodeSnipPositionAny,
+ TypeSystem::TargetLangCode);
+ QCOMPARE(snips.size(), 1);
+}
+
+void TestAddFunction::testAddFunctionWithDefaultArgs()
+{
+ static constexpr auto sig1 = "func"_L1;
+ QString errorMessage;
+ auto f1 = AddedFunction::createAddedFunction(sig1, voidT, &errorMessage);
+ QVERIFY2(f1, qPrintable(errorMessage));
+ QCOMPARE(f1->name(), u"func");
+ QCOMPARE(f1->arguments().size(), 0);
+ QCOMPARE(f1->isConstant(), false);
+
+ const char cppCode[] = "struct A { };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func(int, int)'>\n\
+ <modify-argument index='2'>\n\
+ <replace-default-expression with='2'/>\n\
+ </modify-argument>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction(sig1);
+ QVERIFY(addedFunc);
+ const AbstractMetaArgument &arg = addedFunc->arguments().at(1);
+ QCOMPARE(arg.defaultValueExpression(), u"2");
+}
+
+void TestAddFunction::testAddFunctionAtModuleLevel()
+{
+ const char cppCode[] = "struct A { };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'/>\n\
+ <add-function signature='func(int, int)'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+
+ auto *typeDb = TypeDatabase::instance();
+
+ AddedFunctionList addedFuncs = typeDb->findGlobalUserFunctions(u"func"_s);
+
+ QCOMPARE(addedFuncs.size(), 1);
+
+ auto &mods = addedFuncs.constFirst()->modifications();
+
+ QCOMPARE(mods.size(), 1);
+ QVERIFY(mods.constFirst().isCodeInjection());
+ CodeSnip snip = mods.constFirst().snips().constFirst();
+ QCOMPARE(snip.code().trimmed(), u"custom_code();");
+}
+
+void TestAddFunction::testAddFunctionWithVarargs()
+{
+ QString errorMessage;
+ auto f1 = AddedFunction::createAddedFunction("func(int,char,...)"_L1, voidT,
+ &errorMessage);
+ QVERIFY2(f1, qPrintable(errorMessage));
+ QCOMPARE(f1->name(), u"func");
+ QCOMPARE(f1->arguments().size(), 3);
+ QVERIFY(!f1->isConstant());
+
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='char'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func(int,char,...)'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction("func");
+ QVERIFY(addedFunc);
+ const AbstractMetaArgument &arg = addedFunc->arguments().constLast();
+ QVERIFY(arg.type().isVarargs());
+ QVERIFY(arg.type().typeEntry()->isVarargs());
+}
+
+void TestAddFunction::testAddStaticFunction()
+{
+ const char cppCode[] = "struct A { };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='func(int, int)' static='yes'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction("func");
+ QVERIFY(addedFunc);
+ QVERIFY(addedFunc->isStatic());
+}
+
+void TestAddFunction::testAddGlobalFunction()
+{
+ const char cppCode[] = "struct A { };struct B {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'/>\n\
+ <add-function signature='globalFunc(int, int)' static='yes'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ <add-function signature='globalFunc2(int, int)' static='yes'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ const auto globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.size(), 2);
+ const auto classB = AbstractMetaClass::findClass(builder->classes(), "B");
+ QVERIFY(classB);
+ QVERIFY(!classB->findFunction("globalFunc"));
+ QVERIFY(!classB->findFunction("globalFunc2"));
+ QVERIFY(!globalFuncs[0]->injectedCodeSnips().isEmpty());
+ QVERIFY(!globalFuncs[1]->injectedCodeSnips().isEmpty());
+}
+
+void TestAddFunction::testAddFunctionWithApiVersion()
+{
+ const char cppCode[] = "";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <add-function signature='globalFunc(int, int)' static='yes' since='1.3'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ <add-function signature='globalFunc2(int, int)' static='yes' since='0.1'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, u"0.1"_s));
+ QVERIFY(builder);
+ const auto globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.size(), 1);
+}
+
+void TestAddFunction::testModifyAddedFunction()
+{
+ const char cppCode[] = "class Foo { };\n";
+ const char xmlCode[] = R"(
+<typesystem package='Package'>
+ <primitive-type name='float'/>
+ <primitive-type name='int'/>
+ <value-type name='Foo'>
+ <add-function signature='method(float, int)'>
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>
+ <modify-argument index='2' rename='varName'>
+ <replace-default-expression with='0'/>
+ </modify-argument>
+ </add-function>
+ </value-type>
+</typesystem>
+)";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto foo = AbstractMetaClass::findClass(classes, "Foo");
+ const auto method = foo->findFunction("method");
+ QVERIFY(method);
+ QCOMPARE(method->arguments().size(), 2);
+ const AbstractMetaArgument &arg = method->arguments().at(1);
+ QCOMPARE(arg.defaultValueExpression(), u"0");
+ QCOMPARE(arg.name(), u"varName");
+ QCOMPARE(method->argumentName(2), u"varName");
+}
+
+void TestAddFunction::testAddFunctionOnTypedef()
+{
+ const char cppCode[] = "template<class T> class Foo { }; typedef Foo<int> FooInt;\n";
+ const char xmlCode[] = "\
+ <typesystem package='Package'>\n\
+ <value-type name='FooInt'>\n\
+ <add-function signature='FooInt(PySequence)'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ <add-function signature='method()'>\n\
+ <inject-code class='target' position='beginning'>custom_code();</inject-code>\n\
+ </add-function>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto foo = AbstractMetaClass::findClass(classes, "FooInt");
+ QVERIFY(foo);
+ QVERIFY(foo->hasNonPrivateConstructor());
+ const auto &lst = foo->queryFunctions(FunctionQueryOption::AnyConstructor);
+ for (const auto &f : lst)
+ QVERIFY(f->signature().startsWith(f->name()));
+ QCOMPARE(lst.size(), 2);
+ const auto method = foo->findFunction("method");
+ QVERIFY(method);
+}
+
+void TestAddFunction::testAddFunctionWithTemplateArg()
+{
+ const char cppCode[] = "template<class T> class Foo { };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Package'>\n\
+ <primitive-type name='int'/>\n\
+ <container-type name='Foo' type='list'/>\n\
+ <add-function signature='func(Foo&lt;int>)'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ QCOMPARE(builder->globalFunctions().size(), 1);
+ const auto func = builder->globalFunctions().constFirst();
+ const AbstractMetaArgument &arg = func->arguments().constFirst();
+ QCOMPARE(arg.type().instantiations().size(), 1);
+}
+
+// Test splitting of <add-function> parameter lists.
+
+Q_DECLARE_METATYPE(AddedFunctionParser::Argument)
+
+using Arguments = AddedFunctionParser::Arguments;
+
+void TestAddFunction::testAddFunctionTypeParser_data()
+{
+ QTest::addColumn<QString>("parameterList");
+ QTest::addColumn<Arguments>("expected");
+
+ QTest::newRow("empty")
+ << QString() << Arguments{};
+
+ QTest::newRow("1-arg")
+ << QString::fromLatin1("int @a@=42")
+ << Arguments{{u"int"_s, u"a"_s, u"42"_s}};
+
+ QTest::newRow("2-args")
+ << QString::fromLatin1("double @d@, int @a@=42")
+ << Arguments{{u"double"_s, u"d"_s, {}},
+ {u"int"_s, u"a"_s, u"42"_s}};
+
+ QTest::newRow("template-var_args")
+ << QString::fromLatin1("const QList<X,Y> &@list@ = QList<X,Y>{1,2}, int @b@=5, ...")
+ << Arguments{{u"const QList<X,Y> &"_s, u"list"_s, u"QList<X,Y>{1,2}"_s},
+ {u"int"_s, u"b"_s, u"5"_s},
+ {u"..."_s, {}, {}}};
+}
+
+void TestAddFunction::testAddFunctionTypeParser()
+{
+
+ QFETCH(QString, parameterList);
+ QFETCH(Arguments, expected);
+
+ const auto actual = AddedFunctionParser::splitParameters(parameterList);
+ QCOMPARE(actual, expected);
+}
+
+QTEST_APPLESS_MAIN(TestAddFunction)
diff --git a/sources/shiboken6/ApiExtractor/tests/testaddfunction.h b/sources/shiboken6/ApiExtractor/tests/testaddfunction.h
new file mode 100644
index 000000000..77339609f
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testaddfunction.h
@@ -0,0 +1,31 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTADDFUNCTION_H
+#define TESTADDFUNCTION_H
+#include <QtCore/QObject>
+
+class TestAddFunction : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testParsingFuncNameAndConstness();
+ void testAddFunction();
+ void testAddFunctionConstructor();
+ void testAddFunctionTagDefaultValues();
+ void testAddFunctionCodeSnippets();
+ void testAddFunctionWithoutParenteses();
+ void testAddFunctionWithDefaultArgs();
+ void testAddFunctionAtModuleLevel();
+ void testAddFunctionWithVarargs();
+ void testAddStaticFunction();
+ void testAddGlobalFunction();
+ void testAddFunctionWithApiVersion();
+ void testModifyAddedFunction();
+ void testAddFunctionOnTypedef();
+ void testAddFunctionWithTemplateArg();
+ void testAddFunctionTypeParser_data();
+ void testAddFunctionTypeParser();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testarrayargument.cpp b/sources/shiboken6/ApiExtractor/tests/testarrayargument.cpp
new file mode 100644
index 000000000..6e1820bed
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testarrayargument.cpp
@@ -0,0 +1,155 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testarrayargument.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetaenum.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <primitivetypeentry.h>
+#include <parser/enumvalue.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestArrayArgument::testArrayArgumentWithSizeDefinedByInteger()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ enum SomeEnum { Value0, Value1, NValues };\n\
+ void method(double[3]);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='double'/>\n\
+ <object-type name='A'>\n\
+ <enum-type name='SomeEnum'/>\n\
+ </object-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+
+ const AbstractMetaArgument &arg = classA->functions().constLast()->arguments().constFirst();
+ QVERIFY(arg.type().isArray());
+ QCOMPARE(arg.type().arrayElementCount(), 3);
+ QCOMPARE(arg.type().arrayElementType()->name(), u"double");
+}
+
+static QString functionMinimalSignature(const AbstractMetaClassCPtr &c, const QString &name)
+{
+ const auto f = c->findFunction(name);
+ return f ? f->minimalSignature() : QString();
+}
+
+void TestArrayArgument::testArraySignature()
+{
+ const char cppCode[] ="\
+ struct A {\n\
+ void mi1(int arg[5]);\n\
+ void mi1c(const int arg[5]);\n\
+ void mi1cu(const int arg[]);\n\
+ void mc1cu(const char arg[]);\n\
+ void mc1cup(const char *arg[]);\n\
+ void muc2(unsigned char *arg[2][3]);\n\
+ void mc2c(const char *arg[5][6]);\n\
+ void mc2cu(const char arg[][2]);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='char'/>\n\
+ <primitive-type name='unsigned char'/>\n\
+ <primitive-type name='int'/>\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QCOMPARE(functionMinimalSignature(classA, u"mi1"_s),
+ u"mi1(int[5])");
+ QCOMPARE(functionMinimalSignature(classA, u"mi1c"_s),
+ u"mi1c(const int[5])");
+ QCOMPARE(functionMinimalSignature(classA, u"mi1cu"_s),
+ u"mi1cu(const int[])");
+ QCOMPARE(functionMinimalSignature(classA, u"mc1cu"_s),
+ u"mc1cu(const char*)");
+ QCOMPARE(functionMinimalSignature(classA, u"mc1cup"_s),
+ u"mc1cup(const char*[])");
+ QCOMPARE(functionMinimalSignature(classA, u"muc2"_s),
+ u"muc2(unsigned char*[2][3])");
+ QCOMPARE(functionMinimalSignature(classA, u"mc2c"_s),
+ u"mc2c(const char*[5][6])");
+ QCOMPARE(functionMinimalSignature(classA, u"mc2cu"_s),
+ u"mc2cu(const char[][2])");
+}
+
+void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValue()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ enum SomeEnum { Value0, Value1, NValues };\n\
+ void method(double[NValues]);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='double'/>\n\
+ <object-type name='A'>\n\
+ <enum-type name='SomeEnum'/>\n\
+ </object-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(!builder.isNull());
+ AbstractMetaClassPtr classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+
+ auto someEnum = classA->findEnum(u"SomeEnum"_s);
+ QVERIFY(someEnum.has_value());
+ auto nvalues = classA->findEnumValue(u"NValues"_s);
+ QVERIFY(nvalues.has_value());
+
+ const AbstractMetaArgument &arg = classA->functions().constLast()->arguments().constFirst();
+ QVERIFY(arg.type().isArray());
+ QCOMPARE(arg.type().arrayElementCount(), nvalues->value().value());
+ QCOMPARE(arg.type().arrayElementType()->name(), u"double");
+};
+
+void TestArrayArgument::testArrayArgumentWithSizeDefinedByEnumValueFromGlobalEnum()
+{
+ const char cppCode[] = "\
+ enum SomeEnum { Value0, Value1, NValues };\n\
+ struct A {\n\
+ void method(double[NValues]);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='double'/>\n\
+ <enum-type name='SomeEnum'/>\n\
+ <object-type name='A'>\n\
+ </object-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+
+ AbstractMetaEnum someEnum = builder->globalEnums().constFirst();
+ auto nvalues = someEnum.findEnumValue(u"NValues");
+ QVERIFY(nvalues.has_value());
+
+ const AbstractMetaArgument &arg = classA->functions().constLast()->arguments().constFirst();
+ QVERIFY(arg.type().isArray());
+ QCOMPARE(arg.type().arrayElementCount(), nvalues->value().value());
+ QCOMPARE(arg.type().arrayElementType()->name(), u"double");
+};
+
+QTEST_APPLESS_MAIN(TestArrayArgument)
diff --git a/sources/shiboken6/ApiExtractor/tests/testarrayargument.h b/sources/shiboken6/ApiExtractor/tests/testarrayargument.h
new file mode 100644
index 000000000..75ef0f792
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testarrayargument.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTARRAYARGUMENT_H
+#define TESTARRAYARGUMENT_H
+#include <QtCore/QObject>
+
+class TestArrayArgument : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testArrayArgumentWithSizeDefinedByInteger();
+ void testArraySignature();
+ void testArrayArgumentWithSizeDefinedByEnumValue();
+ void testArrayArgumentWithSizeDefinedByEnumValueFromGlobalEnum();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp
new file mode 100644
index 000000000..4829e6c33
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.cpp
@@ -0,0 +1,164 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testcodeinjection.h"
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <codesnip.h>
+#include <modifications.h>
+#include <textstream.h>
+#include <complextypeentry.h>
+#include <valuetypeentry.h>
+
+#include <qtcompat.h>
+
+#include <QtCore/QDir>
+#include <QtCore/QFileInfo>
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestCodeInjections::testReadFile_data()
+{
+ QTest::addColumn<QString>("filePath");
+ QTest::addColumn<QString>("snippet");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("utf8")
+ << QString::fromLatin1(":/utf8code.txt")
+ << QString()
+ << QString::fromUtf8("\xC3\xA1\xC3\xA9\xC3\xAD\xC3\xB3\xC3\xBA");
+
+ QTest::newRow("snippet")
+ << QString::fromLatin1(":/injectedcode.txt")
+ << QString::fromLatin1("label")
+ << QString::fromLatin1("code line");
+}
+
+void TestCodeInjections::testReadFile()
+{
+ QFETCH(QString, filePath);
+ QFETCH(QString, snippet);
+ QFETCH(QString, expected);
+
+ const char cppCode[] = "struct A {};\n";
+ int argc = 0;
+ char *argv[] = {nullptr};
+ QCoreApplication app(argc, argv);
+
+ QString attribute = u"file='"_s + filePath + u'\'';
+ if (!snippet.isEmpty())
+ attribute += u" snippet='"_s + snippet + u'\'';
+
+ QString xmlCode = u"\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <conversion-rule class='target' "_s + attribute + u"/>\n\
+ <inject-code class='target' "_s + attribute + u"/>\n\
+ <value-type name='B'/>\n\
+ </value-type>\n\
+ </typesystem>\n"_s;
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().constData()));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QCOMPARE(classA->typeEntry()->codeSnips().size(), 1);
+ QString code = classA->typeEntry()->codeSnips().constFirst().code();
+ QVERIFY(code.indexOf(expected) != -1);
+ QVERIFY(classA->typeEntry()->isValue());
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(classA->typeEntry());
+ code = vte->targetConversionRule();
+ QVERIFY(code.indexOf(expected) != -1);
+}
+
+void TestCodeInjections::testInjectWithValidApiVersion()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <inject-code class='target' since='1.0'>\n\
+ test Inject code\n\
+ </inject-code>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, u"1.0"_s));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QCOMPARE(classA->typeEntry()->codeSnips().size(), 1);
+}
+
+void TestCodeInjections::testInjectWithInvalidApiVersion()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <inject-code class='target' since='1.0'>\n\
+ test Inject code\n\
+ </inject-code>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, u"0.1"_s));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QCOMPARE(classA->typeEntry()->codeSnips().size(), 0);
+}
+
+void TestCodeInjections::testTextStream()
+{
+ StringStream str(TextStream::Language::Cpp);
+ str << "void foo(int a, int b) {\n" << indent
+ << "if (a == b)\n" << indent << "return a;\n" << outdent
+ << "#if Q_OS_WIN\nprint()\n#endif\nreturn a + b;\n" << outdent
+ << "}\n\n// A table\n|"
+ << AlignedField("bla", 40, QTextStream::AlignRight) << "|\n|"
+ << AlignedField("bla", 40, QTextStream::AlignLeft) << "|\n|"
+ << AlignedField(QString(), 40, QTextStream::AlignLeft) << "|\n";
+ str << "\n2nd table\n|" << AlignedField("bla", 3, QTextStream::AlignLeft)
+ << '|' << AlignedField(QString{}, 0, QTextStream::AlignLeft) << "|\n";
+
+constexpr auto expected = R"(void foo(int a, int b) {
+ if (a == b)
+ return a;
+#if Q_OS_WIN
+ print()
+#endif
+ return a + b;
+}
+
+// A table
+| bla|
+|bla |
+| |
+
+2nd table
+|bla||
+)"_L1;
+
+ QCOMPARE(str.toString(), expected);
+}
+
+void TestCodeInjections::testTextStreamRst()
+{
+ // Test that sphinx error: "Inline strong start-string without end-string."
+ // is avoided, that is, characters following a formatting end are escaped.
+
+ StringStream str;
+ str << rstBold << "QObject" << rstBoldOff << "'s properties..."
+ << rstItalic << "some italic" << rstItalicOff << " followed by space.";
+
+ static const char16_t expected[] =
+ uR"(**QObject**\'s properties...*some italic* followed by space.)";
+
+ QCOMPARE(str.toString(), expected);
+}
+
+QTEST_APPLESS_MAIN(TestCodeInjections)
diff --git a/sources/shiboken6/ApiExtractor/tests/testcodeinjection.h b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.h
new file mode 100644
index 000000000..a164ea36e
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.h
@@ -0,0 +1,23 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTCODEINJECTIONS_H
+#define TESTCODEINJECTIONS_H
+
+#include <QtCore/QObject>
+
+class AbstractMetaBuilder;
+
+class TestCodeInjections : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testReadFile_data();
+ void testReadFile();
+ void testInjectWithValidApiVersion();
+ void testInjectWithInvalidApiVersion();
+ void testTextStream();
+ void testTextStreamRst();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testcodeinjection.qrc b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.qrc
new file mode 100644
index 000000000..fd7616bd2
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testcodeinjection.qrc
@@ -0,0 +1,6 @@
+<RCC>
+ <qresource>
+ <file>utf8code.txt</file>
+ <file>injectedcode.txt</file>
+ </qresource>
+</RCC>
diff --git a/sources/shiboken6/ApiExtractor/tests/testcontainer.cpp b/sources/shiboken6/ApiExtractor/tests/testcontainer.cpp
new file mode 100644
index 000000000..0bb72b3c1
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testcontainer.cpp
@@ -0,0 +1,84 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testcontainer.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <complextypeentry.h>
+#include <containertypeentry.h>
+
+void TestContainer::testContainerType()
+{
+ const char cppCode[] = "\
+ namespace std {\n\
+ template<class T>\n\
+ class list {\n\
+ T get(int x) { return 0; }\n\
+ };\n\
+ }\n\
+ class A : public std::list<int> {\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='std' generate='no' />\n\
+ <container-type name='std::list' type='list' />\n\
+ <object-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ //search for class A
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ auto baseContainer = classA->typeEntry()->baseContainerType();
+ QVERIFY(baseContainer);
+ QCOMPARE(reinterpret_cast<const ContainerTypeEntry*>(baseContainer.get())->containerKind(),
+ ContainerTypeEntry::ListContainer);
+}
+
+void TestContainer::testListOfValueType()
+{
+ const char cppCode[] = "\
+ namespace std {\n\
+ template<class T>\n\
+ class list {\n\
+ T get(int x) { return 0; }\n\
+ };\n\
+ }\n\
+ class ValueType {};\n\
+ class A : public std::list<ValueType> {\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='std' generate='no'/>\n\
+ <container-type name='std::list' type='list'/>\n\
+ <value-type name='ValueType'/>\n\
+ <value-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 3);
+
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->templateBaseClassInstantiations().size(), 1);
+ const AbstractMetaType templateInstanceType =
+ classA->templateBaseClassInstantiations().constFirst();
+
+ QCOMPARE(templateInstanceType.indirections(), 0);
+ QVERIFY(!templateInstanceType.typeEntry()->isObject());
+ QVERIFY(templateInstanceType.typeEntry()->isValue());
+ QCOMPARE(templateInstanceType.referenceType(), NoReference);
+ QVERIFY(!templateInstanceType.isObject());
+ QVERIFY(!templateInstanceType.isValuePointer());
+ QVERIFY(templateInstanceType.isValue());
+}
+
+QTEST_APPLESS_MAIN(TestContainer)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testcontainer.h b/sources/shiboken6/ApiExtractor/tests/testcontainer.h
new file mode 100644
index 000000000..3fd23c3f0
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testcontainer.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTCONTAINER_H
+#define TESTCONTAINER_H
+#include <QtCore/QObject>
+
+class TestContainer : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testContainerType();
+ void testListOfValueType();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testconversionoperator.cpp b/sources/shiboken6/ApiExtractor/tests/testconversionoperator.cpp
new file mode 100644
index 000000000..8f2b277af
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testconversionoperator.cpp
@@ -0,0 +1,178 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testconversionoperator.h"
+#include "testutil.h"
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <typesystem.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestConversionOperator::testConversionOperator()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ };\n\
+ struct B {\n\
+ operator A() const;\n\
+ };\n\
+ struct C {\n\
+ operator A() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ <value-type name='C'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ const auto classC = AbstractMetaClass::findClass(classes, "C");
+ QVERIFY(classA);
+ QVERIFY(classB);
+ QVERIFY(classC);
+ QCOMPARE(classA->functions().size(), 2);
+ QCOMPARE(classB->functions().size(), 3);
+ QCOMPARE(classC->functions().size(), 3);
+ QCOMPARE(classA->externalConversionOperators().size(), 2);
+
+ AbstractMetaFunctionCPtr convOp;
+ for (const auto &func : classB->functions()) {
+ if (func->isConversionOperator()) {
+ convOp = func;
+ break;
+ }
+ }
+ QVERIFY(convOp);
+ QVERIFY(classA->externalConversionOperators().contains(convOp));
+}
+
+void TestConversionOperator::testConversionOperatorOfDiscardedClass()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ };\n\
+ struct B {\n\
+ operator A() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A' />\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->externalConversionOperators().size(), 0);
+}
+
+void TestConversionOperator::testRemovedConversionOperator()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ };\n\
+ struct B {\n\
+ operator A() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A' />\n\
+ <value-type name='B'>\n\
+ <modify-function signature='operator A() const' remove='all'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classA);
+ QVERIFY(classB);
+ QCOMPARE(classA->functions().size(), 2);
+ QCOMPARE(classB->functions().size(), 3);
+ QCOMPARE(classA->externalConversionOperators().size(), 0);
+ QCOMPARE(classA->implicitConversions().size(), 0);
+}
+
+void TestConversionOperator::testConversionOperatorReturningReference()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ operator A&() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classA);
+ QVERIFY(classB);
+ QCOMPARE(classA->functions().size(), 2);
+ QCOMPARE(classB->functions().size(), 3);
+ QCOMPARE(classA->externalConversionOperators().size(), 1);
+ QCOMPARE(classA->externalConversionOperators().constFirst()->type().cppSignature(),
+ u"A");
+ QCOMPARE(classA->externalConversionOperators().constFirst()->ownerClass()->name(),
+ u"B");
+ QCOMPARE(classA->implicitConversions().size(), 1);
+ QCOMPARE(classA->implicitConversions().constFirst()->type().cppSignature(),
+ u"A");
+ QCOMPARE(classA->implicitConversions().constFirst()->ownerClass()->name(),
+ u"B");
+}
+
+void TestConversionOperator::testConversionOperatorReturningConstReference()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ operator const A&() const;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classA);
+ QVERIFY(classB);
+ QCOMPARE(classA->functions().size(), 2);
+ QCOMPARE(classB->functions().size(), 3);
+ QCOMPARE(classA->externalConversionOperators().size(), 1);
+ QCOMPARE(classA->externalConversionOperators().constFirst()->type().cppSignature(),
+ u"A"_s);
+ QCOMPARE(classA->externalConversionOperators().constFirst()->ownerClass()->name(),
+ u"B"_s);
+ QCOMPARE(classA->implicitConversions().size(), 1);
+ QCOMPARE(classA->implicitConversions().constFirst()->type().cppSignature(),
+ u"A"_s);
+ QCOMPARE(classA->implicitConversions().constFirst()->ownerClass()->name(),
+ u"B"_s);
+}
+
+QTEST_APPLESS_MAIN(TestConversionOperator)
diff --git a/sources/shiboken6/ApiExtractor/tests/testconversionoperator.h b/sources/shiboken6/ApiExtractor/tests/testconversionoperator.h
new file mode 100644
index 000000000..68288d240
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testconversionoperator.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTCONVERSIONOPERATOR_H
+#define TESTCONVERSIONOPERATOR_H
+#include <QtCore/QObject>
+
+class TestConversionOperator : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testConversionOperator();
+ void testConversionOperatorOfDiscardedClass();
+ void testRemovedConversionOperator();
+ void testConversionOperatorReturningReference();
+ void testConversionOperatorReturningConstReference();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp
new file mode 100644
index 000000000..b5efd92a6
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.cpp
@@ -0,0 +1,240 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testconversionruletag.h"
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <complextypeentry.h>
+#include <customconversion.h>
+#include <primitivetypeentry.h>
+#include <valuetypeentry.h>
+
+#include <qtcompat.h>
+
+#include <QtCore/QFile>
+#include <QtCore/QTemporaryFile>
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestConversionRuleTag::testConversionRuleTagWithFile()
+{
+ // FIXME PYSIDE7 remove
+ // temp file used later
+ constexpr auto conversionData = "Hi! I'm a conversion rule."_L1;
+ QTemporaryFile file;
+ QVERIFY(file.open());
+ QCOMPARE(file.write(conversionData.constData()), conversionData.size());
+ file.close();
+
+ const char cppCode[] = "struct A {};\n";
+ QString xmlCode = u"\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <conversion-rule class='target' file='"_s + file.fileName() + u"'/>\n\
+ </value-type>\n\
+ </typesystem>\n"_s;
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.toLocal8Bit().data()));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto typeEntry = classA->typeEntry();
+ QVERIFY(typeEntry->isValue());
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(typeEntry);
+ QVERIFY(vte->hasTargetConversionRule());
+ QCOMPARE(vte->targetConversionRule(), conversionData);
+}
+
+void TestConversionRuleTag::testConversionRuleTagReplace()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ A();\n\
+ A(const char*, int);\n\
+ };\n\
+ struct B {\n\
+ A createA();\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='char'/>\n\
+ <primitive-type name='A'>\n\
+ <conversion-rule>\n\
+ <native-to-target>\n\
+ DoThis();\n\
+ return ConvertFromCppToPython(%IN);\n\
+ </native-to-target>\n\
+ <target-to-native>\n\
+ <add-conversion type='TargetNone' check='%IN == Target_None'>\n\
+ DoThat();\n\
+ DoSomething();\n\
+ %OUT = A();\n\
+ </add-conversion>\n\
+ <add-conversion type='B' check='CheckIfInputObjectIsB(%IN)'>\n\
+ %OUT = %IN.createA();\n\
+ </add-conversion>\n\
+ <add-conversion type='String' check='String_Check(%IN)'>\n\
+ %OUT = new A(String_AsString(%IN), String_GetSize(%IN));\n\
+ </add-conversion>\n\
+ </target-to-native>\n\
+ </conversion-rule>\n\
+ </primitive-type>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ auto *typeDb = TypeDatabase::instance();
+ auto typeA = typeDb->findPrimitiveType(u"A"_s);
+ QVERIFY(typeA);
+
+ QVERIFY(typeA->hasCustomConversion());
+ auto conversion = typeA->customConversion();
+
+ QCOMPARE(typeA, conversion->ownerType());
+ QCOMPARE(conversion->nativeToTargetConversion().simplified(),
+ u"DoThis(); return ConvertFromCppToPython(%IN);");
+
+ QVERIFY(conversion->replaceOriginalTargetToNativeConversions());
+ QVERIFY(conversion->hasTargetToNativeConversions());
+ QCOMPARE(conversion->targetToNativeConversions().size(), 3);
+
+ QVERIFY(!conversion->targetToNativeConversions().isEmpty());
+ auto toNative = conversion->targetToNativeConversions().at(0);
+ QCOMPARE(toNative.sourceTypeName(), u"TargetNone");
+ QVERIFY(toNative.isCustomType());
+ QCOMPARE(toNative.sourceType(), nullptr);
+ QCOMPARE(toNative.sourceTypeCheck(), u"%IN == Target_None");
+ QCOMPARE(toNative.conversion().simplified(),
+ u"DoThat(); DoSomething(); %OUT = A();");
+
+ QVERIFY(conversion->targetToNativeConversions().size() > 1);
+ toNative = conversion->targetToNativeConversions().at(1);
+ QCOMPARE(toNative.sourceTypeName(), u"B");
+ QVERIFY(!toNative.isCustomType());
+ auto typeB = typeDb->findType(u"B"_s);
+ QVERIFY(typeB);
+ QCOMPARE(toNative.sourceType(), typeB);
+ QCOMPARE(toNative.sourceTypeCheck(), u"CheckIfInputObjectIsB(%IN)");
+ QCOMPARE(toNative.conversion().trimmed(), u"%OUT = %IN.createA();");
+
+ QVERIFY(conversion->targetToNativeConversions().size() > 2);
+ toNative = conversion->targetToNativeConversions().at(2);
+ QCOMPARE(toNative.sourceTypeName(), u"String");
+ QVERIFY(toNative.isCustomType());
+ QCOMPARE(toNative.sourceType(), nullptr);
+ QCOMPARE(toNative.sourceTypeCheck(), u"String_Check(%IN)");
+ QCOMPARE(toNative.conversion().trimmed(),
+ u"%OUT = new A(String_AsString(%IN), String_GetSize(%IN));");
+}
+
+void TestConversionRuleTag::testConversionRuleTagAdd()
+{
+ const char cppCode[] = "\
+ struct Date {\n\
+ Date();\n\
+ Date(int, int, int);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='Date'>\n\
+ <conversion-rule>\n\
+ <target-to-native replace='no'>\n\
+ <add-conversion type='TargetDate' check='TargetDate_Check(%IN)'>\n\
+if (!TargetDateTimeAPI) TargetDateTime_IMPORT;\n\
+%OUT = new Date(TargetDate_Day(%IN), TargetDate_Month(%IN), TargetDate_Year(%IN));\n\
+ </add-conversion>\n\
+ </target-to-native>\n\
+ </conversion-rule>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "Date");
+ QVERIFY(classA);
+
+ QVERIFY(classA->typeEntry()->isValue());
+ auto vte = std::static_pointer_cast<const ValueTypeEntry>(classA->typeEntry());
+ QVERIFY(vte->hasCustomConversion());
+ auto conversion = vte->customConversion();
+
+ QCOMPARE(conversion->nativeToTargetConversion(), QString());
+
+ QVERIFY(!conversion->replaceOriginalTargetToNativeConversions());
+ QVERIFY(conversion->hasTargetToNativeConversions());
+ QCOMPARE(conversion->targetToNativeConversions().size(), 1);
+
+ QVERIFY(!conversion->targetToNativeConversions().isEmpty());
+ const auto &toNative = conversion->targetToNativeConversions().constFirst();
+ QCOMPARE(toNative.sourceTypeName(), u"TargetDate");
+ QVERIFY(toNative.isCustomType());
+ QCOMPARE(toNative.sourceType(), nullptr);
+ QCOMPARE(toNative.sourceTypeCheck(), u"TargetDate_Check(%IN)");
+ QCOMPARE(toNative.conversion().trimmed(),
+ uR"(if (!TargetDateTimeAPI) TargetDateTime_IMPORT;
+%OUT = new Date(TargetDate_Day(%IN), TargetDate_Month(%IN), TargetDate_Year(%IN));)");
+}
+
+void TestConversionRuleTag::testConversionRuleTagWithInsertTemplate()
+{
+ const char cppCode[] = "struct A {};";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <!-- single line -->\n\
+ <template name='native_to_target'>return ConvertFromCppToPython(%IN);</template>\n\
+ <!-- multi-line -->\n\
+ <template name='target_to_native'>\n\
+%OUT = %IN.createA();\n\
+ </template>\n\
+ <primitive-type name='A'>\n\
+ <conversion-rule>\n\
+ <native-to-target>\n\
+ <insert-template name='native_to_target'/>\n\
+ </native-to-target>\n\
+ <target-to-native>\n\
+ <add-conversion type='TargetType'>\n\
+ <insert-template name='target_to_native'/>\n\
+ </add-conversion>\n\
+ </target-to-native>\n\
+ </conversion-rule>\n\
+ </primitive-type>\n\
+ </typesystem>\n";
+
+ const char nativeToTargetExpected[] =
+ "// TEMPLATE - native_to_target - START\n"
+ "return ConvertFromCppToPython(%IN);\n"
+ "// TEMPLATE - native_to_target - END";
+
+ const char targetToNativeExpected[] =
+ "// TEMPLATE - target_to_native - START\n"
+ "%OUT = %IN.createA();\n"
+ "// TEMPLATE - target_to_native - END";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ auto *typeDb = TypeDatabase::instance();
+ auto typeA = typeDb->findPrimitiveType(u"A"_s);
+ QVERIFY(typeA);
+
+ QVERIFY(typeA->hasCustomConversion());
+ auto conversion = typeA->customConversion();
+
+ QCOMPARE(typeA, conversion->ownerType());
+ QCOMPARE(conversion->nativeToTargetConversion().trimmed(),
+ QLatin1StringView(nativeToTargetExpected));
+
+ QVERIFY(conversion->hasTargetToNativeConversions());
+ QCOMPARE(conversion->targetToNativeConversions().size(), 1);
+
+ QVERIFY(!conversion->targetToNativeConversions().isEmpty());
+ const auto &toNative = conversion->targetToNativeConversions().constFirst();
+ QCOMPARE(toNative.conversion().trimmed(),
+ QLatin1StringView(targetToNativeExpected));
+}
+
+QTEST_APPLESS_MAIN(TestConversionRuleTag)
diff --git a/sources/shiboken6/ApiExtractor/tests/testconversionruletag.h b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.h
new file mode 100644
index 000000000..64d496cc3
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testconversionruletag.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTCONVERSIONRULE_H
+#define TESTCONVERSIONRULE_H
+
+#include <QtCore/QObject>
+
+class TestConversionRuleTag : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testConversionRuleTagWithFile();
+ void testConversionRuleTagReplace();
+ void testConversionRuleTagAdd();
+ void testConversionRuleTagWithInsertTemplate();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testctorinformation.cpp b/sources/shiboken6/ApiExtractor/tests/testctorinformation.cpp
new file mode 100644
index 000000000..c3a3ebef0
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testctorinformation.cpp
@@ -0,0 +1,57 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testctorinformation.h"
+#include "abstractmetabuilder.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestCtorInformation::testCtorIsPrivate()
+{
+ const char cppCode[] = "class Control { public: Control() {} };\n\
+ class Subject { private: Subject() {} };\n\
+ class CtorLess { };\n";
+ const char xmlCode[] = "<typesystem package='Foo'>\n\
+ <value-type name='Control'/>\n\
+ <object-type name='Subject'/>\n\
+ <value-type name='CtorLess'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 3);
+ auto klass = AbstractMetaClass::findClass(classes, "Control");
+ QVERIFY(klass);
+ QVERIFY(klass->hasNonPrivateConstructor());
+ klass = AbstractMetaClass::findClass(classes, "Subject");
+ QVERIFY(klass);
+ QVERIFY(!klass->hasNonPrivateConstructor());
+ klass = AbstractMetaClass::findClass(classes, "CtorLess");
+ QVERIFY(klass);
+ QVERIFY(klass->hasNonPrivateConstructor());
+}
+
+void TestCtorInformation::testHasNonPrivateCtor()
+{
+ const char cppCode[] = "template<typename T>\n\
+ struct Base { Base(double) {} };\n\
+ typedef Base<int> Derived;\n";
+ const char xmlCode[] = "<typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='double'/>\n\
+ <object-type name='Base' generate='no'/>\n\
+ <object-type name='Derived'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto base = AbstractMetaClass::findClass(classes, "Base");
+ QCOMPARE(base->hasNonPrivateConstructor(), true);
+ const auto derived = AbstractMetaClass::findClass(classes, "Derived");
+ QCOMPARE(derived->hasNonPrivateConstructor(), true);
+}
+
+QTEST_APPLESS_MAIN(TestCtorInformation)
diff --git a/sources/shiboken6/ApiExtractor/tests/testctorinformation.h b/sources/shiboken6/ApiExtractor/tests/testctorinformation.h
new file mode 100644
index 000000000..58f1648e4
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testctorinformation.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTCTORINFORMATION_H
+#define TESTCTORINFORMATION_H
+
+#include <QtCore/QObject>
+
+class AbstractMetaBuilder;
+
+class TestCtorInformation: public QObject
+{
+ Q_OBJECT
+private slots:
+ void testCtorIsPrivate();
+ void testHasNonPrivateCtor();
+};
+
+#endif // TESTCTORINFORMATION_H
diff --git a/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.cpp b/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.cpp
new file mode 100644
index 000000000..16f50e69d
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.cpp
@@ -0,0 +1,228 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testdroptypeentries.h"
+#include "testutil.h"
+#include <abstractmetaenum.h>
+#include <abstractmetalang.h>
+#include <typesystem.h>
+#include <conditionalstreamreader.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+static const char cppCode[] = "\
+ struct ValueA {};\n\
+ struct ValueB {};\n\
+ struct ObjectA {};\n\
+ struct ObjectB {};\n\
+ namespace NamespaceA {\n\
+ struct InnerClassA {};\n\
+ namespace InnerNamespaceA {}\n\
+ }\n\
+ namespace NamespaceB {}\n\
+ enum EnumA { Value0 };\n\
+ enum EnumB { Value1 };\n\
+ void funcA();\n\
+ void funcB();\n";
+
+static const char xmlCode[] = "\
+<typesystem package='Foo'>\n\
+ <value-type name='ValueA'/>\n\
+ <value-type name='ValueB'/>\n\
+ <object-type name='ObjectA'/>\n\
+ <object-type name='ObjectB'/>\n\
+ <namespace-type name='NamespaceA'>\n\
+ <value-type name='InnerClassA'/>\n\
+ <namespace-type name='InnerNamespaceA'/>\n\
+ </namespace-type>\n\
+ <namespace-type name='NamespaceB'/>\n\
+ <enum-type name='EnumA'/>\n\
+ <enum-type name='EnumB'/>\n\
+ <function signature='funcA()'/>\n\
+ <function signature='funcB()'/>\n\
+</typesystem>\n";
+
+void TestDropTypeEntries::testDropEntries()
+{
+ const QStringList droppedEntries{u"Foo.ValueB"_s,
+ u"ObjectB"_s, // Check whether module can be omitted
+ u"Foo.NamespaceA.InnerClassA"_s,
+ u"Foo.NamespaceB"_s, u"Foo.EnumB"_s,
+ u"Foo.funcB()"_s,
+ u"Foo.NamespaceA.InnerNamespaceA"_s};
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false,
+ QString(), droppedEntries));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(AbstractMetaClass::findClass(classes, "ValueA"));
+ QVERIFY(!AbstractMetaClass::findClass(classes, "ValueB"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "ObjectA"));
+ QVERIFY(!AbstractMetaClass::findClass(classes, "ObjectB"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceA"));
+ QVERIFY(!AbstractMetaClass::findClass(classes, "NamespaceA::InnerClassA"));
+ QVERIFY(!AbstractMetaClass::findClass(classes, "NamespaceB"));
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.size(), 1);
+ QCOMPARE(globalEnums.constFirst().name(), u"EnumA");
+
+ auto *td = TypeDatabase::instance();
+ QVERIFY(td->findType(u"funcA"_s));
+ QVERIFY(!td->findType(u"funcB"_s));
+}
+
+void TestDropTypeEntries::testDontDropEntries()
+{
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(AbstractMetaClass::findClass(classes, "ValueA"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "ValueB"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "ObjectA"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "ObjectB"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceA"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceA::InnerClassA"));
+ QVERIFY(AbstractMetaClass::findClass(classes, "NamespaceB"));
+
+ QCOMPARE(builder->globalEnums().size(), 2);
+
+ auto *td = TypeDatabase::instance();
+ QVERIFY(td->findType(u"funcA"_s));
+ QVERIFY(td->findType(u"funcB"_s));
+}
+
+static const char cppCode2[] = "\
+ struct ValueA {\n\
+ void func();\n\
+ };\n";
+
+static const char xmlCode2[] = R"(
+<typesystem package='Foo'>
+ <value-type name='ValueA'>
+ <modify-function signature='func()' remove='all'/>
+ </value-type>
+</typesystem>
+)";
+
+void TestDropTypeEntries::testDropEntryWithChildTags()
+{
+ QStringList droppedEntries(u"Foo.ValueA"_s);
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false,
+ QString(), droppedEntries));
+ QVERIFY(builder);
+ QVERIFY(!AbstractMetaClass::findClass(builder->classes(), "ValueA"));
+}
+
+
+void TestDropTypeEntries::testDontDropEntryWithChildTags()
+{
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode2, xmlCode2, false));
+ QVERIFY(builder);
+ QVERIFY(AbstractMetaClass::findClass(builder->classes(), "ValueA"));
+}
+
+void TestDropTypeEntries::testConditionalParsing_data()
+{
+ const QString xml = R"(<?xml version="1.0" encoding="UTF-8"?>
+<root>
+ <tag1>text</tag1>
+ <?if keyword1?>
+ <tag2>text</tag2>
+ <?if keyword2?>
+ <tag3>text</tag3>
+ <?endif?>
+ <?if keyword1 !keyword2?>
+ <tag4>text</tag4>
+ <?endif?>
+ <?endif?>
+ <tag5>text</tag5>
+ <?if !keyword99?> <!-- Exclusion only -->
+ <tag6>text</tag6>
+ <?endif?>
+</root>)"_L1;
+
+ constexpr auto root = "root"_L1;
+ constexpr auto tag1 = "tag1"_L1;
+ constexpr auto tag2 = "tag2"_L1;
+ constexpr auto tag3 = "tag3"_L1;
+ constexpr auto tag4 = "tag4"_L1;
+ constexpr auto tag5 = "tag5"_L1;
+ constexpr auto tag6 = "tag6"_L1;
+ constexpr auto keyword1 = "keyword1"_L1;
+ constexpr auto keyword2 = "keyword2"_L1;
+
+ QTest::addColumn<QString>("xml");
+ QTest::addColumn<QStringList>("keywords");
+ QTest::addColumn<QStringList>("expectedTags");
+
+ QTest::newRow("no-keywords")
+ << xml << QStringList{} << QStringList{root, tag1, tag5, tag6};
+
+ QTest::newRow("skip-nested-condition")
+ << xml << QStringList{keyword1}
+ << QStringList{root, tag1, tag2, tag4, tag5, tag6};
+
+ QTest::newRow("both/check-not")
+ << xml << QStringList{keyword1, keyword2}
+ << QStringList{root, tag1, tag2, tag3, tag5, tag6};
+}
+
+// Parse XML and return a list of tags encountered
+static QStringList parseXml(const QString &xml, const QStringList &keywords)
+{
+ QStringList tags;
+ ConditionalStreamReader reader(xml);
+ reader.setConditions(keywords);
+ while (!reader.atEnd()) {
+ auto t = reader.readNext();
+ switch (t) {
+ case QXmlStreamReader::StartElement:
+ tags.append(reader.name().toString());
+ break;
+ default:
+ break;
+ }
+ }
+ return tags;
+}
+
+void TestDropTypeEntries::testConditionalParsing()
+{
+ QFETCH(QString, xml);
+ QFETCH(QStringList, keywords);
+ QFETCH(QStringList, expectedTags);
+
+ const QStringList actualTags = parseXml(xml, keywords);
+ QCOMPARE(actualTags, expectedTags);
+}
+
+void TestDropTypeEntries::testEntityParsing()
+{
+ const QString xml = R"(<?xml version="1.0" encoding="UTF-8"?>
+<root>
+ <?entity testentity word1 word2?>
+ <text>bla &testentity;</text>
+</root>)"_L1;
+
+ QString actual;
+ ConditionalStreamReader reader(xml);
+ while (!reader.atEnd()) {
+ auto t = reader.readNext();
+ switch (t) {
+ case QXmlStreamReader::Characters:
+ actual.append(reader.text());
+ default:
+ break;
+ }
+ }
+ QVERIFY2(!reader.hasError(), qPrintable(reader.errorString()));
+ QCOMPARE(actual.trimmed(), u"bla word1 word2");
+}
+
+QTEST_APPLESS_MAIN(TestDropTypeEntries)
diff --git a/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.h b/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.h
new file mode 100644
index 000000000..98717bd21
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testdroptypeentries.h
@@ -0,0 +1,22 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTDROPTYPEENTRIES_H
+#define TESTDROPTYPEENTRIES_H
+
+#include <QtCore/QObject>
+
+class TestDropTypeEntries : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testDropEntries();
+ void testDontDropEntries();
+ void testDropEntryWithChildTags();
+ void testDontDropEntryWithChildTags();
+ void testConditionalParsing_data();
+ void testConditionalParsing();
+ void testEntityParsing();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testdtorinformation.cpp b/sources/shiboken6/ApiExtractor/tests/testdtorinformation.cpp
new file mode 100644
index 000000000..2152d39de
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testdtorinformation.cpp
@@ -0,0 +1,158 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testdtorinformation.h"
+#include "abstractmetabuilder.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestDtorInformation::testDtorIsPrivate()
+{
+ const char cppCode[] = R"(class Control {
+public:
+ ~Control() {}
+};
+class Subject {
+private:
+ ~Subject() {}
+};
+)";
+ const char xmlCode[] = R"(<typesystem package="Foo">
+ <value-type name="Control"/>
+ <value-type name="Subject"/>
+</typesystem>)";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ auto klass = AbstractMetaClass::findClass(classes, "Control");
+ QVERIFY(klass);
+ QVERIFY(!klass->hasPrivateDestructor());
+ klass = AbstractMetaClass::findClass(classes, "Subject");
+ QVERIFY(klass);
+ QVERIFY(klass->hasPrivateDestructor());
+}
+
+void TestDtorInformation::testDtorIsProtected()
+{
+ const char cppCode[] = R"(class Control {
+public:
+ ~Control() {}
+};
+class Subject {
+protected:
+ ~Subject() {}
+};
+)";
+ const char xmlCode[] = R"(<typesystem package="Foo">
+ <value-type name="Control"/>
+ <value-type name="Subject"/>
+</typesystem>)";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ auto klass = AbstractMetaClass::findClass(classes, "Control");
+ QVERIFY(klass);
+ QVERIFY(!klass->hasProtectedDestructor());
+ klass = AbstractMetaClass::findClass(classes, "Subject");
+ QVERIFY(klass);
+ QVERIFY(klass->hasProtectedDestructor());
+}
+
+void TestDtorInformation::testDtorIsVirtual()
+{
+ const char cppCode[] = R"(class Control {
+public:
+ ~Control() {}
+};
+class Subject {
+protected:
+ virtual ~Subject() {}
+};
+)";
+ const char xmlCode[] = R"(<typesystem package="Foo">
+ <value-type name="Control"/>
+ <value-type name="Subject"/>
+</typesystem>)";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ auto klass = AbstractMetaClass::findClass(classes, "Control");
+ QVERIFY(klass);
+ QVERIFY(!klass->hasVirtualDestructor());
+ klass = AbstractMetaClass::findClass(classes, "Subject");
+ QVERIFY(klass);
+ QVERIFY(klass->hasVirtualDestructor());
+}
+
+void TestDtorInformation::testDtorFromBaseIsVirtual()
+{
+ const char cppCode[] = R"CPP(class ControlBase { public: ~ControlBase() {} };
+class Control : public ControlBase {};
+class SubjectBase { public: virtual ~SubjectBase() {} };
+class Subject : public SubjectBase {};
+)CPP";
+ const char xmlCode[] = R"XML(<typesystem package="Foo"><value-type name="ControlBase"/>
+<value-type name="Control"/>"
+<value-type name="SubjectBase"/>"
+<value-type name="Subject"/>
+</typesystem>
+)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 4);
+
+ auto klass = AbstractMetaClass::findClass(classes, "ControlBase");
+ QVERIFY(klass);
+ QVERIFY(!klass->hasVirtualDestructor());
+ klass = AbstractMetaClass::findClass(classes, "Control");
+ QVERIFY(klass);
+ QVERIFY(!klass->hasVirtualDestructor());
+
+ klass = AbstractMetaClass::findClass(classes, "SubjectBase");
+ QVERIFY(klass);
+ QVERIFY(klass->hasVirtualDestructor());
+ klass = AbstractMetaClass::findClass(classes, "Subject");
+ QVERIFY(klass);
+ QVERIFY(klass->hasVirtualDestructor());
+}
+
+void TestDtorInformation::testClassWithVirtualDtorIsPolymorphic()
+{
+ const char cppCode[] = R"(class Control {
+public:
+ virtual ~Control() {}
+};
+class Subject {
+protected:
+ virtual ~Subject() {}
+};
+)";
+ const char xmlCode[] = R"(<typesystem package="Foo">
+ <value-type name="Control"/>
+ <value-type name="Subject"/>
+</typesystem>)";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ auto klass = AbstractMetaClass::findClass(classes, "Control");
+ QVERIFY(klass);
+ QVERIFY(klass->isPolymorphic());
+ klass = AbstractMetaClass::findClass(classes, "Subject");
+ QVERIFY(klass);
+ QVERIFY(klass->isPolymorphic());
+}
+
+QTEST_APPLESS_MAIN(TestDtorInformation)
+
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testdtorinformation.h b/sources/shiboken6/ApiExtractor/tests/testdtorinformation.h
new file mode 100644
index 000000000..0f8cb59b3
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testdtorinformation.h
@@ -0,0 +1,22 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTDTORINFORMATION_H
+#define TESTDTORINFORMATION_H
+
+#include <QtCore/QObject>
+
+class AbstractMetaBuilder;
+
+class TestDtorInformation: public QObject
+{
+ Q_OBJECT
+private slots:
+ void testDtorIsPrivate();
+ void testDtorIsProtected();
+ void testDtorIsVirtual();
+ void testDtorFromBaseIsVirtual();
+ void testClassWithVirtualDtorIsPolymorphic();
+};
+
+#endif // TESTDTORINFORMATION_H
diff --git a/sources/shiboken6/ApiExtractor/tests/testenum.cpp b/sources/shiboken6/ApiExtractor/tests/testenum.cpp
new file mode 100644
index 000000000..c7c2b8b3b
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testenum.cpp
@@ -0,0 +1,577 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testenum.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetaenum.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetabuilder_p.h>
+#include <enumtypeentry.h>
+#include <flagstypeentry.h>
+#include <parser/enumvalue.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestEnum::testEnumCppSignature()
+{
+ const char cppCode[] = "\
+ enum GlobalEnum { A, B };\n\
+ \n\
+ struct A {\n\
+ enum ClassEnum { CA, CB };\n\
+ void method(ClassEnum);\n\
+ };\n\
+ void func(A::ClassEnum);\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <enum-type name='GlobalEnum'/>\n\
+ <value-type name='A'>\n\
+ <enum-type name='ClassEnum'/>\n\
+ </value-type>\n\
+ <function signature='func(A::ClassEnum)'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.size(), 1);
+ QCOMPARE(globalEnums.constFirst().name(), u"GlobalEnum");
+
+ // enum as parameter of a function
+ const auto functions = builder->globalFunctions();
+ QCOMPARE(functions.size(), 1);
+ QCOMPARE(functions.constFirst()->arguments().size(), 1);
+ QCOMPARE(functions.constFirst()->arguments().constFirst().type().cppSignature(),
+ u"A::ClassEnum");
+
+ // enum as parameter of a method
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QCOMPARE(classA->enums().size(), 1);
+ const auto funcs = classA->queryFunctionsByName(u"method"_s);
+ QVERIFY(!funcs.isEmpty());
+ const auto method = funcs.constFirst();
+ AbstractMetaArgument arg = method->arguments().constFirst();
+ QCOMPARE(arg.type().name(), u"ClassEnum");
+ QCOMPARE(arg.type().cppSignature(), u"A::ClassEnum");
+ QCOMPARE(functions.constFirst()->arguments().size(), 1);
+ arg = functions.constFirst()->arguments().constFirst();
+ QCOMPARE(arg.type().name(), u"ClassEnum");
+ QCOMPARE(arg.type().cppSignature(), u"A::ClassEnum");
+
+ AbstractMetaEnumList classEnums = classA->enums();
+ QVERIFY(!classEnums.isEmpty());
+ QCOMPARE(classEnums.constFirst().name(), u"ClassEnum");
+ auto e = AbstractMetaClass::findEnumValue(classes, u"CA"_s);
+ QVERIFY(e.has_value());
+ e = AbstractMetaClass::findEnumValue(classes, u"ClassEnum::CA"_s);
+ QVERIFY(e.has_value());
+}
+
+void TestEnum::testEnumWithApiVersion()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ enum ClassEnum { EnumA, EnumB };\n\
+ enum ClassEnum2 { EnumC, EnumD };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <enum-type name='ClassEnum' since='0.1'/>\n\
+ <enum-type name='ClassEnum2' since='0.2'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ true, u"0.1"_s));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ QCOMPARE(classes[0]->enums().size(), 1);
+}
+
+void TestEnum::testAnonymousEnum()
+{
+ const char cppCode[] = "\
+ enum { Global0, Global1 };\n\
+ struct A {\n\
+ enum { A0, A1 };\n\
+ enum { isThis = true, isThat = false };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <!-- Uses the first value of the enum to identify it. -->\n\
+ <enum-type identified-by-value='Global0'/>\n\
+ <value-type name='A'>\n\
+ <!-- Uses the second value of the enum to identify it. -->\n\
+ <enum-type identified-by-value='A1'/>\n\
+ <enum-type identified-by-value='isThis'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.size(), 1);
+ QCOMPARE(globalEnums.constFirst().typeEntry()->qualifiedCppName(),
+ u"Global0");
+ QVERIFY(globalEnums.constFirst().isAnonymous());
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ QCOMPARE(classes[0]->enums().size(), 2);
+
+ auto anonEnumA1 = classes[0]->findEnum(u"A1"_s);
+ QVERIFY(anonEnumA1.has_value());
+ QVERIFY(anonEnumA1->isAnonymous());
+ QCOMPARE(anonEnumA1->typeEntry()->qualifiedCppName(), u"A::A1");
+
+ AbstractMetaEnumValue enumValueA0 = anonEnumA1->values().constFirst();
+ QCOMPARE(enumValueA0.name(), u"A0");
+ QCOMPARE(enumValueA0.value().value(), 0);
+ QCOMPARE(enumValueA0.stringValue(), QString());
+
+ AbstractMetaEnumValue enumValueA1 = anonEnumA1->values().constLast();
+ QCOMPARE(enumValueA1.name(), u"A1");
+ QCOMPARE(enumValueA1.value().value(), 1);
+ QCOMPARE(enumValueA1.stringValue(), QString());
+
+ auto anonEnumIsThis = classes[0]->findEnum(u"isThis"_s);
+ QVERIFY(anonEnumIsThis.has_value());
+ QVERIFY(anonEnumIsThis->isAnonymous());
+ QCOMPARE(anonEnumIsThis->typeEntry()->qualifiedCppName(), u"A::isThis");
+
+ AbstractMetaEnumValue enumValueIsThis = anonEnumIsThis->values().constFirst();
+ QCOMPARE(enumValueIsThis.name(), u"isThis");
+ QCOMPARE(enumValueIsThis.value().value(), static_cast<int>(true));
+ QCOMPARE(enumValueIsThis.stringValue(), u"true");
+
+ AbstractMetaEnumValue enumValueIsThat = anonEnumIsThis->values().constLast();
+ QCOMPARE(enumValueIsThat.name(), u"isThat");
+ QCOMPARE(enumValueIsThat.value().value(), static_cast<int>(false));
+ QCOMPARE(enumValueIsThat.stringValue(), u"false");
+}
+
+void TestEnum::testGlobalEnums()
+{
+ const char cppCode[] = "\
+ enum EnumA { A0, A1 };\n\
+ enum EnumB { B0 = 2, B1 = 0x4 };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <enum-type name='EnumA'/>\n\
+ <enum-type name='EnumB'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.size(), 2);
+
+ AbstractMetaEnum enumA = globalEnums.constFirst();
+ QCOMPARE(enumA.typeEntry()->qualifiedCppName(), u"EnumA");
+
+ AbstractMetaEnumValue enumValueA0 = enumA.values().constFirst();
+ QCOMPARE(enumValueA0.name(), u"A0");
+ QCOMPARE(enumValueA0.value().value(), 0);
+ QCOMPARE(enumValueA0.stringValue(), QString());
+
+ AbstractMetaEnumValue enumValueA1 = enumA.values().constLast();
+ QCOMPARE(enumValueA1.name(), u"A1");
+ QCOMPARE(enumValueA1.value().value(), 1);
+ QCOMPARE(enumValueA1.stringValue(), QString());
+
+ AbstractMetaEnum enumB = globalEnums.constLast();
+ QCOMPARE(enumB.typeEntry()->qualifiedCppName(), u"EnumB");
+
+ AbstractMetaEnumValue enumValueB0 = enumB.values().constFirst();
+ QCOMPARE(enumValueB0.name(), u"B0");
+ QCOMPARE(enumValueB0.value().value(), 2);
+ QCOMPARE(enumValueB0.stringValue(), u"2");
+
+ AbstractMetaEnumValue enumValueB1 = enumB.values().constLast();
+ QCOMPARE(enumValueB1.name(), u"B1");
+ QCOMPARE(enumValueB1.value().value(), 4);
+ QCOMPARE(enumValueB1.stringValue(), u"0x4");
+}
+
+void TestEnum::testEnumValueFromNeighbourEnum()
+{
+ const char cppCode[] = "\
+ namespace A {\n\
+ enum EnumA { ValueA0, ValueA1 };\n\
+ enum EnumB { ValueB0 = A::ValueA1, ValueB1 = ValueA0 };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <namespace-type name='A'>\n\
+ <enum-type name='EnumA'/>\n\
+ <enum-type name='EnumB'/>\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ QCOMPARE(classes[0]->enums().size(), 2);
+
+ auto enumA = classes[0]->findEnum(u"EnumA"_s);
+ QVERIFY(enumA.has_value());
+ QCOMPARE(enumA->typeEntry()->qualifiedCppName(), u"A::EnumA");
+
+ AbstractMetaEnumValue enumValueA0 = enumA->values().constFirst();
+ QCOMPARE(enumValueA0.name(), u"ValueA0");
+ QCOMPARE(enumValueA0.value().value(), 0);
+ QCOMPARE(enumValueA0.stringValue(), QString());
+
+ AbstractMetaEnumValue enumValueA1 = enumA->values().constLast();
+ QCOMPARE(enumValueA1.name(), u"ValueA1");
+ QCOMPARE(enumValueA1.value().value(), 1);
+ QCOMPARE(enumValueA1.stringValue(), QString());
+
+ auto enumB = classes[0]->findEnum(u"EnumB"_s);
+ QVERIFY(enumB.has_value());
+ QCOMPARE(enumB->typeEntry()->qualifiedCppName(), u"A::EnumB");
+
+ AbstractMetaEnumValue enumValueB0 = enumB->values().constFirst();
+ QCOMPARE(enumValueB0.name(), u"ValueB0");
+ QCOMPARE(enumValueB0.value().value(), 1);
+ QCOMPARE(enumValueB0.stringValue(), u"A::ValueA1");
+
+ AbstractMetaEnumValue enumValueB1 = enumB->values().constLast();
+ QCOMPARE(enumValueB1.name(), u"ValueB1");
+ QCOMPARE(enumValueB1.value().value(), 0);
+ QCOMPARE(enumValueB1.stringValue(), u"ValueA0");
+}
+
+void TestEnum::testEnumValueFromExpression()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ enum EnumA : unsigned {\n\
+ ValueA0 = 3u,\n\
+ ValueA1 = ~3u,\n\
+ ValueA2 = 0xffffffff,\n\
+ ValueA3 = 0xf0,\n\
+ ValueA4 = 8 |ValueA3,\n\
+ ValueA5 = ValueA3|32,\n\
+ ValueA6 = ValueA3 >> 1,\n\
+ ValueA7 = ValueA3 << 1\n\
+ };\n\
+ enum EnumB : int {\n\
+ ValueB0 = ~3,\n\
+ };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <enum-type name='EnumA'/>\n\
+ <enum-type name='EnumB'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaClassPtr classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+
+ auto enumA = classA->findEnum(u"EnumA"_s);
+ QVERIFY(enumA.has_value());
+ QVERIFY(!enumA->isSigned());
+ QCOMPARE(enumA->typeEntry()->qualifiedCppName(), u"A::EnumA");
+
+ AbstractMetaEnumValue valueA0 = enumA->values().at(0);
+ QCOMPARE(valueA0.name(), u"ValueA0");
+ QCOMPARE(valueA0.stringValue(), u"3u");
+ QCOMPARE(valueA0.value().unsignedValue(), 3u);
+
+ AbstractMetaEnumValue valueA1 = enumA->values().at(1);
+ QCOMPARE(valueA1.name(), u"ValueA1");
+ QCOMPARE(valueA1.stringValue(), u"~3u");
+ QCOMPARE(valueA1.value().unsignedValue(), ~3u);
+
+ AbstractMetaEnumValue valueA2 = enumA->values().at(2);
+ QCOMPARE(valueA2.name(), u"ValueA2");
+ QCOMPARE(valueA2.stringValue(), u"0xffffffff");
+ QCOMPARE(valueA2.value().unsignedValue(), 0xffffffffu);
+
+ AbstractMetaEnumValue valueA3 = enumA->values().at(3);
+ QCOMPARE(valueA3.name(), u"ValueA3");
+ QCOMPARE(valueA3.stringValue(), u"0xf0");
+ QCOMPARE(valueA3.value().unsignedValue(), 0xf0u);
+
+ AbstractMetaEnumValue valueA4 = enumA->values().at(4);
+ QCOMPARE(valueA4.name(), u"ValueA4");
+ QCOMPARE(valueA4.stringValue(), u"8 |ValueA3");
+ QCOMPARE(valueA4.value().unsignedValue(), 8|0xf0u);
+
+ AbstractMetaEnumValue valueA5 = enumA->values().at(5);
+ QCOMPARE(valueA5.name(), u"ValueA5");
+ QCOMPARE(valueA5.stringValue(), u"ValueA3|32");
+ QCOMPARE(valueA5.value().unsignedValue(), 0xf0u|32);
+
+ AbstractMetaEnumValue valueA6 = enumA->values().at(6);
+ QCOMPARE(valueA6.name(), u"ValueA6");
+ QCOMPARE(valueA6.stringValue(), u"ValueA3 >> 1");
+ QCOMPARE(valueA6.value().unsignedValue(), 0xf0u >> 1);
+
+ AbstractMetaEnumValue valueA7 = enumA->values().at(7);
+ QCOMPARE(valueA7.name(), u"ValueA7");
+ QCOMPARE(valueA7.stringValue(), u"ValueA3 << 1");
+ QCOMPARE(valueA7.value().unsignedValue(), 0xf0u << 1);
+
+ const auto enumB = classA->findEnum(u"EnumB"_s);
+ QVERIFY(enumB.has_value());
+ QVERIFY(enumB->isSigned());
+ QCOMPARE(enumB->typeEntry()->qualifiedCppName(), u"A::EnumB");
+ QCOMPARE(enumB->values().size(), 1);
+ const AbstractMetaEnumValue valueB0 = enumB->values().at(0);
+ QCOMPARE(valueB0.name(), u"ValueB0");
+ QCOMPARE(valueB0.stringValue(), u"~3");
+ QCOMPARE(valueB0.value().value(), ~3);
+}
+
+void TestEnum::testPrivateEnum()
+{
+ const char cppCode[] = "\
+ class A {\n\
+ private:\n\
+ enum PrivateEnum { Priv0 = 0x0f, Priv1 = 0xf0 };\n\
+ public:\n\
+ enum PublicEnum { Pub0 = Priv0, Pub1 = A::Priv1 };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'>\n\
+ <enum-type name='PublicEnum'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->enums().size(), 2);
+
+ auto privateEnum = classA->findEnum(u"PrivateEnum"_s);
+ QVERIFY(privateEnum.has_value());
+ QVERIFY(privateEnum->isPrivate());
+ QCOMPARE(privateEnum->typeEntry()->qualifiedCppName(), u"A::PrivateEnum");
+
+ auto publicEnum = classA->findEnum(u"PublicEnum"_s);
+ QVERIFY(publicEnum.has_value());
+ QCOMPARE(publicEnum->typeEntry()->qualifiedCppName(), u"A::PublicEnum");
+
+ AbstractMetaEnumValue pub0 = publicEnum->values().constFirst();
+ QCOMPARE(pub0.name(), u"Pub0");
+ QCOMPARE(pub0.value().value(), 0x0f);
+ QCOMPARE(pub0.stringValue(), u"Priv0");
+
+ AbstractMetaEnumValue pub1 = publicEnum->values().constLast();
+ QCOMPARE(pub1.name(), u"Pub1");
+ QCOMPARE(pub1.value().value(), 0xf0);
+ QCOMPARE(pub1.stringValue(), u"A::Priv1");
+}
+
+void TestEnum::testTypedefEnum()
+{
+ const char cppCode[] = "\
+ typedef enum EnumA {\n\
+ A0,\n\
+ A1,\n\
+ } EnumA;\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <enum-type name='EnumA'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaEnumList globalEnums = builder->globalEnums();
+ QCOMPARE(globalEnums.size(), 1);
+
+ AbstractMetaEnum enumA = globalEnums.constFirst();
+ QCOMPARE(enumA.typeEntry()->qualifiedCppName(), u"EnumA");
+
+ AbstractMetaEnumValue enumValueA0 = enumA.values().constFirst();
+ QCOMPARE(enumValueA0.name(), u"A0");
+ QCOMPARE(enumValueA0.value().value(), 0);
+ QCOMPARE(enumValueA0.stringValue(), u"");
+
+ AbstractMetaEnumValue enumValueA1 = enumA.values().constLast();
+ QCOMPARE(enumValueA1.name(), u"A1");
+ QCOMPARE(enumValueA1.value().value(), 1);
+ QCOMPARE(enumValueA1.stringValue(), QString());
+}
+
+// Helper classes and functions for testing enum default value fixing.
+// Put the AbstractMetaBuilder into test fixture struct to avoid having
+// to re-parse for each data row.
+
+struct EnumDefaultValuesFixture
+{
+ std::shared_ptr<AbstractMetaBuilder> builder;
+
+ AbstractMetaType globalEnum;
+ AbstractMetaType testEnum;
+ AbstractMetaType testOptions;
+};
+
+Q_DECLARE_METATYPE(EnumDefaultValuesFixture)
+Q_DECLARE_METATYPE(AbstractMetaType)
+
+static int populateDefaultValuesFixture(EnumDefaultValuesFixture *fixture)
+{
+ static const char cppCode[] =R"(
+enum GlobalEnum { GE1, GE2 };
+namespace Test1
+{
+namespace Test2
+{
+ enum Enum1 { E1, E2 };
+ enum Option { O1, O2 };
+} // namespace Test2
+} // namespace Test1
+)";
+ static const char xmlCode[] = R"(
+<typesystem package="Foo">
+ <enum-type name='GlobalEnum'/>
+ <namespace-type name='Test1'>
+ <namespace-type name='Test2'>
+ <enum-type name='Enum1'/>
+ <enum-type name='Option' flags='Options'/>
+ </namespace-type>
+ </namespace-type>
+</typesystem>
+)";
+
+ fixture->builder.reset(TestUtil::parse(cppCode, xmlCode, false));
+ if (!fixture->builder)
+ return -1;
+
+ const auto globalEnums = fixture->builder->globalEnums();
+ if (globalEnums.size() != 1)
+ return -2;
+
+ fixture->globalEnum = AbstractMetaType(globalEnums.constFirst().typeEntry());
+ fixture->globalEnum.decideUsagePattern();
+
+ AbstractMetaClassCPtr testNamespace;
+ for (const auto &c : fixture->builder->classes()) {
+ if (c->name() == u"Test2") {
+ testNamespace = c;
+ break;
+ }
+ }
+ if (!testNamespace)
+ return -3;
+
+ const auto namespaceEnums = testNamespace->enums();
+ if (namespaceEnums.size() != 2)
+ return -4;
+ QList<EnumTypeEntryCPtr > enumTypeEntries{
+ std::static_pointer_cast<const EnumTypeEntry>(namespaceEnums.at(0).typeEntry()),
+ std::static_pointer_cast<const EnumTypeEntry>(namespaceEnums.at(1).typeEntry())};
+ if (enumTypeEntries.constFirst()->flags())
+ std::swap(enumTypeEntries[0], enumTypeEntries[1]);
+ fixture->testEnum = AbstractMetaType(enumTypeEntries.at(0));
+ fixture->testEnum.decideUsagePattern();
+ fixture->testOptions = AbstractMetaType(enumTypeEntries.at(1)->flags());
+ fixture->testOptions.decideUsagePattern();
+ return 0;
+}
+
+void TestEnum::testEnumDefaultValues_data()
+{
+ EnumDefaultValuesFixture fixture;
+ const int setupOk = populateDefaultValuesFixture(&fixture);
+
+ QTest::addColumn<EnumDefaultValuesFixture>("fixture");
+ QTest::addColumn<int>("setupOk"); // To verify setup
+ QTest::addColumn<AbstractMetaType>("metaType"); // Type and parameters for fixup
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<QString>("expected");
+
+ // Global should just remain unmodified
+ QTest::newRow("global") << fixture << setupOk
+ << fixture.globalEnum << "GE1" << "GE1";
+ QTest::newRow("global-int") << fixture << setupOk
+ << fixture.globalEnum << "42" << "42";
+ QTest::newRow("global-hex-int") << fixture << setupOk
+ << fixture.globalEnum << "0x10" << "0x10";
+ QTest::newRow("global-int-cast") << fixture << setupOk
+ << fixture.globalEnum << "GlobalEnum(-1)" << "GlobalEnum(-1)";
+
+ // Namespaced enum as number should remain unmodified
+ QTest::newRow("namespace-enum-int") << fixture << setupOk
+ << fixture.testEnum << "42" << "42";
+ QTest::newRow("namespace-enum-hex-int") << fixture << setupOk
+ << fixture.testEnum << "0x10" << "0x10";
+ // Partial qualification of namespaced enum
+ QTest::newRow("namespace-enum-qualified") << fixture << setupOk
+ << fixture.testEnum << "Enum1::E1" << "Test1::Test2::Enum1::E1";
+ // Unqualified namespaced enums
+ QTest::newRow("namespace-enum-unqualified") << fixture << setupOk
+ << fixture.testEnum << "E1" << "Test1::Test2::Enum1::E1";
+ // Namespaced enums cast from int should be qualified by scope
+ QTest::newRow("namespace-enum-int-cast") << fixture << setupOk
+ << fixture.testEnum << "Enum1(-1)" << "Test1::Test2::Enum1(-1)";
+
+ // Namespaced option as number should remain unmodified
+ QTest::newRow("namespace-option-int") << fixture << setupOk
+ << fixture.testOptions << "0x10" << "0x10";
+ QTest::newRow("namespace-option-expression") << fixture << setupOk
+ << fixture.testOptions << "0x10 | 0x20" << "0x10 | 0x20";
+ QTest::newRow("namespace-option-expression1") << fixture << setupOk
+ << fixture.testOptions << "0x10 | Test1::Test2::Option::O1"
+ << "0x10 | Test1::Test2::Option::O1";
+ QTest::newRow("namespace-option-expression2") << fixture << setupOk
+ << fixture.testOptions << "0x10 | O1" << "0x10 | Test1::Test2::Option::O1";
+ // Complicated expressions - should remain unmodified
+ QTest::newRow("namespace-option-expression-paren") << fixture << setupOk
+ << fixture.testOptions << "0x10 | (0x20 | 0x40 | O1)"
+ << "0x10 | (0x20 | 0x40 | O1)";
+
+ // Option: Cast Enum from int should be qualified
+ QTest::newRow("namespace-option-int-cast") << fixture << setupOk
+ << fixture.testOptions << "Option(0x10)" << "Test1::Test2::Option(0x10)";
+ // Option: Cast Flags from int should be qualified
+ QTest::newRow("namespace-options-int-cast") << fixture << setupOk
+ << fixture.testOptions << "Options(0x10 | 0x20)" << "Test1::Test2::Options(0x10 | 0x20)";
+ QTest::newRow("namespace-option-cast-expression1") << fixture << setupOk
+ << fixture.testOptions << "Test1::Test2::Options(0x10 | Test1::Test2::Option::O1)"
+ << "Test1::Test2::Options(0x10 | Test1::Test2::Option::O1)";
+ QTest::newRow("namespace-option-cast-expression2") << fixture << setupOk
+ << fixture.testOptions << "Options(0x10 | O1)"
+ << "Test1::Test2::Options(0x10 | Test1::Test2::Option::O1)";
+}
+
+void TestEnum::testEnumDefaultValues()
+{
+ QFETCH(EnumDefaultValuesFixture, fixture);
+ QFETCH(int, setupOk);
+ QFETCH(AbstractMetaType, metaType);
+ QFETCH(QString, input);
+ QFETCH(QString, expected);
+ QCOMPARE(setupOk, 0);
+ const QString actual = fixture.builder->fixEnumDefault(metaType, input);
+ QCOMPARE(actual, expected);
+}
+
+QTEST_APPLESS_MAIN(TestEnum)
diff --git a/sources/shiboken6/ApiExtractor/tests/testenum.h b/sources/shiboken6/ApiExtractor/tests/testenum.h
new file mode 100644
index 000000000..452755490
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testenum.h
@@ -0,0 +1,25 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTENUM_H
+#define TESTENUM_H
+
+#include <QtCore/QObject>
+
+class TestEnum : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testEnumCppSignature();
+ void testEnumWithApiVersion();
+ void testAnonymousEnum();
+ void testGlobalEnums();
+ void testEnumValueFromNeighbourEnum();
+ void testEnumValueFromExpression();
+ void testPrivateEnum();
+ void testTypedefEnum();
+ void testEnumDefaultValues_data();
+ void testEnumDefaultValues();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testextrainclude.cpp b/sources/shiboken6/ApiExtractor/tests/testextrainclude.cpp
new file mode 100644
index 000000000..fcc409a42
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testextrainclude.cpp
@@ -0,0 +1,62 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testextrainclude.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <complextypeentry.h>
+#include <typesystemtypeentry.h>
+
+void TestExtraInclude::testClassExtraInclude()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'>\n\
+ <extra-includes>\n\
+ <include file-name='header.h' location='global'/>\n\
+ </extra-includes>\n\
+ </value-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+
+ QList<Include> includes = classA->typeEntry()->extraIncludes();
+ QCOMPARE(includes.size(), 1);
+ QCOMPARE(includes.constFirst().name(), u"header.h");
+}
+
+void TestExtraInclude::testGlobalExtraIncludes()
+{
+ const char cppCode[] = "struct A {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <extra-includes>\n\
+ <include file-name='header1.h' location='global'/>\n\
+ <include file-name='header2.h' location='global'/>\n\
+ </extra-includes>\n\
+ <value-type name='A'/>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(AbstractMetaClass::findClass(classes, "A"));
+
+ auto *td = TypeDatabase::instance();
+ TypeSystemTypeEntryCPtr module = td->defaultTypeSystemType();
+ QVERIFY(module);
+ QCOMPARE(module->name(), u"Foo");
+
+ QList<Include> includes = module->extraIncludes();
+ QCOMPARE(includes.size(), 2);
+ QCOMPARE(includes.constFirst().name(), u"header1.h");
+ QCOMPARE(includes.constLast().name(), u"header2.h");
+}
+
+QTEST_APPLESS_MAIN(TestExtraInclude)
diff --git a/sources/shiboken6/ApiExtractor/tests/testextrainclude.h b/sources/shiboken6/ApiExtractor/tests/testextrainclude.h
new file mode 100644
index 000000000..6bcb57993
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testextrainclude.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTEXTRAINCLUDE_H
+#define TESTEXTRAINCLUDE_H
+
+#include <QtCore/QObject>
+
+class TestExtraInclude : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testClassExtraInclude();
+ void testGlobalExtraIncludes();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testfunctiontag.cpp b/sources/shiboken6/ApiExtractor/tests/testfunctiontag.cpp
new file mode 100644
index 000000000..18eaf5774
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testfunctiontag.cpp
@@ -0,0 +1,79 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testfunctiontag.h"
+#include "testutil.h"
+#include <abstractmetafunction.h>
+#include <modifications.h>
+#include <typesystem.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestFunctionTag::testFunctionTagForSpecificSignature()
+{
+ const char cppCode[] = "void globalFunction(int); void globalFunction(float); void dummy();\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='float'/>\n\
+ <function signature='globalFunction(int)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ TypeEntryCPtr func = TypeDatabase::instance()->findType(u"globalFunction"_s);
+ QVERIFY(func);
+ QCOMPARE(builder->globalFunctions().size(), 1);
+}
+
+void TestFunctionTag::testFunctionTagForAllSignatures()
+{
+ const char cppCode[] = "void globalFunction(int); void globalFunction(float); void dummy();\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='float'/>\n\
+ <function signature='globalFunction(int)'/>\n\
+ <function signature='globalFunction(float)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ TypeEntryCPtr func = TypeDatabase::instance()->findType(u"globalFunction"_s);
+ QVERIFY(func);
+ QCOMPARE(builder->globalFunctions().size(), 2);
+}
+
+void TestFunctionTag::testRenameGlobalFunction()
+{
+ const char cppCode[] = "void global_function_with_ugly_name();\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <function signature='global_function_with_ugly_name()' rename='smooth'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ TypeEntryCPtr func = TypeDatabase::instance()->findType(u"global_function_with_ugly_name"_s);
+ QVERIFY(func);
+
+ QCOMPARE(builder->globalFunctions().size(), 1);
+ const auto metaFunc = builder->globalFunctions().constFirst();
+
+ QVERIFY(metaFunc);
+ QCOMPARE(metaFunc->modifications().size(), 1);
+ QVERIFY(metaFunc->modifications().constFirst().isRenameModifier());
+ QCOMPARE(metaFunc->modifications().constFirst().renamedToName(),
+ u"smooth");
+
+ QCOMPARE(metaFunc->name(), u"smooth");
+ QCOMPARE(metaFunc->originalName(), u"global_function_with_ugly_name");
+ QCOMPARE(metaFunc->minimalSignature(), u"global_function_with_ugly_name()");
+}
+
+QTEST_APPLESS_MAIN(TestFunctionTag)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testfunctiontag.h b/sources/shiboken6/ApiExtractor/tests/testfunctiontag.h
new file mode 100644
index 000000000..7c60cb4e0
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testfunctiontag.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTFUNCTIONTAG_H
+#define TESTFUNCTIONTAG_H
+
+#include <QtCore/QObject>
+
+class TestFunctionTag : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testFunctionTagForSpecificSignature();
+ void testFunctionTagForAllSignatures();
+ void testRenameGlobalFunction();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.cpp b/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.cpp
new file mode 100644
index 000000000..899d00ad4
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.cpp
@@ -0,0 +1,142 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testimplicitconversions.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <complextypeentry.h>
+#include <QtTest/QTest>
+
+void TestImplicitConversions::testWithPrivateCtors()
+{
+ const char cppCode[] = "\
+ class B;\n\
+ class C;\n\
+ class A {\n\
+ A(const B&);\n\
+ public:\n\
+ A(const C&);\n\
+ };\n\
+ class B {};\n\
+ class C {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ <value-type name='C'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 3);
+
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classC = AbstractMetaClass::findClass(classes, "C");
+ const auto implicitConvs = classA->implicitConversions();
+ QCOMPARE(implicitConvs.size(), 1);
+ QCOMPARE(implicitConvs.constFirst()->arguments().constFirst().type().typeEntry(),
+ classC->typeEntry());
+}
+
+void TestImplicitConversions::testWithModifiedVisibility()
+{
+ const char cppCode[] = "\
+ class B;\n\
+ class A {\n\
+ public:\n\
+ A(const B&);\n\
+ };\n\
+ class B {};\n";
+ const char xmlCode[] = R"(
+<typesystem package='Foo'>
+ <value-type name='A'>
+ <modify-function signature='A(const B&amp;)' access='private'/>
+ </value-type>
+ <value-type name='B'/>
+</typesystem>
+)";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ const auto implicitConvs = classA->implicitConversions();
+ QCOMPARE(implicitConvs.size(), 1);
+ QCOMPARE(implicitConvs.constFirst()->arguments().constFirst().type().typeEntry(),
+ classB->typeEntry());
+}
+
+
+void TestImplicitConversions::testWithAddedCtor()
+{
+ const char cppCode[] = "\
+ class B;\n\
+ class A {\n\
+ public:\n\
+ A(const B&);\n\
+ };\n\
+ class B {};\n\
+ class C {};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <custom-type name='TARGETLANGTYPE'/>\n\
+ <value-type name='A'>\n\
+ <add-function signature='A(const C&amp;)'/>\n\
+ </value-type>\n\
+ <value-type name='B'>\n\
+ <add-function signature='B(TARGETLANGTYPE*)'/>\n\
+ </value-type>\n\
+ <value-type name='C'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 3);
+
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ auto implicitConvs = classA->implicitConversions();
+ QCOMPARE(implicitConvs.size(), 2);
+
+ // Added constructors with custom types should never result in implicit converters.
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ implicitConvs = classB->implicitConversions();
+ QCOMPARE(implicitConvs.size(), 0);
+}
+
+void TestImplicitConversions::testWithExternalConversionOperator()
+{
+ const char cppCode[] = "\
+ class A {};\n\
+ struct B {\n\
+ operator A() const;\n\
+ };\n";
+ const char xmlCode[] = "\n\
+ <typesystem package='Foo'>\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ const auto implicitConvs = classA->implicitConversions();
+ QCOMPARE(implicitConvs.size(), 1);
+ const auto &externalConvOps = classA->externalConversionOperators();
+ QCOMPARE(externalConvOps.size(), 1);
+
+ AbstractMetaFunctionCPtr convOp;
+ for (const auto &func : classB->functions()) {
+ if (func->isConversionOperator())
+ convOp = func;
+ }
+ QVERIFY(convOp);
+ QCOMPARE(implicitConvs.constFirst(), convOp);
+}
+
+QTEST_APPLESS_MAIN(TestImplicitConversions)
diff --git a/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.h b/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.h
new file mode 100644
index 000000000..e0678c5f5
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testimplicitconversions.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTIMPLICITCONVERSIONS_H
+#define TESTIMPLICITCONVERSIONS_H
+
+#include <QtCore/QObject>
+
+class AbstractMetaBuilder;
+
+class TestImplicitConversions : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testWithPrivateCtors();
+ void testWithModifiedVisibility();
+ void testWithAddedCtor();
+ void testWithExternalConversionOperator();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testinserttemplate.cpp b/sources/shiboken6/ApiExtractor/tests/testinserttemplate.cpp
new file mode 100644
index 000000000..23cf0f9ea
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testinserttemplate.cpp
@@ -0,0 +1,63 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testinserttemplate.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <codesnip.h>
+#include <modifications.h>
+#include <complextypeentry.h>
+#include <typesystemtypeentry.h>
+
+void TestInsertTemplate::testInsertTemplateOnClassInjectCode()
+{
+ const char cppCode[] = "struct A{};\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <template name='code_template'>\n\
+ code template content\n\
+ </template>\n\
+ <value-type name='A'>\n\
+ <inject-code class='native'>\n\
+ <insert-template name='code_template'/>\n\
+ </inject-code>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->typeEntry()->codeSnips().size(), 1);
+ QString code = classA->typeEntry()->codeSnips().constFirst().code();
+ QVERIFY(code.contains(u"code template content"));
+}
+
+void TestInsertTemplate::testInsertTemplateOnModuleInjectCode()
+{
+ const char cppCode[] = "";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <template name='code_template'>\n\
+ code template content\n\
+ </template>\n\
+ <inject-code class='native'>\n\
+ <insert-template name='code_template'/>\n\
+ </inject-code>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QVERIFY(classes.isEmpty());
+
+ TypeSystemTypeEntryCPtr module = TypeDatabase::instance()->defaultTypeSystemType();
+ QVERIFY(module);
+ QCOMPARE(module->name(), u"Foo");
+ QCOMPARE(module->codeSnips().size(), 1);
+ QString code = module->codeSnips().constFirst().code().trimmed();
+ QVERIFY(code.contains(u"code template content"));
+}
+
+QTEST_APPLESS_MAIN(TestInsertTemplate)
diff --git a/sources/shiboken6/ApiExtractor/tests/testinserttemplate.h b/sources/shiboken6/ApiExtractor/tests/testinserttemplate.h
new file mode 100644
index 000000000..f4f67abc0
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testinserttemplate.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTINSERTTEMPLATE_H
+#define TESTINSERTTEMPLATE_H
+
+#include <QtCore/QObject>
+
+class TestInsertTemplate : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testInsertTemplateOnClassInjectCode();
+ void testInsertTemplateOnModuleInjectCode();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp
new file mode 100644
index 000000000..9cf2e0cc7
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.cpp
@@ -0,0 +1,117 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testmodifydocumentation.h"
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <abstractmetafunction.h>
+#include <documentation.h>
+#include <modifications.h>
+#include <complextypeentry.h>
+#include <qtdocparser.h>
+
+#include <qtcompat.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTemporaryDir>
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestModifyDocumentation::testModifyDocumentation()
+{
+ const char cppCode[] = "struct B { void b(); }; class A {};\n";
+ const char xmlCode[] =
+R"(<typesystem package="Foo">
+ <value-type name='B'>
+ <modify-function signature='b()' remove='all'/>
+ </value-type>
+ <value-type name='A'>
+ <modify-documentation xpath='description/brief'>&lt;brief>Modified Brief&lt;/brief></modify-documentation>
+ <modify-documentation xpath='description/para[3]'>&lt;para>Some changed contents here&lt;/para></modify-documentation>
+ </value-type>
+</typesystem>
+)";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+ DocModificationList docMods = classA->typeEntry()->docModifications();
+ QCOMPARE(docMods.size(), 2);
+ QCOMPARE(docMods[0].code().trimmed(), u"<brief>Modified Brief</brief>");
+ QCOMPARE(docMods[0].signature(), QString());
+ QCOMPARE(docMods[1].code().trimmed(), u"<para>Some changed contents here</para>");
+ QCOMPARE(docMods[1].signature(), QString());
+
+ // Create a temporary directory for the documentation file since libxml2
+ // cannot handle Qt resources.
+ QTemporaryDir tempDir(QDir::tempPath() + u"/shiboken_testmodifydocXXXXXX"_s);
+ QVERIFY2(tempDir.isValid(), qPrintable(tempDir.errorString()));
+ constexpr auto docFileName = "a.xml"_L1;
+ QVERIFY(QFile::copy(u":/"_s + docFileName, tempDir.filePath(docFileName)));
+
+ QtDocParser docParser;
+ docParser.setDocumentationDataDirectory(tempDir.path());
+ docParser.fillDocumentation(classA);
+
+ const Documentation &doc = classA->documentation();
+ const QString actualDocSimplified = doc.detailed().simplified();
+ const QString actualBriefSimplified = doc.brief().simplified();
+ QVERIFY(!actualDocSimplified.isEmpty());
+
+const char expectedDoc[] =
+R"(<?xml version="1.0"?>
+<description>oi
+<para>Paragraph number 1</para>
+<para>Paragraph number 2</para>
+<para>Some changed contents here</para>
+</description>
+)";
+ const QString expectedDocSimplified = QString::fromLatin1(expectedDoc).simplified();
+ // Check whether the first modification worked.
+ QVERIFY(actualBriefSimplified.contains(u"Modified Brief"));
+
+#ifndef HAVE_LIBXSLT
+ // QtXmlPatterns is unable to handle para[3] in style sheets,
+ // this only works in its XPath search.
+ QEXPECT_FAIL("", "QtXmlPatterns cannot handle para[3] (QTBUG-66925)", Abort);
+#endif
+ QCOMPARE(actualDocSimplified, expectedDocSimplified);
+}
+
+void TestModifyDocumentation::testInjectAddedFunctionDocumentation()
+{
+ const char cppCode[] ="class A {};\n";
+ const char xmlCode[] = R"XML(
+<typesystem package="Foo">
+ <value-type name='A'>
+ <add-function signature="foo(int@parameter_name@)">
+ <inject-documentation format="target" mode="append">
+ Injected documentation of added function foo.
+ </inject-documentation>
+ </add-function>
+ </value-type>
+</typesystem>
+)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+ const auto f = classA->findFunction("foo");
+ QVERIFY(f);
+ QVERIFY(f->isUserAdded());
+ auto docMods = f->addedFunctionDocModifications();
+ QCOMPARE(docMods.size(), 1);
+ const QString code = docMods.constFirst().code();
+ QVERIFY(code.contains(u"Injected documentation of added function foo."));
+}
+
+// We expand QTEST_MAIN macro but using QCoreApplication instead of QApplication
+// because this test needs an event loop but can't use QApplication to avoid a crash
+// on our ARMEL/FRAMANTLE buildbot
+int main(int argc, char** argv)
+{
+ QCoreApplication app(argc, argv);
+ TestModifyDocumentation tc;
+ return QTest::qExec(&tc, argc, argv);
+}
diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.h b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.h
new file mode 100644
index 000000000..c1cc8f480
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTMODIFYDOCUMENTATION_H
+#define TESTMODIFYDOCUMENTATION_H
+
+#include <QtCore/QObject>
+
+class TestModifyDocumentation : public QObject
+{
+Q_OBJECT
+private slots:
+ void testModifyDocumentation();
+ void testInjectAddedFunctionDocumentation();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.qrc b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.qrc
new file mode 100644
index 000000000..76b1bfc61
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmodifydocumentation.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource>
+ <file>a.xml</file>
+ </qresource>
+</RCC>
diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.cpp b/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.cpp
new file mode 100644
index 000000000..a7d40f70a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.cpp
@@ -0,0 +1,480 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testmodifyfunction.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetabuilder_p.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <modifications.h>
+#include <typesystem.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestModifyFunction::testRenameArgument_data()
+{
+ QTest::addColumn<QByteArray>("pattern");
+ QTest::newRow("fixed_string") << QByteArrayLiteral("method(int)");
+ QTest::newRow("regular_expression") << QByteArrayLiteral("^method.*");
+}
+
+void TestModifyFunction::testRenameArgument()
+{
+ QFETCH(QByteArray, pattern);
+
+ const char cppCode[] = "\
+ struct A {\n\
+ void method(int=0);\n\
+ };\n";
+ const char xmlCode1[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <object-type name='A'>\n\
+ <modify-function signature='";
+ const char xmlCode2[] = R"('>
+ <modify-argument index='1' rename='otherArg'/>
+ </modify-function>
+ </object-type>
+ </typesystem>
+)";
+
+ const QByteArray xmlCode = QByteArray(xmlCode1) + pattern + QByteArray(xmlCode2);
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode.constData(), false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ const auto func = classA->findFunction("method");
+ QVERIFY(func);
+
+ QCOMPARE(func->argumentName(1), u"otherArg");
+}
+
+void TestModifyFunction::testOwnershipTransfer()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ virtual A* method();\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A' />\n\
+ <object-type name='B'>\n\
+ <modify-function signature='method()'>\n\
+ <modify-argument index='return'>\n\
+ <define-ownership owner='c++'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ const auto func = classB->findFunction("method");
+ QVERIFY(func);
+
+ QCOMPARE(func->argumentTargetOwnership(func->ownerClass(), 0),
+ TypeSystem::CppOwnership);
+}
+
+
+void TestModifyFunction::invalidateAfterUse()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ virtual void call(int *a);\n\
+ };\n\
+ struct B : A {\n\
+ };\n\
+ struct C : B {\n\
+ virtual void call2(int *a);\n\
+ };\n\
+ struct D : C {\n\
+ virtual void call2(int *a);\n\
+ };\n\
+ struct E : D {\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int'/>\n\
+ <object-type name='A'>\n\
+ <modify-function signature='call(int*)'>\n\
+ <modify-argument index='1' invalidate-after-use='true'/>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ <object-type name='B' />\n\
+ <object-type name='C'>\n\
+ <modify-function signature='call2(int*)'>\n\
+ <modify-argument index='1' invalidate-after-use='true'/>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ <object-type name='D'>\n\
+ <modify-function signature='call2(int*)'>\n\
+ <modify-argument index='1' invalidate-after-use='true'/>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ <object-type name='E' />\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, u"0.1"_s));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ auto func = classB->findFunction("call");
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+
+ const auto classC = AbstractMetaClass::findClass(classes, "C");
+ QVERIFY(classC);
+ func = classC->findFunction("call");
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+
+ func = classC->findFunction("call2");
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+
+ AbstractMetaClassCPtr classD = AbstractMetaClass::findClass(classes, "D");
+ QVERIFY(classD);
+ func = classD->findFunction("call");
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+
+ func = classD->findFunction("call2");
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+
+ const auto classE = AbstractMetaClass::findClass(classes, "E");
+ QVERIFY(classE);
+ func = classE->findFunction("call");
+ QVERIFY(func);
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+
+ func = classE->findFunction("call2");
+ QVERIFY(func);
+ QCOMPARE(func->modifications().size(), 1);
+ QCOMPARE(func->modifications().at(0).argument_mods().size(), 1);
+ QVERIFY(func->modifications().at(0).argument_mods().at(0).resetAfterUse());
+}
+
+void TestModifyFunction::testWithApiVersion()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ virtual A* method();\n\
+ virtual B* methodB();\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <object-type name='A' />\n\
+ <object-type name='B'>\n\
+ <modify-function signature='method()' since='0.1'>\n\
+ <modify-argument index='return'>\n\
+ <define-ownership owner='c++'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ <modify-function signature='methodB()' since='0.2'>\n\
+ <modify-argument index='return'>\n\
+ <define-ownership owner='c++'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, u"0.1"_s));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ auto func = classB->findFunction("method");
+
+ auto returnOwnership = func->argumentTargetOwnership(func->ownerClass(), 0);
+ QCOMPARE(returnOwnership, TypeSystem::CppOwnership);
+
+ func = classB->findFunction("methodB");
+ returnOwnership = func->argumentTargetOwnership(func->ownerClass(), 0);
+ QVERIFY(returnOwnership != TypeSystem::CppOwnership);
+}
+
+// Modifications on class/typesystem level are tested below
+// in testScopedModifications().
+void TestModifyFunction::testAllowThread()
+{
+ const char cppCode[] =R"CPP(\
+struct A {
+ void f1();
+ void f2();
+ void f3();
+ int getter1() const;
+ int getter2() const;
+};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='A'>
+ <modify-function signature='f2()' allow-thread='auto'/>
+ <modify-function signature='f3()' allow-thread='no'/>
+ <modify-function signature='getter2()const' allow-thread='yes'/>
+ </object-type>
+</typesystem>
+)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, u"0.1"_s));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+
+ // Nothing specified, true
+ const auto f1 = classA->findFunction("f1");
+ QVERIFY(f1);
+ QVERIFY(!f1->allowThread());
+
+ // 'auto' specified, should be false for nontrivial function
+ const auto f2 = classA->findFunction("f2");
+ QVERIFY(f2);
+ QVERIFY(f2->allowThread());
+
+ // 'no' specified, should be false
+ const auto f3 = classA->findFunction("f3");
+ QVERIFY(f3);
+ QVERIFY(!f3->allowThread());
+
+ // Nothing specified, should be false for simple getter
+ const auto getter1 = classA->findFunction("getter1");
+ QVERIFY(getter1);
+ QVERIFY(!getter1->allowThread());
+
+ // Forced to true simple getter
+ const auto getter2 = classA->findFunction("getter2");
+ QVERIFY(getter2);
+ QVERIFY(getter2->allowThread()); // Forced to true simple getter
+}
+
+void TestModifyFunction::testGlobalFunctionModification()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ void function(A* a = 0);\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='A'/>\n\
+ <function signature='function(A*)'>\n\
+ <modify-function signature='function(A*)'>\n\
+ <modify-argument index='1'>\n\
+ <replace-type modified-type='A'/>\n\
+ <replace-default-expression with='A()'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </function>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ QCOMPARE(builder->globalFunctions().size(), 1);
+
+ auto *td = TypeDatabase::instance();
+ FunctionModificationList mods = td->globalFunctionModifications({u"function(A*)"_s});
+ QCOMPARE(mods.size(), 1);
+ const QList<ArgumentModification> &argMods = mods.constFirst().argument_mods();
+ QCOMPARE(argMods.size(), 1);
+ ArgumentModification argMod = argMods.constFirst();
+ QCOMPARE(argMod.replacedDefaultExpression(), u"A()");
+
+ QVERIFY(!builder->globalFunctions().isEmpty());
+ const auto func = builder->globalFunctions().constFirst();
+ QCOMPARE(func->arguments().size(), 1);
+ const AbstractMetaArgument &arg = func->arguments().constFirst();
+ QCOMPARE(arg.type().cppSignature(), u"A *");
+ QCOMPARE(arg.originalDefaultValueExpression(), u"0");
+ QCOMPARE(arg.defaultValueExpression(), u"A()");
+}
+
+// Tests modifications of exception handling and allow-thread
+// on various levels.
+void TestModifyFunction::testScopedModifications_data()
+{
+ QTest::addColumn<QByteArray>("cppCode");
+ QTest::addColumn<QByteArray>("xmlCode");
+ QTest::addColumn<bool>("expectedGenerateUnspecified");
+ QTest::addColumn<bool>("expectedGenerateNonThrowing");
+ QTest::addColumn<bool>("expectedGenerateThrowing");
+ QTest::addColumn<bool>("expectedAllowThread");
+
+ const QByteArray cppCode = R"CPP(
+struct Base {
+};
+
+struct A : public Base {
+ void unspecified();
+ void nonThrowing() noexcept;
+# if __cplusplus >= 201703L // C++ 17
+ void throwing() noexcept(false);
+#else
+ void throwing() throw(int);
+#endif
+};
+)CPP";
+
+ // Default: Off
+ QTest::newRow("none")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package= 'Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A'/>
+</typesystem>)XML")
+ << false << false << false // exception
+ << false; // allowthread
+
+ // Modify one function
+ QTest::newRow("modify-function1")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A'>
+ <modify-function signature='throwing()' exception-handling='auto-on'/>
+ </object-type>
+</typesystem>)XML")
+ << false << false << true // exception
+ << false; // allowthread
+
+ // Flip defaults by modifying functions
+ QTest::newRow("modify-function2")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A'>
+ <modify-function signature='unspecified()' exception-handling='auto-on'/>
+ <modify-function signature='throwing()' exception-handling='no'/>
+ </object-type>
+</typesystem>)XML")
+ << true << false << false // exception
+ << false; // allowthread
+
+ // Activate on type system level
+ QTest::newRow("typesystem-on")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo' exception-handling='auto-on' allow-thread='no'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A'/>
+</typesystem>)XML")
+ << true << false << true // exception
+ << false; // allowthread
+
+ // Activate on class level
+ QTest::newRow("class-on")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A' exception-handling='auto-on' allow-thread='no'/>
+</typesystem>)XML")
+ << true << false << true // exception
+ << false; // allowthread
+
+ // Activate on base class level
+ QTest::newRow("baseclass-on")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base' exception-handling='auto-on' allow-thread='no'/>
+ <object-type name='A'/>
+</typesystem>)XML")
+ << true << false << true // exception
+ << false; // allowthread
+
+ // Override value on class level
+ QTest::newRow("override-class-on")
+ << cppCode
+ << QByteArray(R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <object-type name='Base'/>
+ <object-type name='A' exception-handling='auto-on'>
+ <modify-function signature='throwing()' exception-handling='no'/>
+ </object-type>
+</typesystem>)XML")
+ << true << false << false // exception
+ << false; // allowthread
+}
+
+void TestModifyFunction::testScopedModifications()
+{
+ QFETCH(QByteArray, cppCode);
+ QFETCH(QByteArray, xmlCode);
+ QFETCH(bool, expectedGenerateUnspecified);
+ QFETCH(bool, expectedGenerateNonThrowing);
+ QFETCH(bool, expectedGenerateThrowing);
+ QFETCH(bool, expectedAllowThread);
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode.constData(), xmlCode.constData(), false));
+ QVERIFY(builder);
+
+ const auto classA = AbstractMetaClass::findClass(builder->classes(), "A");
+ QVERIFY(classA);
+
+ auto f = classA->findFunction("unspecified");
+ QVERIFY(f);
+ QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Unknown);
+ QCOMPARE(f->generateExceptionHandling(), expectedGenerateUnspecified);
+ QCOMPARE(f->allowThread(), expectedAllowThread);
+
+ f = classA->findFunction("nonThrowing");
+ QVERIFY(f);
+ QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::NoExcept);
+ QCOMPARE(f->generateExceptionHandling(), expectedGenerateNonThrowing);
+
+ f = classA->findFunction("throwing");
+ QVERIFY(f);
+ QCOMPARE(f->exceptionSpecification(), ExceptionSpecification::Throws);
+ QCOMPARE(f->generateExceptionHandling(), expectedGenerateThrowing);
+}
+
+void TestModifyFunction::testSnakeCaseRenaming_data()
+{
+ QTest::addColumn<QLatin1StringView>("name");
+ QTest::addColumn<QLatin1StringView>("expected");
+ QTest::newRow("s1")
+ << "snakeCaseFunc"_L1 << "snake_case_func"_L1;
+ QTest::newRow("s2")
+ << "SnakeCaseFunc"_L1 << "snake_case_func"_L1;
+ QTest::newRow("consecutive-uppercase")
+ << "snakeCAseFunc"_L1 << "snakeCAseFunc"_L1;
+}
+
+void TestModifyFunction::testSnakeCaseRenaming()
+{
+ QFETCH(QLatin1StringView, name);
+ QFETCH(QLatin1StringView, expected);
+
+ const QString actual = AbstractMetaBuilder::getSnakeCaseName(name);
+ QCOMPARE(actual, expected);
+}
+
+QTEST_APPLESS_MAIN(TestModifyFunction)
diff --git a/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.h b/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.h
new file mode 100644
index 000000000..8a4f5d826
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmodifyfunction.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTABSTRACTMETACLASS_H
+#define TESTABSTRACTMETACLASS_H
+
+#include <QtCore/QObject>
+
+class TestModifyFunction : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testOwnershipTransfer();
+ void testWithApiVersion();
+ void testAllowThread();
+ void testRenameArgument_data();
+ void testRenameArgument();
+ void invalidateAfterUse();
+ void testGlobalFunctionModification();
+ void testScopedModifications_data();
+ void testScopedModifications();
+ void testSnakeCaseRenaming_data();
+ void testSnakeCaseRenaming();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.cpp b/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.cpp
new file mode 100644
index 000000000..1cf4c8e0f
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.cpp
@@ -0,0 +1,50 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testmultipleinheritance.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestMultipleInheritance::testVirtualClass()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ virtual ~A();\n\
+ virtual void theBug();\n\
+ };\n\
+ struct B {\n\
+ virtual ~B();\n\
+ };\n\
+ struct C : A, B {\n\
+ };\n\
+ struct D : C {\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A' />\n\
+ <object-type name='B' />\n\
+ <object-type name='C' />\n\
+ <object-type name='D' />\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 4);
+
+ const auto classD = AbstractMetaClass::findClass(classes, "D");
+ bool functionFound = false;
+ for (const auto &f : classD->functions()) {
+ if (f->name() == u"theBug") {
+ functionFound = true;
+ break;
+ }
+ }
+ QVERIFY(functionFound);
+
+}
+
+QTEST_APPLESS_MAIN(TestMultipleInheritance)
diff --git a/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.h b/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.h
new file mode 100644
index 000000000..ec9935305
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testmultipleinheritance.h
@@ -0,0 +1,18 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTMULTIPLEINHERITANCE_H
+#define TESTMULTIPLEINHERITANCE_H
+
+#include <QtCore/QObject>
+
+class AbstractMetaBuilder;
+
+class TestMultipleInheritance : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testVirtualClass();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testnamespace.cpp b/sources/shiboken6/ApiExtractor/tests/testnamespace.cpp
new file mode 100644
index 000000000..3773e614a
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testnamespace.cpp
@@ -0,0 +1,77 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testnamespace.h"
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <abstractmetaenum.h>
+#include <typesystem.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void NamespaceTest::testNamespaceMembers()
+{
+ const char cppCode[] = "\
+ namespace Namespace\n\
+ {\n\
+ enum Option {\n\
+ OpZero,\n\
+ OpOne\n\
+ };\n\
+ void foo(Option opt);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='Namespace'>\n\
+ <enum-type name='Option' />\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto ns = AbstractMetaClass::findClass(classes, "Namespace");
+ QVERIFY(ns);
+ auto metaEnum = ns->findEnum(u"Option"_s);
+ QVERIFY(metaEnum.has_value());
+ const auto func = ns->findFunction("foo");
+ QVERIFY(func);
+}
+
+void NamespaceTest::testNamespaceInnerClassMembers()
+{
+ const char cppCode[] = "\
+ namespace OuterNamespace\n\
+ {\n\
+ namespace InnerNamespace {\n\
+ struct SomeClass {\n\
+ void method();\n\
+ };\n\
+ };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='OuterNamespace'>\n\
+ <namespace-type name='InnerNamespace'>\n\
+ <value-type name='SomeClass'/>\n\
+ </namespace-type>\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto ons = AbstractMetaClass::findClass(classes, "OuterNamespace");
+ QVERIFY(ons);
+ const auto ins = AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace");
+ QVERIFY(ins);
+ const auto sc = AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace::SomeClass");
+ QVERIFY(sc);
+ const auto meth = sc->findFunction("method");
+ QVERIFY(meth);
+}
+
+QTEST_APPLESS_MAIN(NamespaceTest)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testnamespace.h b/sources/shiboken6/ApiExtractor/tests/testnamespace.h
new file mode 100644
index 000000000..af46bdea3
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testnamespace.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTNAMESPACE_H
+#define TESTNAMESPACE_H
+
+#include <QtCore/QObject>
+
+// The class is named 'NamespaceTest' to avoid clashes with Qt COIN using
+// '-qtnamespace TestNamespace'.
+class NamespaceTest : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testNamespaceMembers();
+ void testNamespaceInnerClassMembers();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testnestedtypes.cpp b/sources/shiboken6/ApiExtractor/tests/testnestedtypes.cpp
new file mode 100644
index 000000000..10ca1a0f6
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testnestedtypes.cpp
@@ -0,0 +1,115 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testnestedtypes.h"
+#include "testutil.h"
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <codesnip.h>
+#include <modifications.h>
+#include <complextypeentry.h>
+#include <primitivetypeentry.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestNestedTypes::testNestedTypesModifications()
+{
+ const char cppCode[] = "\
+ namespace OuterNamespace {\n\
+ namespace InnerNamespace {\n\
+ struct SomeClass {\n\
+ void method() {}\n\
+ };\n\
+ };\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='OuterNamespace'>\n\
+ <namespace-type name='InnerNamespace'>\n\
+ <inject-code class='native'>custom_code1();</inject-code>\n\
+ <add-function signature='method()' return-type='OuterNamespace::InnerNamespace::SomeClass'>\n\
+ <inject-code class='target'>custom_code2();</inject-code>\n\
+ </add-function>\n\
+ <object-type name='SomeClass' target-lang-name='RenamedSomeClass'>\n\
+ <modify-function signature='method()' remove='all'/>\n\
+ </object-type>\n\
+ </namespace-type>\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto ons = AbstractMetaClass::findClass(classes, "OuterNamespace");
+ QVERIFY(ons);
+
+ const auto ins = AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace");
+ QVERIFY(ins);
+ QCOMPARE(ins->functions().size(), 1);
+ QCOMPARE(ins->typeEntry()->codeSnips().size(), 1);
+ CodeSnip snip = ins->typeEntry()->codeSnips().constFirst();
+ QCOMPARE(snip.code().trimmed(), u"custom_code1();");
+
+ const auto addedFunc = ins->functions().constFirst();
+ QVERIFY(addedFunc->isUserAdded());
+ QCOMPARE(addedFunc->access(), Access::Public);
+ QCOMPARE(addedFunc->functionType(), AbstractMetaFunction::NormalFunction);
+ QCOMPARE(addedFunc->type().minimalSignature(),
+ u"OuterNamespace::InnerNamespace::SomeClass");
+
+ QCOMPARE(addedFunc->modifications().size(), 1);
+ QVERIFY(addedFunc->modifications().constFirst().isCodeInjection());
+ snip = addedFunc->modifications().constFirst().snips().constFirst();
+ QCOMPARE(snip.code().trimmed(), u"custom_code2();");
+
+ const auto sc =
+ AbstractMetaClass::findClass(classes, "OuterNamespace::InnerNamespace::SomeClass");
+ QVERIFY(sc);
+ QCOMPARE(sc->functions().size(), 2); // default constructor and removed method
+ const auto removedFunc = sc->functions().constLast();
+ QVERIFY(removedFunc->isModifiedRemoved());
+}
+
+
+void TestNestedTypes::testDuplicationOfNestedTypes()
+{
+ const char cppCode[] = "\
+ namespace Namespace {\n\
+ class SomeClass {};\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <namespace-type name='Namespace'>\n\
+ <value-type name='SomeClass'>\n\
+ <add-function signature='createSomeClass(Namespace::SomeClass)'/>\n\
+ </value-type>\n\
+ </namespace-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 2);
+ const auto nspace = AbstractMetaClass::findClass(classes, "Namespace");
+ QVERIFY(nspace);
+ const auto cls1 = AbstractMetaClass::findClass(classes, "SomeClass");
+ QVERIFY(cls1);
+ const auto cls2 = AbstractMetaClass::findClass(classes, "Namespace::SomeClass");
+ QVERIFY(cls2);
+ QCOMPARE(cls1, cls2);
+ QCOMPARE(cls1->name(), u"SomeClass");
+ QCOMPARE(cls1->qualifiedCppName(), u"Namespace::SomeClass");
+
+ auto t1 = TypeDatabase::instance()->findType(u"Namespace::SomeClass"_s);
+ QVERIFY(t1);
+ auto t2 = TypeDatabase::instance()->findType(u"SomeClass"_s);
+ QVERIFY(!t2);
+}
+
+QTEST_APPLESS_MAIN(TestNestedTypes)
diff --git a/sources/shiboken6/ApiExtractor/tests/testnestedtypes.h b/sources/shiboken6/ApiExtractor/tests/testnestedtypes.h
new file mode 100644
index 000000000..544ea05ab
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testnestedtypes.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTNESTEDTYPES_H
+#define TESTNESTEDTYPES_H
+
+#include <QtCore/QObject>
+
+class TestNestedTypes : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testNestedTypesModifications();
+ void testDuplicationOfNestedTypes();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.cpp b/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.cpp
new file mode 100644
index 000000000..9eef7ec47
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.cpp
@@ -0,0 +1,90 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testnumericaltypedef.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <typesystem.h>
+
+void TestNumericalTypedef::testNumericalTypedef()
+{
+ const char cppCode[] = "\
+ typedef double real;\n\
+ void funcDouble(double);\n\
+ void funcReal(real);\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='double'/>\n\
+ <primitive-type name='real'/>\n\
+ <function signature='funcDouble(double)'/>\n\
+ <function signature='funcReal(real)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ QCOMPARE(builder->globalFunctions().size(), 2);
+ auto funcDouble = builder->globalFunctions().constFirst();
+ auto funcReal = builder->globalFunctions().constLast();
+ QVERIFY(funcReal);
+
+ if (funcDouble->name() == u"funcReal")
+ std::swap(funcDouble, funcReal);
+
+ QCOMPARE(funcDouble->minimalSignature(), u"funcDouble(double)");
+ QCOMPARE(funcReal->minimalSignature(), u"funcReal(real)");
+
+ const AbstractMetaType doubleType = funcDouble->arguments().constFirst().type();
+ QCOMPARE(doubleType.cppSignature(), u"double");
+ QVERIFY(doubleType.isPrimitive());
+ QVERIFY(isCppPrimitive(doubleType.typeEntry()));
+
+ const AbstractMetaType realType = funcReal->arguments().constFirst().type();
+ QCOMPARE(realType.cppSignature(), u"real");
+ QVERIFY(realType.isPrimitive());
+ QVERIFY(isCppPrimitive(realType.typeEntry()));
+}
+
+void TestNumericalTypedef::testUnsignedNumericalTypedef()
+{
+ const char cppCode[] = "\
+ typedef unsigned short custom_ushort;\n\
+ void funcUnsignedShort(unsigned short);\n\
+ void funcUShort(custom_ushort);\n";
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='short'/>\n\
+ <primitive-type name='unsigned short'/>\n\
+ <primitive-type name='custom_ushort'/>\n\
+ <function signature='funcUnsignedShort(unsigned short)'/>\n\
+ <function signature='funcUShort(custom_ushort)'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ QCOMPARE(builder->globalFunctions().size(), 2);
+ auto funcUnsignedShort = builder->globalFunctions().constFirst();
+ auto funcUShort = builder->globalFunctions().constLast();
+
+ if (funcUnsignedShort->name() == u"funcUShort")
+ std::swap(funcUnsignedShort, funcUShort);
+
+ QCOMPARE(funcUnsignedShort->minimalSignature(), u"funcUnsignedShort(unsigned short)");
+ QCOMPARE(funcUShort->minimalSignature(), u"funcUShort(custom_ushort)");
+
+ const AbstractMetaType unsignedShortType = funcUnsignedShort->arguments().constFirst().type();
+ QCOMPARE(unsignedShortType.cppSignature(), u"unsigned short");
+ QVERIFY(unsignedShortType.isPrimitive());
+ QVERIFY(isCppPrimitive(unsignedShortType.typeEntry()));
+
+ const AbstractMetaType ushortType = funcUShort->arguments().constFirst().type();
+ QCOMPARE(ushortType.cppSignature(), u"custom_ushort");
+ QVERIFY(ushortType.isPrimitive());
+ QVERIFY(isCppPrimitive(ushortType.typeEntry()));
+}
+
+QTEST_APPLESS_MAIN(TestNumericalTypedef)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.h b/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.h
new file mode 100644
index 000000000..32f549836
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testnumericaltypedef.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTNUMERICALTYPEDEF_H
+#define TESTNUMERICALTYPEDEF_H
+
+#include <QtCore/QObject>
+
+class TestNumericalTypedef : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testNumericalTypedef();
+ void testUnsignedNumericalTypedef();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.cpp b/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.cpp
new file mode 100644
index 000000000..99cced09d
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.cpp
@@ -0,0 +1,40 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testprimitivetypetag.h"
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <primitivetypeentry.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestPrimitiveTypeTag::testPrimitiveTypeDefaultConstructor()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {};\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='A' default-constructor='A()'/>\n\
+ <object-type name='B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+
+ auto typeEntry = TypeDatabase::instance()->findPrimitiveType(u"A"_s);
+ QVERIFY(typeEntry);
+ QVERIFY(typeEntry->hasDefaultConstructor());
+ QCOMPARE(typeEntry->defaultConstructor(), u"A()");
+}
+
+QTEST_APPLESS_MAIN(TestPrimitiveTypeTag)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.h b/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.h
new file mode 100644
index 000000000..3a0e05138
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testprimitivetypetag.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTPRIMITIVETYPETAG_H
+#define TESTPRIMITIVETYPETAG_H
+
+#include <QtCore/QObject>
+
+class TestPrimitiveTypeTag : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testPrimitiveTypeDefaultConstructor();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testrefcounttag.cpp b/sources/shiboken6/ApiExtractor/tests/testrefcounttag.cpp
new file mode 100644
index 000000000..f2e261624
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testrefcounttag.cpp
@@ -0,0 +1,84 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testrefcounttag.h"
+#include "testutil.h"
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <modifications.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestRefCountTag::testReferenceCountTag()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ void keepObject(B* b);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'>\n\
+ <modify-function signature='keepObject(B*)'>\n\
+ <modify-argument index='1'>\n\
+ <reference-count action='add'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ const auto func = classB->findFunction("keepObject");
+ QVERIFY(func);
+ const auto refCount =
+ func->modifications().constFirst().argument_mods().constFirst().referenceCounts().constFirst();
+ QCOMPARE(refCount.action, ReferenceCount::Add);
+}
+
+void TestRefCountTag::testWithApiVersion()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ void keepObject(B*, B*);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'>\n\
+ <modify-function signature='keepObject(B*, B*)'>\n\
+ <modify-argument index='1' since='0.1'>\n\
+ <reference-count action='add'/>\n\
+ </modify-argument>\n\
+ <modify-argument index='2' since='0.2'>\n\
+ <reference-count action='add'/>\n\
+ </modify-argument>\n\
+ </modify-function>\n\
+ </object-type>\n\
+ </typesystem>\n";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode,
+ false, u"0.1"_s));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ const auto func = classB->findFunction("keepObject");
+ QVERIFY(func);
+ const auto refCount =
+ func->modifications().constFirst().argument_mods().constFirst().referenceCounts().constFirst();
+ QCOMPARE(refCount.action, ReferenceCount::Add);
+
+ QCOMPARE(func->modifications().size(), 1);
+}
+
+
+QTEST_APPLESS_MAIN(TestRefCountTag)
+
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testrefcounttag.h b/sources/shiboken6/ApiExtractor/tests/testrefcounttag.h
new file mode 100644
index 000000000..6093c6f7b
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testrefcounttag.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTREFCOUNTTAG_H
+#define TESTREFCOUNTTAG_H
+
+#include <QtCore/QObject>
+
+class TestRefCountTag : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testReferenceCountTag();
+ void testWithApiVersion();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.cpp b/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.cpp
new file mode 100644
index 000000000..ae85c5a86
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.cpp
@@ -0,0 +1,37 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testreferencetopointer.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <typesystem.h>
+
+void TestReferenceToPointer::testReferenceToPointerArgument()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {\n\
+ void dummy(A*&);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <object-type name='A'/>\n\
+ <object-type name='B'/>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ const auto func = classB->findFunction("dummy");
+ QVERIFY(func);
+ QCOMPARE(func->arguments().constFirst().type().minimalSignature(), u"A*&");
+}
+
+QTEST_APPLESS_MAIN(TestReferenceToPointer)
+
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.h b/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.h
new file mode 100644
index 000000000..2a7b34807
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testreferencetopointer.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTREFERENCETOPOINTER_H
+#define TESTREFERENCETOPOINTER_H
+
+#include <QtCore/QObject>
+
+class TestReferenceToPointer : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testReferenceToPointerArgument();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testremovefield.cpp b/sources/shiboken6/ApiExtractor/tests/testremovefield.cpp
new file mode 100644
index 000000000..2cc82071b
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testremovefield.cpp
@@ -0,0 +1,76 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testremovefield.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafield.h>
+#include <abstractmetafunction.h>
+#include <abstractmetatype.h>
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+using namespace Qt::StringLiterals;
+
+void TestRemoveField::testRemoveField()
+{
+ const char cppCode[] = "\
+ struct A {\n\
+ int fieldA;\n\
+ int fieldB;\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int'/>\n\
+ <value-type name='A'>\n\
+ <modify-field name='fieldB' remove='all'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->fields().size(), 1);
+ const AbstractMetaField &fieldA = classA->fields().constFirst();
+ QCOMPARE(fieldA.name(), u"fieldA");
+}
+
+// Verify that 'static constexpr' fields are seen as static/const and
+// appear fully qualified for function parameter default values.
+void TestRemoveField::testConstExprField()
+{
+ const char cppCode[] = R"(
+struct A {
+ static constexpr int constExprField = 44;
+
+ void f(int iParam=constExprField);
+};
+)";
+
+ const char xmlCode[] = R"(
+<typesystem package="Foo">
+ <value-type name='A'/>
+</typesystem>
+)";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto &fields = classA->fields();
+ QCOMPARE(fields.size(), 1);
+ QVERIFY(fields.constFirst().isStatic());
+ QVERIFY(fields.constFirst().type().isConstant());
+ const auto function = classA->findFunction("f"_L1);
+ QVERIFY(function);
+ const auto &arguments = function->arguments();
+ QCOMPARE(arguments.size(), 1);
+ QCOMPARE(arguments.constFirst().defaultValueExpression(), "A::constExprField"_L1);
+}
+
+QTEST_APPLESS_MAIN(TestRemoveField)
+
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testremovefield.h b/sources/shiboken6/ApiExtractor/tests/testremovefield.h
new file mode 100644
index 000000000..05912d99e
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testremovefield.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTREMOVEFIELD_H
+#define TESTREMOVEFIELD_H
+
+#include <QtCore/QObject>
+
+class TestRemoveField : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testRemoveField();
+ void testConstExprField();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.cpp b/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.cpp
new file mode 100644
index 000000000..87e318e95
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.cpp
@@ -0,0 +1,48 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testremoveimplconv.h"
+#include "testutil.h"
+#include <QtTest/QTest>
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <complextypeentry.h>
+
+// When a constructor able to trigger implicity conversions is removed
+// it should not appear in the implicity conversion list.
+void TestRemoveImplConv::testRemoveImplConv()
+{
+ const char cppCode[] = "\
+ struct A {};\n\
+ struct B {};\n\
+ struct C {\n\
+ C(const A&);\n\
+ C(const B&);\n\
+ };\n";
+ const char xmlCode[] = "\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'/>\n\
+ <value-type name='B'/>\n\
+ <value-type name='C'>\n\
+ <modify-function signature='C(const A&amp;)' remove='all'/>\n\
+ </value-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 3);
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ const auto classC = AbstractMetaClass::findClass(classes, "C");
+ QVERIFY(classC);
+ const auto implConv = classC->implicitConversions();
+ QCOMPARE(implConv.size(), 1);
+ QCOMPARE(implConv.constFirst()->arguments().constFirst().type().typeEntry(),
+ classB->typeEntry());
+}
+
+QTEST_APPLESS_MAIN(TestRemoveImplConv)
diff --git a/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.h b/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.h
new file mode 100644
index 000000000..d11d30633
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testremoveimplconv.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTREMOVEIMPLCONV_H
+#define TESTREMOVEIMPLCONV_H
+
+#include <QtCore/QObject>
+
+class TestRemoveImplConv : public QObject
+{
+Q_OBJECT
+private slots:
+ void testRemoveImplConv();
+};
+
+#endif // TESTREMOVEIMPLCONV_H
diff --git a/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.cpp b/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.cpp
new file mode 100644
index 000000000..17a069b5e
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.cpp
@@ -0,0 +1,98 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testremoveoperatormethod.h"
+#include "testutil.h"
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestRemoveOperatorMethod::testRemoveOperatorMethod()
+{
+ const char cppCode[] = R"(#include <cstdint>
+
+struct Char {};
+struct ByteArray {};
+struct String {};
+
+struct A {
+ A& operator>>(char&);
+ A& operator>>(char*);
+ A& operator>>(short&);
+ A& operator>>(unsigned short&);
+ A& operator>>(int&);
+ A& operator>>(unsigned int&);
+ A& operator>>(int64_t&);
+ A& operator>>(uint64_t&);
+ A& operator>>(float&);
+ A& operator>>(double&);
+ A& operator>>(Char&);
+ A& operator>>(ByteArray&);
+ A& operator>>(String&);
+};
+)";
+
+ const char xmlCode[] = "\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='char'/>\n\
+ <primitive-type name='short'/>\n\
+ <primitive-type name='unsigned short'/>\n\
+ <primitive-type name='int'/>\n\
+ <primitive-type name='unsigned int'/>\n\
+ <primitive-type name='int64_t'/>\n\
+ <primitive-type name='uint64_t'/>\n\
+ <primitive-type name='float'/>\n\
+ <primitive-type name='double'/>\n\
+ <primitive-type name='Char'/>\n\
+ <primitive-type name='String'/>\n\
+ <value-type name='ByteArray'/>\n\
+ <object-type name='A'>\n\
+ <modify-function signature='operator&gt;&gt;(char&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(char*)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(short&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(unsigned short&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(int&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(unsigned int&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(int64_t&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(uint64_t&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(float&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(double&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(Char&amp;)' remove='all'/>\n\
+ <modify-function signature='operator&gt;&gt;(String&amp;)' remove='all'/>\n\
+ </object-type>\n\
+ </typesystem>\n";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().size(), 14);
+ QStringList removedSignatures;
+ removedSignatures.append(u"operator>>(char&)"_s);
+ removedSignatures.append(u"operator>>(char*)"_s);
+ removedSignatures.append(u"operator>>(short&)"_s);
+ removedSignatures.append(u"operator>>(unsigned short&)"_s);
+ removedSignatures.append(u"operator>>(int&)"_s);
+ removedSignatures.append(u"operator>>(unsigned int&)"_s);
+ removedSignatures.append(u"operator>>(int64_t&)"_s);
+ removedSignatures.append(u"operator>>(uint64_t&)"_s);
+ removedSignatures.append(u"operator>>(float&)"_s);
+ removedSignatures.append(u"operator>>(double&)"_s);
+ removedSignatures.append(u"operator>>(Char&)"_s);
+ removedSignatures.append(u"operator>>(String&)"_s);
+ auto notRemoved = classA->functions().size();
+ for (const auto &f : classA->functions()) {
+ QCOMPARE(f->isModifiedRemoved(), bool(removedSignatures.contains(f->minimalSignature())));
+ notRemoved -= int(f->isModifiedRemoved());
+ }
+ QCOMPARE(notRemoved, 2);
+}
+
+QTEST_APPLESS_MAIN(TestRemoveOperatorMethod)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.h b/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.h
new file mode 100644
index 000000000..6ec335e0c
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testremoveoperatormethod.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTREMOVEOPERATORMETHOD_H
+#define TESTREMOVEOPERATORMETHOD_H
+
+#include <QtCore/QObject>
+
+class TestRemoveOperatorMethod : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testRemoveOperatorMethod();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp b/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp
new file mode 100644
index 000000000..67ebcc606
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testresolvetype.cpp
@@ -0,0 +1,281 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testresolvetype.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetaenum.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <complextypeentry.h>
+#include <enumtypeentry.h>
+#include <primitivetypeentry.h>
+#include <typedatabase.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestResolveType::initTestCase()
+{
+ // For enum lookup in testFixDefaultArguments()
+ AbstractMetaBuilder::setCodeModelTestMode(true);
+}
+
+void TestResolveType::testResolveReturnTypeFromParentScope()
+{
+ const char cppCode[] = "\n\
+ namespace A {\n\
+ struct B {\n\
+ struct C {};\n\
+ };\n\
+ struct D : public B::C {\n\
+ C* foo = 0;\n\
+ C* method();\n\
+ };\n\
+ };";
+ const char xmlCode[] = R"XML(
+ <typesystem package='Foo'>
+ <namespace-type name='A'>
+ <value-type name='B'>
+ <value-type name='C'/>
+ </value-type>
+ <value-type name='D'/>
+ </namespace-type>
+ </typesystem>)XML";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classD = AbstractMetaClass::findClass(classes, "A::D");
+ QVERIFY(classD);
+ const auto meth = classD->findFunction("method");
+ QVERIFY(meth);
+ QVERIFY(meth);
+}
+
+// Helper classes and functions for testing default value fixing.
+// Put the AbstractMetaBuilder into test fixture struct to avoid having
+// to re-parse for each data row.
+
+struct DefaultValuesFixture
+{
+ std::shared_ptr<AbstractMetaBuilder> builder;
+
+ AbstractMetaType intType;
+ AbstractMetaType stringType;
+ AbstractMetaType classType;
+ AbstractMetaType listType;
+ AbstractMetaType enumType;
+ AbstractMetaClassCPtr klass{};
+};
+
+Q_DECLARE_METATYPE(DefaultValuesFixture)
+Q_DECLARE_METATYPE(AbstractMetaType)
+
+static int populateDefaultValuesFixture(DefaultValuesFixture *fixture)
+{
+ static const char cppCode[] =R"(
+#include <string>
+#include <list>
+
+namespace Namespace {
+class Test
+{
+public:
+ enum Enum { enumValue1, enumValue2 };
+
+ explicit Test(int x = INT_FIELD_1);
+ explicit Test(const std::string &t = std::string(CHAR_FIELD_1));
+
+ static void listFunc(std::list<Test> list = std::list<Test>());
+
+ static const int INT_FIELD_1 = 42;
+ static const char *CHAR_FIELD_1;
+ static const Enum DefaultValue = enumValue1;
+};
+} // Namespace
+)";
+ static const char xmlCode[] = R"(
+<typesystem package="Foo">
+ <namespace-type name='Namespace'>
+ <value-type name='Test'>
+ <enum-type name='Enum'/>
+ </value-type>
+ </namespace-type>
+ <container-type name="std::list" type="list"/>
+</typesystem>
+)";
+
+ fixture->builder.reset(TestUtil::parse(cppCode, xmlCode, false));
+ if (!fixture->builder)
+ return -1;
+
+ for (const auto &klass : fixture->builder->classes()) {
+ if (klass->name() == u"Test") {
+ fixture->klass = klass;
+ break;
+ }
+ }
+ if (!fixture->klass)
+ return -2;
+
+ fixture->classType = AbstractMetaType(fixture->klass->typeEntry());
+ fixture->classType.decideUsagePattern();
+
+ for (const auto &f : fixture->klass->findFunctions("Test")) {
+ if (f->functionType() == AbstractMetaFunction::ConstructorFunction
+ && f->arguments().size() == 1) {
+ const auto type = f->arguments().constFirst().type();
+ if (type.name() == u"int")
+ fixture->intType = type;
+ else
+ fixture->stringType = type;
+ }
+ }
+ if (fixture->intType.isVoid() || fixture->stringType.isVoid())
+ return -3;
+
+ auto listFunc = fixture->klass->findFunction("listFunc");
+ if (!listFunc || listFunc->arguments().size() != 1)
+ return -3;
+ fixture->listType = listFunc->arguments().constFirst().type();
+
+ fixture->enumType = AbstractMetaType(fixture->klass->enums().constFirst().typeEntry());
+ fixture->enumType.decideUsagePattern();
+
+ return 0;
+}
+
+void TestResolveType::testFixDefaultArguments_data()
+{
+ DefaultValuesFixture fixture;
+ const int setupOk = populateDefaultValuesFixture(&fixture);
+
+ QTest::addColumn<DefaultValuesFixture>("fixture");
+ QTest::addColumn<int>("setupOk"); // To verify setup
+ QTest::addColumn<AbstractMetaType>("metaType"); // Type and parameters for fixup
+ QTest::addColumn<QString>("input");
+ QTest::addColumn<QString>("expected");
+
+ QTest::newRow("int") << fixture << setupOk
+ << fixture.intType << "1" << "1";
+ QTest::newRow("int-macro") << fixture << setupOk
+ << fixture.intType << "GL_MACRO" << "GL_MACRO";
+ QTest::newRow("int-enum") << fixture << setupOk
+ << fixture.intType << "enumValue1" << "Namespace::Test::Enum::enumValue1";
+
+ // Test expansion of container types
+ QString expected = u"std::list<Namespace::Test>()"_s;
+ QTest::newRow("list")
+ << fixture << setupOk << fixture.listType
+ << expected << expected;
+ QTest::newRow("partially qualified list")
+ << fixture << setupOk << fixture.listType
+ << "std::list<Test>()" << expected;
+
+ // Test field expansion
+ expected = u"Namespace::Test::INT_FIELD_1"_s;
+ QTest::newRow("qualified class field")
+ << fixture << setupOk << fixture.intType
+ << expected << expected;
+ QTest::newRow("partially qualified class field")
+ << fixture << setupOk << fixture.intType
+ << "Test::INT_FIELD_1" << expected;
+ QTest::newRow("unqualified class field")
+ << fixture << setupOk << fixture.intType
+ << "INT_FIELD_1" << expected;
+
+ // Test field expansion when constructing some class
+ expected = u"QLatin1String(Namespace::Test::CHAR_FIELD_1)"_s;
+ QTest::newRow("class from qualified class field")
+ << fixture << setupOk << fixture.classType
+ << expected << expected;
+ QTest::newRow("class from partially qualified class field")
+ << fixture << setupOk << fixture.classType
+ << "QLatin1String(Test::CHAR_FIELD_1)" << expected;
+ QTest::newRow("class from unqualified class field")
+ << fixture << setupOk << fixture.classType
+ << "QLatin1String(CHAR_FIELD_1)" << expected;
+
+ // Test field expansion when constructing class itself
+ expected = u"Namespace::Test(Namespace::Test::CHAR_FIELD_1)"_s;
+ QTest::newRow("self from qualified class field")
+ << fixture << setupOk << fixture.classType
+ << expected << expected;
+ QTest::newRow("self from partially qualified class field")
+ << fixture << setupOk << fixture.classType
+ << "Test(Test::CHAR_FIELD_1)" << expected;
+ QTest::newRow("self from unqualified class field")
+ << fixture << setupOk << fixture.classType
+ << "Test(CHAR_FIELD_1)" << expected;
+
+ // Test enum expansion when constructing class itself
+ expected = u"Namespace::Test(Namespace::Test::Enum::enumValue1)"_s;
+ QTest::newRow("self from qualified enum")
+ << fixture << setupOk << fixture.classType
+ << expected << expected;
+ QTest::newRow("self from enum")
+ << fixture << setupOk << fixture.classType
+ << "Test(enumValue1)" << expected;
+
+ // Don't qualify fields to "Test::Enum::DefaultValue"
+ QTest::newRow("enum from static field")
+ << fixture << setupOk << fixture.enumType
+ << "DefaultValue" << u"Namespace::Test::DefaultValue"_s;
+}
+
+void TestResolveType::testFixDefaultArguments()
+{
+ QFETCH(DefaultValuesFixture, fixture);
+ QFETCH(int, setupOk);
+ QFETCH(AbstractMetaType, metaType);
+ QFETCH(QString, input);
+ QFETCH(QString, expected);
+ QCOMPARE(setupOk, 0);
+ const QString actual = fixture.builder->fixDefaultValue(input, metaType, fixture.klass);
+ QCOMPARE(actual, expected);
+}
+
+// Verify that the typedefs of the C++ 11 integer types (int32_t, ...)
+// are seen by the C++ parser, otherwise they are handled as unknown
+// primitive types, causing invalid code to be generated.
+// (see BuilderPrivate::visitHeader(),
+// sources/shiboken6/ApiExtractor/clangparser/clangbuilder.cpp).
+void TestResolveType::testCppTypes()
+{
+ static const char cppCode[] =R"(
+#include <cstdint>
+
+class Test
+{
+public:
+ explicit Test(int32_t v);
+};
+)";
+ static const char xmlCode[] = R"(
+<typesystem package="Foo">
+ <value-type name='Test'/>
+ <primitive-type name='int32_t'/>
+</typesystem>
+)";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto testClass = AbstractMetaClass::findClass(classes, "Test");
+ QVERIFY(testClass);
+
+ auto *tdb = TypeDatabase::instance();
+ auto int32TEntry = tdb->findType(u"int32_t"_s);
+ QVERIFY2(int32TEntry, "int32_t not found");
+ QVERIFY(int32TEntry->isPrimitive());
+ auto int32T = std::static_pointer_cast<const PrimitiveTypeEntry>(int32TEntry);
+ auto basicType = basicReferencedTypeEntry(int32T);
+ QVERIFY2(basicType != int32T,
+ "Typedef for int32_t not found. Check the system include paths.");
+}
+
+QTEST_APPLESS_MAIN(TestResolveType)
diff --git a/sources/shiboken6/ApiExtractor/tests/testresolvetype.h b/sources/shiboken6/ApiExtractor/tests/testresolvetype.h
new file mode 100644
index 000000000..a07855eab
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testresolvetype.h
@@ -0,0 +1,21 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTRESOLVETYPE_H
+#define TESTRESOLVETYPE_H
+
+#include <QtCore/QObject>
+
+class TestResolveType : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void initTestCase();
+
+ void testResolveReturnTypeFromParentScope();
+ void testFixDefaultArguments_data();
+ void testFixDefaultArguments();
+ void testCppTypes();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp
new file mode 100644
index 000000000..f4eecff2c
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.cpp
@@ -0,0 +1,129 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testreverseoperators.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <typesystem.h>
+#include <clangparser/compilersupport.h>
+
+#include <algorithm>
+
+void TestReverseOperators::testReverseSum()
+{
+ const char cppCode[] = "struct A {\n\
+ A& operator+(int);\n\
+ };\n\
+ A& operator+(int, const A&);";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int' />\n\
+ <value-type name='A' />\n\
+ </typesystem>";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().size(), 4);
+
+ AbstractMetaFunctionCPtr reverseOp;
+ AbstractMetaFunctionCPtr normalOp;
+ for (const auto &func : classA->functions()) {
+ if (func->name() == u"operator+") {
+ if (func->isReverseOperator())
+ reverseOp = func;
+ else
+ normalOp = func;
+ }
+ }
+
+ QVERIFY(normalOp);
+ QVERIFY(!normalOp->isReverseOperator());
+ QCOMPARE(normalOp->arguments().size(), 1);
+ QVERIFY(reverseOp);
+ QVERIFY(reverseOp->isReverseOperator());
+ QCOMPARE(reverseOp->arguments().size(), 1);
+}
+
+void TestReverseOperators::testReverseSumWithAmbiguity()
+{
+ const char cppCode[] = "\n\
+ struct A { A operator+(int); };\n\
+ A operator+(int, const A&);\n\
+ struct B {};\n\
+ B operator+(const A&, const B&);\n\
+ B operator+(const B&, const A&);\n\
+ ";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <primitive-type name='int' />\n\
+ <value-type name='A' />\n\
+ <value-type name='B' />\n\
+ </typesystem>";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QCOMPARE(classA->functions().size(), 4);
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ QCOMPARE(classB->functions().size(), 4);
+
+ AbstractMetaFunctionCPtr reverseOp;
+ AbstractMetaFunctionCPtr normalOp;
+ for (const auto &func : classB->functions()) {
+ if (func->name() == u"operator+") {
+ if (func->isReverseOperator())
+ reverseOp = func;
+ else
+ normalOp = func;
+ }
+ }
+ QVERIFY(normalOp);
+ QVERIFY(!normalOp->isReverseOperator());
+ QCOMPARE(normalOp->arguments().size(), 1);
+ QCOMPARE(normalOp->minimalSignature(), u"operator+(B,A)");
+ QVERIFY(reverseOp);
+ QVERIFY(reverseOp->isReverseOperator());
+ QCOMPARE(reverseOp->arguments().size(), 1);
+ QCOMPARE(reverseOp->minimalSignature(), u"operator+(A,B)");
+}
+
+void TestReverseOperators::testSpaceshipOperator()
+{
+ const char cppCode[] = R"(
+ class Test {
+ public:
+ explicit Test(int v);
+ int operator<=>(const Test &rhs) const = default;
+ };)";
+ const char xmlCode[] = R"(
+ <typesystem package="Foo">
+ <value-type name='Test'/>
+ </typesystem>)";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false,
+ {}, {}, LanguageLevel::Cpp20));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+ const auto testClass = AbstractMetaClass::findClass(classes, "Test");
+ QVERIFY(testClass);
+ const auto &functions = testClass->functions();
+ // 6 operators should be synthesized
+ const auto count = std::count_if(functions.cbegin(), functions.cend(),
+ [](const AbstractMetaFunctionCPtr &f) {
+ return f->isComparisonOperator();
+ });
+ QCOMPARE(count, 6);
+}
+
+QTEST_APPLESS_MAIN(TestReverseOperators)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h
new file mode 100644
index 000000000..fb8d97c97
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testreverseoperators.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTREVERSEOPERATORS_H
+#define TESTREVERSEOPERATORS_H
+#include <QtCore/QObject>
+
+class TestReverseOperators : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testReverseSum();
+ void testReverseSumWithAmbiguity();
+ void testSpaceshipOperator();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testtemplates.cpp b/sources/shiboken6/ApiExtractor/tests/testtemplates.cpp
new file mode 100644
index 000000000..ea37c6255
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testtemplates.cpp
@@ -0,0 +1,628 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testtemplates.h"
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafield.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <abstractmetatype.h>
+#include <complextypeentry.h>
+#include <containertypeentry.h>
+
+#include <qtcompat.h>
+
+#include <QtCore/QTemporaryFile>
+#include <QtCore/QTextStream>
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestTemplates::testTemplateWithNamespace()
+{
+ const char cppCode[] = R"CPP(
+template<typename T> struct QList {};
+struct Url {
+ void name();
+};
+namespace Internet {
+ struct Url{};
+ struct Bookmarks {
+ QList<Url> list();
+ };
+};
+)CPP";
+
+ const char xmlCode0[] = R"XML(
+<typesystem package='Package.Network'>
+ <value-type name='Url'/>
+</typesystem>)XML";
+
+ QTemporaryFile file;
+ QVERIFY(file.open());
+ file.write(xmlCode0);
+ file.close();
+
+ QString xmlCode1 = QString::fromLatin1(R"XML(
+<typesystem package='Package.Internet'>
+ <load-typesystem name='%1' generate='no'/>
+ <container-type name='QList' type='list'/>
+ <namespace-type name='Internet' generate='no'>
+ <value-type name='Url'/>
+ <value-type name='Bookmarks'/>
+ </namespace-type>
+</typesystem>)XML").arg(file.fileName());
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, qPrintable(xmlCode1), false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto classB = AbstractMetaClass::findClass(classes, "Bookmarks");
+ QVERIFY(classB);
+ const auto func = classB->findFunction("list");
+ QVERIFY(func);
+ AbstractMetaType funcType = func->type();
+ QVERIFY(!funcType.isVoid());
+ QCOMPARE(funcType.cppSignature(), u"QList<Internet::Url>");
+}
+
+void TestTemplates::testTemplateOnContainers()
+{
+ const char cppCode[] = R"CPP(
+struct Base {};
+template<typename T> struct QList {};
+namespace Namespace {
+ enum SomeEnum { E1, E2 };
+ template<SomeEnum type> struct A {
+ A<type> foo(const QList<A<type> >& a);
+ };
+ typedef A<E1> B;
+}
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package="Package">
+ <container-type name='QList' type='list'/>
+ <namespace-type name='Namespace'>
+ <enum-type name='SomeEnum'/>
+ <object-type name='A' generate='no'/>
+ <object-type name='B'/>
+ </namespace-type>
+ <object-type name='Base'/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ QVERIFY(!classB->baseClass());
+ QVERIFY(classB->baseClassName().isEmpty());
+ const auto func = classB->findFunction("foo");
+ QVERIFY(func);
+ AbstractMetaType argType = func->arguments().constFirst().type();
+ QCOMPARE(argType.instantiations().size(), 1);
+ QCOMPARE(argType.typeEntry()->qualifiedCppName(), u"QList");
+
+ const AbstractMetaType &instance1 = argType.instantiations().constFirst();
+ QCOMPARE(instance1.instantiations().size(), 1);
+ QCOMPARE(instance1.typeEntry()->qualifiedCppName(), u"Namespace::A");
+
+ const AbstractMetaType &instance2 = instance1.instantiations().constFirst();
+ QCOMPARE(instance2.instantiations().size(), 0);
+ QCOMPARE(instance2.typeEntry()->qualifiedCppName(), u"Namespace::E1");
+}
+
+void TestTemplates::testTemplateValueAsArgument()
+{
+ const char cppCode[] = R"CPP(
+template<typename T> struct List {};
+void func(List<int> arg) {}
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Package'>
+ <primitive-type name='int'/>
+ <container-type name='List' type='list'/>
+ <function signature='func(List&lt;int&gt;)'/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ const auto globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.size(), 1);
+
+ const auto func = globalFuncs.constFirst();
+ QCOMPARE(func->minimalSignature(), u"func(List<int>)");
+ QCOMPARE(func->arguments().constFirst().type().cppSignature(),
+ u"List<int>");
+}
+
+void TestTemplates::testTemplatePointerAsArgument()
+{
+ const char cppCode[] = R"CPP(
+template<typename T> struct List {};
+void func(List<int>* arg) {}
+)CPP";
+
+ const char xmlCode[] = R"XML(
+ <typesystem package='Package'>
+ <primitive-type name='int'/>
+ <container-type name='List' type='list'/>
+ <function signature='func(List&lt;int&gt;*)'/>
+ </typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaFunctionCList globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.size(), 1);
+
+ const auto func = globalFuncs.constFirst();
+ QCOMPARE(func->minimalSignature(), u"func(List<int>*)");
+ QCOMPARE(func->arguments().constFirst().type().cppSignature(),
+ u"List<int> *");
+}
+
+void TestTemplates::testTemplateReferenceAsArgument()
+{
+ const char cppCode[] = R"CPP(
+template<typename T> struct List {};
+void func(List<int>& arg) {}
+ )CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Package'>
+ <primitive-type name='int'/>
+ <container-type name='List' type='list'/>
+ <function signature='func(List&lt;int&gt;&amp;)'/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ const auto globalFuncs = builder->globalFunctions();
+ QCOMPARE(globalFuncs.size(), 1);
+
+ const auto func = globalFuncs.constFirst();
+ QCOMPARE(func->minimalSignature(), u"func(List<int>&)");
+ QCOMPARE(func->arguments().constFirst().type().cppSignature(),
+ u"List<int> &");
+}
+
+void TestTemplates::testTemplateParameterFixup()
+{
+ const char cppCode[] = R"CPP(
+template<typename T>
+struct List {
+ struct Iterator {};
+ void append(List l);
+ void erase(List::Iterator it);
+};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+ <typesystem package='Package'>
+ <container-type name='List' type='list'>
+ <value-type name='Iterator'/>
+ </container-type>
+ </typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ const AbstractMetaClassList templates = builder->templates();
+
+ QCOMPARE(templates.size(), 1);
+ AbstractMetaClassCPtr list = templates.constFirst();
+ // Verify that the parameter of "void append(List l)" gets fixed to "List<T>"
+ const auto append = list->findFunction("append");
+ QVERIFY(append);
+ QCOMPARE(append->arguments().size(), 1);
+ QCOMPARE(append->arguments().at(0).type().cppSignature(), u"List<T>");
+ // Verify that the parameter of "void erase(Iterator)" is not modified
+ const auto erase = list->findFunction("erase");
+ QVERIFY(erase);
+ QCOMPARE(erase->arguments().size(), 1);
+ QCOMPARE(erase->arguments().at(0).type().cppSignature(), u"List::Iterator");
+}
+
+void TestTemplates::testInheritanceFromContainterTemplate()
+{
+ const char cppCode[] = R"CPP(
+template<typename T>
+struct ListContainer {
+ inline void push_front(const T& t);
+ inline T& front();
+};
+struct FooBar {};
+struct FooBars : public ListContainer<FooBar> {};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Package'>
+ <container-type name='ListContainer' type='list'/>
+ <value-type name='FooBar'/>
+ <value-type name='FooBars'>
+ <modify-function signature='push_front(FooBar)' remove='all'/>
+ <modify-function signature='front()' remove='all'/>
+ </value-type>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ AbstractMetaClassList templates = builder->templates();
+ QCOMPARE(classes.size(), 2);
+ QCOMPARE(templates.size(), 1);
+
+ const auto foobars = AbstractMetaClass::findClass(classes, "FooBars");
+ QCOMPARE(foobars->functions().size(), 4);
+
+ AbstractMetaClassCPtr lc = templates.constFirst();
+ QCOMPARE(lc->functions().size(), 2);
+}
+
+void TestTemplates::testTemplateInheritanceMixedWithForwardDeclaration()
+{
+ const char cppCode[] = R"CPP(
+enum SomeEnum { E1, E2 };
+template<SomeEnum type> struct Future;
+template<SomeEnum type>
+struct A {
+ A();
+ void method();
+ friend struct Future<type>;
+};
+typedef A<E1> B;
+template<SomeEnum type> struct Future {};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Package'>
+ <enum-type name='SomeEnum'/>
+ <value-type name='A' generate='no'/>
+ <value-type name='B'/>
+ <value-type name='Future' generate='no'/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ QVERIFY(!classB->baseClass());
+ QVERIFY(classB->baseClassName().isEmpty());
+ // 3 functions: simple constructor, copy constructor and "method()".
+ QCOMPARE(classB->functions().size(), 3);
+}
+
+void TestTemplates::testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration()
+{
+ const char cppCode[] = R"CPP(
+namespace Namespace {
+enum SomeEnum { E1, E2 };
+template<SomeEnum type> struct Future;
+template<SomeEnum type>
+struct A {
+ A();
+ void method();
+ friend struct Future<type>;
+};
+typedef A<E1> B;
+template<SomeEnum type> struct Future {};
+};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Package'>
+ <namespace-type name='Namespace'>
+ <enum-type name='SomeEnum'/>
+ <value-type name='A' generate='no'/>
+ <value-type name='B'/>
+ <value-type name='Future' generate='no'/>
+ </namespace-type>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto classB = AbstractMetaClass::findClass(classes, "Namespace::B");
+ QVERIFY(classB);
+ QVERIFY(!classB->baseClass());
+ QVERIFY(classB->baseClassName().isEmpty());
+ // 3 functions: simple constructor, copy constructor and "method()".
+ QCOMPARE(classB->functions().size(), 3);
+}
+
+void TestTemplates::testTypedefOfInstantiationOfTemplateClass()
+{
+ const char cppCode[] = R"CPP(
+namespace NSpace {
+enum ClassType {
+ TypeOne
+};
+template<ClassType CLASS_TYPE>
+struct BaseTemplateClass {
+ inline ClassType getClassType() const { return CLASS_TYPE; }
+};
+typedef BaseTemplateClass<TypeOne> TypeOneClass;
+}
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Package'>
+ <namespace-type name='NSpace'>
+ <enum-type name='ClassType'/>
+ <object-type name='BaseTemplateClass' generate='no'/>
+ <object-type name='TypeOneClass'/>
+ </namespace-type>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 3);
+
+ const auto base = AbstractMetaClass::findClass(classes, "BaseTemplateClass");
+ QVERIFY(base);
+ const auto one = AbstractMetaClass::findClass(classes, "TypeOneClass");
+ QVERIFY(one);
+ QCOMPARE(one->templateBaseClass(), base);
+ QCOMPARE(one->functions().size(), base->functions().size());
+ QVERIFY(one->isTypeDef());
+ auto oneType = one->typeEntry();
+ auto baseType = base->typeEntry();
+ QCOMPARE(oneType->baseContainerType(), baseType);
+ QCOMPARE(one->baseClassNames(), QStringList(u"NSpace::BaseTemplateClass<NSpace::TypeOne>"_s));
+
+ QVERIFY(one->hasTemplateBaseClassInstantiations());
+ AbstractMetaTypeList instantiations = one->templateBaseClassInstantiations();
+ QCOMPARE(instantiations.size(), 1);
+ const AbstractMetaType &inst = instantiations.constFirst();
+ QVERIFY(!inst.isEnum());
+ QVERIFY(!inst.typeEntry()->isEnum());
+ QVERIFY(inst.typeEntry()->isEnumValue());
+ QCOMPARE(inst.cppSignature(), u"NSpace::TypeOne");
+}
+
+void TestTemplates::testContainerTypeIncompleteArgument()
+{
+ const char cppCode[] = R"CPP(
+template<typename T>
+class Vector {
+ void method(const Vector& vector);
+ Vector otherMethod();
+};
+template <typename T>
+void Vector<T>::method(const Vector<T>& vector) {}
+template <typename T>
+Vector<T> Vector<T>::otherMethod() { return Vector<T>(); }
+typedef Vector<int> IntVector;
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <container-type name='Vector' type='vector'/>
+ <value-type name='IntVector'/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ QCOMPARE(classes.size(), 1);
+
+ const auto vector = AbstractMetaClass::findClass(classes, "IntVector");
+ QVERIFY(vector);
+ auto baseContainer = vector->typeEntry()->baseContainerType();
+ QVERIFY(baseContainer);
+ QCOMPARE(reinterpret_cast<const ContainerTypeEntry*>(baseContainer.get())->containerKind(),
+ ContainerTypeEntry::ListContainer);
+ QCOMPARE(vector->functions().size(), 4);
+
+ const auto method = vector->findFunction("method");
+ QVERIFY(method);
+ QCOMPARE(method->signature(), u"method(const Vector<int> & vector)");
+
+ const auto otherMethod = vector->findFunction("otherMethod");
+ QVERIFY(otherMethod);
+ QCOMPARE(otherMethod->signature(), u"otherMethod()");
+ QVERIFY(!otherMethod->type().isVoid());
+ QCOMPARE(otherMethod->type().cppSignature(), u"Vector<int>");
+}
+
+void TestTemplates::testNonTypeTemplates()
+{
+ // PYSIDe-1296, functions with non type templates parameters.
+ const char cppCode[] = R"CPP(
+template <class T, int Size>
+class Array {
+ T array[Size];
+};
+
+Array<int, 2> foo();
+
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <container-type name='Array' type='vector'/>
+ <function signature="foo()"/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true));
+ QVERIFY(builder);
+ auto functions = builder->globalFunctions();
+ QCOMPARE(functions.size(), 1);
+ auto foo = functions.constFirst();
+ QCOMPARE(foo->name(), u"foo");
+ QCOMPARE(foo->type().name(), u"Array");
+}
+
+// Perform checks on template inheritance; a typedef of a template class
+// should result in rewritten types.
+void TestTemplates::testTemplateTypeDefs_data()
+{
+ QTest::addColumn<QString>("cpp");
+ QTest::addColumn<QString>("xml");
+
+ const char optionalClassDef[] = R"CPP(
+template<class T> // Some value type similar to std::optional
+class Optional {
+public:
+ T value() const { return m_value; }
+ operator bool() const { return m_success; }
+
+ T m_value;
+ bool m_success = false;
+};
+)CPP";
+
+ const char xmlPrefix[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <primitive-type name='bool'/>
+)XML";
+
+ const char xmlOptionalDecl[] = "<value-type name='Optional' generate='no'/>\n";
+ const char xmlOptionalIntDecl[] = "<value-type name='IntOptional'/>\n";
+ const char xmlPostFix[] = "</typesystem>\n";
+
+ // Flat, global namespace
+ QString cpp;
+ QTextStream(&cpp) << optionalClassDef
+ << "typedef Optional<int> IntOptional;\n";
+ QString xml;
+ QTextStream(&xml) << xmlPrefix << xmlOptionalDecl << xmlOptionalIntDecl
+ << "<typedef-type name='XmlIntOptional' source='Optional&lt;int&gt;'/>"
+ << xmlPostFix;
+ QTest::newRow("global-namespace")
+ << cpp << xml;
+
+ // Typedef from namespace Std
+ cpp.clear();
+ QTextStream(&cpp) << "namespace Std {\n" << optionalClassDef << "}\n"
+ << "typedef Std::Optional<int> IntOptional;\n";
+ xml.clear();
+ QTextStream(&xml) << xmlPrefix
+ << "<namespace-type name='Std'>\n" << xmlOptionalDecl
+ << "</namespace-type>\n" << xmlOptionalIntDecl
+ << "<typedef-type name='XmlIntOptional' source='Std::Optional&lt;int&gt;'/>"
+ << xmlPostFix;
+ QTest::newRow("namespace-Std")
+ << cpp << xml;
+
+ // Typedef from nested class
+ cpp.clear();
+ QTextStream(&cpp) << "class Outer {\npublic:\n" << optionalClassDef << "\n};\n"
+ << "typedef Outer::Optional<int> IntOptional;\n";
+ xml.clear();
+ QTextStream(&xml) << xmlPrefix
+ << "<object-type name='Outer'>\n" << xmlOptionalDecl
+ << "</object-type>\n" << xmlOptionalIntDecl
+ << "<typedef-type name='XmlIntOptional' source='Outer::Optional&lt;int&gt;'/>"
+ << xmlPostFix;
+ QTest::newRow("nested-class")
+ << cpp << xml;
+}
+
+void TestTemplates::testTemplateTypeDefs()
+{
+ QFETCH(QString, cpp);
+ QFETCH(QString, xml);
+
+ const QByteArray cppBa = cpp.toLocal8Bit();
+ const QByteArray xmlBa = xml.toLocal8Bit();
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppBa.constData(), xmlBa.constData(), true));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto optional = AbstractMetaClass::findClass(classes, "Optional");
+ QVERIFY(optional);
+
+ // Find the typedef'ed class
+ const auto optionalInt = AbstractMetaClass::findClass(classes, "IntOptional");
+ QVERIFY(optionalInt);
+ QCOMPARE(optionalInt->templateBaseClass(), optional);
+
+ // Find the class typedef'ed in the typesystem XML
+ const auto xmlOptionalInt = AbstractMetaClass::findClass(classes, "XmlIntOptional");
+ QVERIFY(xmlOptionalInt);
+ QCOMPARE(xmlOptionalInt->templateBaseClass(), optional);
+
+ // Check whether the value() method now has an 'int' return
+ const auto valueMethod = optionalInt->findFunction("value");
+ QVERIFY(valueMethod);
+ QCOMPARE(valueMethod->type().cppSignature(), u"int");
+
+ // ditto for typesystem XML
+ const auto xmlValueMethod = xmlOptionalInt->findFunction("value");
+ QVERIFY(xmlValueMethod);
+ QCOMPARE(xmlValueMethod->type().cppSignature(), u"int");
+
+ // Check whether the m_value field is of type 'int'
+ const auto valueField = optionalInt->findField(u"m_value");
+ QVERIFY(valueField.has_value());
+ QCOMPARE(valueField->type().cppSignature(), u"int");
+
+ // ditto for typesystem XML
+ const auto xmlValueField =
+ xmlOptionalInt->findField(u"m_value");
+ QVERIFY(xmlValueField.has_value());
+ QCOMPARE(xmlValueField->type().cppSignature(), u"int");
+}
+
+void TestTemplates::testTemplateTypeAliases()
+{
+ // Model Qt 6's "template<typename T> using QList = QVector<T>"
+ const char cppCode[] = R"CPP(
+template<typename T>
+class Container1 { };
+
+template<typename T>
+using Container2 = Container1<T>;
+
+class Test
+{
+public:
+ Container2<int> m_intContainer;
+};
+
+class Derived : public Container2<int>
+{
+public:
+};
+)CPP";
+
+ const char xmlCode[] = R"XML(
+<typesystem package='Foo'>
+ <primitive-type name='int'/>
+ <value-type name='Container1'/>
+ <value-type name='Derived'/>
+ <object-type name='Test'/>
+</typesystem>)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+ const auto testClass = AbstractMetaClass::findClass(classes, "Test");
+ QVERIFY(testClass);
+
+ auto fields = testClass->fields();
+ QCOMPARE(fields.size(), 1);
+ auto fieldType = testClass->fields().at(0).type();
+ QCOMPARE(fieldType.name(), u"Container1");
+ QCOMPARE(fieldType.instantiations().size(), 1);
+
+ const auto derived = AbstractMetaClass::findClass(classes, "Derived");
+ QVERIFY(derived);
+ auto base = derived->templateBaseClass();
+ QVERIFY(base);
+ QCOMPARE(base->name(), u"Container1");
+}
+
+QTEST_APPLESS_MAIN(TestTemplates)
diff --git a/sources/shiboken6/ApiExtractor/tests/testtemplates.h b/sources/shiboken6/ApiExtractor/tests/testtemplates.h
new file mode 100644
index 000000000..36800f723
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testtemplates.h
@@ -0,0 +1,30 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTTEMPLATES_H
+#define TESTTEMPLATES_H
+
+#include <QtCore/QObject>
+
+class TestTemplates : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testTemplateOnContainers();
+ void testTemplateWithNamespace();
+ void testTemplateValueAsArgument();
+ void testTemplatePointerAsArgument();
+ void testTemplateReferenceAsArgument();
+ void testTemplateParameterFixup();
+ void testInheritanceFromContainterTemplate();
+ void testTemplateInheritanceMixedWithForwardDeclaration();
+ void testTemplateInheritanceMixedWithNamespaceAndForwardDeclaration();
+ void testTypedefOfInstantiationOfTemplateClass();
+ void testContainerTypeIncompleteArgument();
+ void testNonTypeTemplates();
+ void testTemplateTypeDefs_data();
+ void testTemplateTypeDefs();
+ void testTemplateTypeAliases();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testtoposort.cpp b/sources/shiboken6/ApiExtractor/tests/testtoposort.cpp
new file mode 100644
index 000000000..50cefcfe9
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testtoposort.cpp
@@ -0,0 +1,61 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testtoposort.h"
+#include "graph.h"
+
+#include <QtTest/QTest>
+#include <QtCore/QDebug>
+
+using IntGraph = Graph<int>;
+
+Q_DECLARE_METATYPE(IntGraph)
+
+using IntList = QList<int>;
+
+void TestTopoSort::testTopoSort_data()
+{
+ QTest::addColumn<IntGraph>("graph");
+ QTest::addColumn<bool>("expectedValid");
+ QTest::addColumn<IntList>("expectedOrder");
+
+ const int nodes1[] = {0, 1, 2};
+ IntGraph g(std::begin(nodes1), std::end(nodes1));
+ g.addEdge(1, 2);
+ g.addEdge(0, 1);
+ IntList expected = {0, 1, 2};
+ QTest::newRow("DAG") << g << true << expected;
+
+ const int nodes2[] = {0, 1};
+ g.clear();
+ g.setNodes(std::begin(nodes2), std::end(nodes2));
+ expected = {1, 0};
+ QTest::newRow("No edges") << g << true << expected;
+
+ g.clear();
+ g.setNodes(std::begin(nodes1), std::end(nodes1));
+ g.addEdge(0, 1);
+ g.addEdge(1, 2);
+ g.addEdge(2, 0);
+ expected.clear();
+ QTest::newRow("Cyclic") << g << false << expected;
+}
+
+void TestTopoSort::testTopoSort()
+{
+ QFETCH(IntGraph, graph);
+ QFETCH(bool, expectedValid);
+ QFETCH(IntList, expectedOrder);
+
+ const auto result = graph.topologicalSort();
+ QCOMPARE(result.isValid(), expectedValid);
+ if (expectedValid) {
+ QCOMPARE(result.result, expectedOrder);
+ QVERIFY(result.cyclic.isEmpty());
+ } else {
+ QVERIFY(!result.cyclic.isEmpty());
+ }
+}
+
+QTEST_APPLESS_MAIN(TestTopoSort)
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testtoposort.h b/sources/shiboken6/ApiExtractor/tests/testtoposort.h
new file mode 100644
index 000000000..4271d6a0e
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testtoposort.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2020 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTTOPOSORT_H
+#define TESTTOPOSORT_H
+
+#include <QtCore/QObject>
+
+class TestTopoSort : public QObject
+{
+Q_OBJECT
+private slots:
+ void testTopoSort_data();
+ void testTopoSort();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testtyperevision.cpp b/sources/shiboken6/ApiExtractor/tests/testtyperevision.cpp
new file mode 100644
index 000000000..72dae8cc5
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testtyperevision.cpp
@@ -0,0 +1,92 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testtyperevision.h"
+#include "testutil.h"
+#include <abstractmetaenum.h>
+#include <abstractmetalang.h>
+#include <complextypeentry.h>
+#include <enumtypeentry.h>
+#include <flagstypeentry.h>
+#include <typedatabase.h>
+
+#include <qtcompat.h>
+
+#include <QtTest/QTest>
+
+using namespace Qt::StringLiterals;
+
+void TestTypeRevision::testRevisionAttr()
+{
+ const char cppCode[] = "class Rev_0 {};"
+ "class Rev_1 {};"
+ "class Rev_2 { public: enum Rev_3 { X }; enum Rev_5 { Y }; };";
+ const char xmlCode[] = "<typesystem package=\"Foo\">"
+ "<value-type name=\"Rev_0\"/>"
+ "<value-type name=\"Rev_1\" revision=\"1\"/>"
+ "<object-type name=\"Rev_2\" revision=\"2\">"
+ " <enum-type name=\"Rev_3\" revision=\"3\" flags=\"Flag_4\" flags-revision=\"4\" />"
+ " <enum-type name=\"Rev_5\" revision=\"5\" flags=\"Flag_5\" />"
+ "</object-type>"
+ "</typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto rev0 = AbstractMetaClass::findClass(classes, "Rev_0");
+ QCOMPARE(rev0->typeEntry()->revision(), 0);
+
+ const auto rev1 = AbstractMetaClass::findClass(classes, "Rev_1");
+ QCOMPARE(rev1->typeEntry()->revision(), 1);
+
+ const auto rev2 = AbstractMetaClass::findClass(classes, "Rev_2");
+ QCOMPARE(rev2->typeEntry()->revision(), 2);
+
+ auto rev3 = rev2->findEnum(u"Rev_3"_s);
+ QVERIFY(rev3.has_value());
+ QCOMPARE(rev3->typeEntry()->revision(), 3);
+ auto rev4 = rev3->typeEntry()->flags();
+ QCOMPARE(rev4->revision(), 4);
+ auto rev5 = rev2->findEnum(u"Rev_5"_s);
+ QVERIFY(rev5.has_value());
+ EnumTypeEntryCPtr revEnumTypeEntry = rev5->typeEntry();
+ QCOMPARE(revEnumTypeEntry->revision(), 5);
+ QCOMPARE(revEnumTypeEntry->flags()->revision(), 5);
+}
+
+
+void TestTypeRevision::testVersion_data()
+{
+ QTest::addColumn<QString>("version");
+ QTest::addColumn<int>("expectedClassCount");
+
+ QTest::newRow("none") << QString() << 2;
+ QTest::newRow("1.0") << QString::fromLatin1("1.0") << 1; // Bar20 excluded
+ QTest::newRow("2.0") << QString::fromLatin1("2.0") << 2;
+ QTest::newRow("3.0") << QString::fromLatin1("3.0") << 1; // Bar excluded by "until"
+}
+
+void TestTypeRevision::testVersion()
+{
+ QFETCH(QString, version);
+ QFETCH(int, expectedClassCount);
+
+ const char cppCode[] = R"CPP(
+class Bar {};
+class Bar20 {};
+)CPP";
+ const char xmlCode[] = R"XML(
+<typesystem package="Foo">
+ <value-type name="Bar" until="2.0"/>
+ <value-type name="Bar20" since="2.0"/>
+</typesystem>
+)XML";
+
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, true, version));
+ QVERIFY(builder);
+
+ QCOMPARE(builder->classes().size(), expectedClassCount);
+}
+
+QTEST_APPLESS_MAIN(TestTypeRevision)
+
+
diff --git a/sources/shiboken6/ApiExtractor/tests/testtyperevision.h b/sources/shiboken6/ApiExtractor/tests/testtyperevision.h
new file mode 100644
index 000000000..84af839d2
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testtyperevision.h
@@ -0,0 +1,19 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTTYPEREVISION_H
+#define TESTTYPEREVISION_H
+
+#include <QtCore/QObject>
+
+class TestTypeRevision : public QObject
+{
+ Q_OBJECT
+
+private slots:
+ void testRevisionAttr();
+ void testVersion_data();
+ void testVersion();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testutil.h b/sources/shiboken6/ApiExtractor/tests/testutil.h
new file mode 100644
index 000000000..dc4e3b2da
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testutil.h
@@ -0,0 +1,65 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTUTIL_H
+#define TESTUTIL_H
+#include <QtCore/QBuffer>
+#include <QtCore/QDebug>
+#include <QtCore/QDir>
+#include <QtCore/QTemporaryFile>
+#include "abstractmetabuilder.h"
+#include "reporthandler.h"
+#include "typedatabase.h"
+
+#include <exception>
+#include <memory>
+
+namespace TestUtil
+{
+ static AbstractMetaBuilder *parse(const char *cppCode, const char *xmlCode,
+ bool silent = true,
+ const QString &apiVersion = {},
+ const QStringList &dropTypeEntries = {},
+ LanguageLevel languageLevel = LanguageLevel::Default)
+ {
+ ReportHandler::setSilent(silent);
+ ReportHandler::startTimer();
+ auto *td = TypeDatabase::instance(true);
+ if (apiVersion.isEmpty())
+ TypeDatabase::clearApiVersions();
+ else if (!TypeDatabase::setApiVersion(QLatin1StringView("*"), apiVersion))
+ return nullptr;
+ td->setDropTypeEntries(dropTypeEntries);
+ QBuffer buffer;
+ // parse typesystem
+ buffer.setData(xmlCode);
+ if (!buffer.open(QIODevice::ReadOnly))
+ return nullptr;
+ if (!td->parseFile(&buffer))
+ return nullptr;
+ buffer.close();
+ // parse C++ code
+ QTemporaryFile tempSource(QDir::tempPath() + QLatin1StringView("/st_XXXXXX_main.cpp"));
+ if (!tempSource.open()) {
+ qWarning().noquote().nospace() << "Creation of temporary file failed: "
+ << tempSource.errorString();
+ return nullptr;
+ }
+ QByteArrayList arguments;
+ arguments.append(QFile::encodeName(tempSource.fileName()));
+ tempSource.write(cppCode, qint64(strlen(cppCode)));
+ tempSource.close();
+
+ auto builder = std::make_unique<AbstractMetaBuilder>();
+ try {
+ if (!builder->build(arguments, {}, true, languageLevel))
+ return nullptr;
+ } catch (const std::exception &e) {
+ qWarning("%s", e.what());
+ return nullptr;
+ }
+ return builder.release();
+ }
+} // namespace TestUtil
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.cpp b/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.cpp
new file mode 100644
index 000000000..98e30eac2
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.cpp
@@ -0,0 +1,39 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testvaluetypedefaultctortag.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetalang.h>
+#include <complextypeentry.h>
+
+void TestValueTypeDefaultCtorTag::testValueTypeDefaultCtorTagArgument()
+{
+ const char cppCode[] = "\n\
+ struct A {\n\
+ A(int,int);\n\
+ };\n\
+ struct B {};\n\
+ ";
+ const char xmlCode[] = "\n\
+ <typesystem package='Foo'>\n\
+ <primitive-type name='int' />\n\
+ <value-type name='A' default-constructor='A(0, 0)' />\n\
+ <value-type name='B' />\n\
+ </typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode, false));
+ QVERIFY(builder);
+
+ AbstractMetaClassList classes = builder->classes();
+
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ QVERIFY(classA->typeEntry()->hasDefaultConstructor());
+ QCOMPARE(classA->typeEntry()->defaultConstructor(), u"A(0, 0)");
+
+ const auto classB = AbstractMetaClass::findClass(classes, "B");
+ QVERIFY(classB);
+ QVERIFY(!classB->typeEntry()->hasDefaultConstructor());
+}
+
+QTEST_APPLESS_MAIN(TestValueTypeDefaultCtorTag)
diff --git a/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.h b/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.h
new file mode 100644
index 000000000..192c07c1d
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testvaluetypedefaultctortag.h
@@ -0,0 +1,16 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTVALUETYPEDEFAULTCTORTAG_H
+#define TESTVALUETYPEDEFAULTCTORTAG_H
+
+#include <QtCore/QObject>
+
+class TestValueTypeDefaultCtorTag : public QObject
+{
+ Q_OBJECT
+ private slots:
+ void testValueTypeDefaultCtorTagArgument();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/testvoidarg.cpp b/sources/shiboken6/ApiExtractor/tests/testvoidarg.cpp
new file mode 100644
index 000000000..a600181a5
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testvoidarg.cpp
@@ -0,0 +1,67 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "testvoidarg.h"
+#include <QtTest/QTest>
+#include "testutil.h"
+#include <abstractmetaargument.h>
+#include <abstractmetafunction.h>
+#include <abstractmetalang.h>
+#include <typesystem.h>
+
+void TestVoidArg::testVoidParsedFunction()
+{
+ const char cppCode[] = "struct A { void a(void); };";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A'/>\n\
+ </typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction("a");
+ QVERIFY(addedFunc);
+ QCOMPARE(addedFunc->arguments().size(), 0);
+}
+
+void TestVoidArg::testVoidAddedFunction()
+{
+ const char cppCode[] = "struct A { };";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A' >\n\
+ <add-function signature=\"a(void)\"/>\n\
+ </value-type>\n\
+ </typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction("a");
+ QVERIFY(addedFunc);
+ QCOMPARE(addedFunc->arguments().size(), 0);
+
+}
+
+void TestVoidArg::testVoidPointerParsedFunction()
+{
+ const char cppCode[] = "struct A { void a(void*); };";
+ const char xmlCode[] = "\n\
+ <typesystem package=\"Foo\">\n\
+ <value-type name='A' />\n\
+ </typesystem>";
+ QScopedPointer<AbstractMetaBuilder> builder(TestUtil::parse(cppCode, xmlCode));
+ QVERIFY(builder);
+ AbstractMetaClassList classes = builder->classes();
+ const auto classA = AbstractMetaClass::findClass(classes, "A");
+ QVERIFY(classA);
+ const auto addedFunc = classA->findFunction("a");
+ QVERIFY(addedFunc);
+ QCOMPARE(addedFunc->arguments().size(), 1);
+
+}
+
+QTEST_APPLESS_MAIN(TestVoidArg)
diff --git a/sources/shiboken6/ApiExtractor/tests/testvoidarg.h b/sources/shiboken6/ApiExtractor/tests/testvoidarg.h
new file mode 100644
index 000000000..191b9cfb2
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/testvoidarg.h
@@ -0,0 +1,17 @@
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#ifndef TESTVOIDARG_H
+#define TESTVOIDARG_H
+#include <QtCore/QObject>
+
+class TestVoidArg : public QObject
+{
+ Q_OBJECT
+private slots:
+ void testVoidParsedFunction();
+ void testVoidPointerParsedFunction();
+ void testVoidAddedFunction();
+};
+
+#endif
diff --git a/sources/shiboken6/ApiExtractor/tests/utf8code.txt b/sources/shiboken6/ApiExtractor/tests/utf8code.txt
new file mode 100644
index 000000000..6d5fa9dcf
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/tests/utf8code.txt
@@ -0,0 +1 @@
+áéíóú \ No newline at end of file