diff options
Diffstat (limited to 'sources/shiboken6/tests')
373 files changed, 26209 insertions, 0 deletions
diff --git a/sources/shiboken6/tests/CMakeLists.txt b/sources/shiboken6/tests/CMakeLists.txt new file mode 100644 index 000000000..05f6e9e60 --- /dev/null +++ b/sources/shiboken6/tests/CMakeLists.txt @@ -0,0 +1,92 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.18) + +if(BUILD_TESTS) + find_package(Qt${QT_MAJOR_VERSION}Test 6.0 REQUIRED) +endif() + +add_subdirectory(libminimal) +if(NOT DEFINED MINIMAL_TESTS) + add_subdirectory(libsample) + add_subdirectory(libsmart) + add_subdirectory(libother) +endif() + +shiboken_get_debug_level(debug_level) + +if(WIN32 OR DEFINED AVOID_PROTECTED_HACK) + message(STATUS "Tests will be generated avoiding the protected hack!") + set(GENERATOR_EXTRA_FLAGS --avoid-protected-hack) +else() + message(STATUS "Tests will be generated using the protected hack!") + set(GENERATOR_EXTRA_FLAGS ) +endif() +list(APPEND GENERATOR_EXTRA_FLAGS ${SHIBOKEN_GENERATOR_EXTRA_FLAGS} ${debug_level}) + +add_subdirectory(minimalbinding) +if(NOT DEFINED MINIMAL_TESTS) + add_subdirectory(samplebinding) + add_subdirectory(smartbinding) + add_subdirectory(otherbinding) +endif() + +if(DEFINED MINIMAL_TESTS) + file(GLOB TEST_FILES minimalbinding/*_test.py) +else() + file(GLOB TEST_FILES minimalbinding/*_test.py + samplebinding/*_test.py + otherbinding/*_test.py + smartbinding/*_test.py + shibokenmodule/*_test.py) +endif() +list(SORT TEST_FILES) + +set(test_blacklist "") + +if(SHIBOKEN_IS_CROSS_BUILD) + # Python_EXECUTABLE will be empty when cross-building. + message(WARNING + "Running tests when cross-compiling is not supported because it would require running " + "a target python interpreter which might have a different architecture than the host." + ) +else() + find_package( + Python + ${USE_PYTHON_VERSION} + REQUIRED + COMPONENTS Interpreter Development + ) +endif() + +if(NOT CTEST_TESTING_TIMEOUT) + set(CTEST_TESTING_TIMEOUT 60) +endif() + +get_filename_component(BUILD_DIR "${libminimal_BINARY_DIR}" DIRECTORY) +get_filename_component(BUILD_DIR "${BUILD_DIR}" DIRECTORY) +get_filename_component(BUILD_DIR "${BUILD_DIR}" DIRECTORY) +foreach(test_file ${TEST_FILES}) + string(REGEX MATCH "/([^/]+)(binding|module)/([^/]+)_test.py" tmp ${test_file}) + set(test_name "${CMAKE_MATCH_1}_${CMAKE_MATCH_3}") + list(FIND test_blacklist ${test_name} expect_fail) + add_test(${test_name} ${Python_EXECUTABLE} ${test_file}) + set_tests_properties(${test_name} PROPERTIES ENVIRONMENT "BUILD_DIR=${BUILD_DIR}") + set_tests_properties(${test_name} PROPERTIES TIMEOUT ${CTEST_TESTING_TIMEOUT}) + if (${expect_fail} GREATER -1) + set_tests_properties(${test_name} PROPERTIES WILL_FAIL TRUE) + endif() +endforeach() + +# dumpcodemodel depends on apiextractor which is not cross-built. +if(SHIBOKEN_BUILD_TOOLS) + add_subdirectory(dumpcodemodel) +endif() + +# FIXME Skipped until add an option to choose the generator +# add_subdirectory(test_generator) + +if (NOT APIEXTRACTOR_DOCSTRINGS_DISABLED) + add_subdirectory(qtxmltosphinxtest) +endif() diff --git a/sources/shiboken6/tests/dumpcodemodel/CMakeLists.txt b/sources/shiboken6/tests/dumpcodemodel/CMakeLists.txt new file mode 100644 index 000000000..e7dbef961 --- /dev/null +++ b/sources/shiboken6/tests/dumpcodemodel/CMakeLists.txt @@ -0,0 +1,16 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +add_executable(dumpcodemodel main.cpp) + +target_include_directories(dumpcodemodel + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/../../ApiExtractor +) + +target_link_libraries(dumpcodemodel + PRIVATE + apiextractor + Qt::Core +) diff --git a/sources/shiboken6/tests/dumpcodemodel/main.cpp b/sources/shiboken6/tests/dumpcodemodel/main.cpp new file mode 100644 index 000000000..eb876634c --- /dev/null +++ b/sources/shiboken6/tests/dumpcodemodel/main.cpp @@ -0,0 +1,260 @@ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include <abstractmetabuilder_p.h> +#include <parser/codemodel.h> +#include <clangparser/compilersupport.h> + +#include <QtCore/QCoreApplication> +#include <QtCore/QCommandLineOption> +#include <QtCore/QCommandLineParser> +#include <QtCore/QDateTime> +#include <QtCore/QDebug> +#include <QtCore/QDir> +#include <QtCore/QFile> +#include <QtCore/QLibraryInfo> +#include <QtCore/QVersionNumber> +#include <QtCore/QXmlStreamWriter> + +#include <iostream> +#include <algorithm> +#include <iterator> + +using namespace Qt::StringLiterals; + +static bool optJoinNamespaces = false; + +static inline QString languageLevelDescription() +{ + return u"C++ Language level (c++11..c++20, default="_s + + QLatin1StringView(clang::languageLevelOption(clang::emulatedCompilerLanguageLevel())) + + u')'; +} + +static void formatDebugOutput(const FileModelItem &dom, bool verbose) +{ + QString output; + { + QDebug debug(&output); + if (verbose) + debug.setVerbosity(3); + debug << dom.get(); + } + std::cout << qPrintable(output) << '\n'; +} + +static const char *primitiveTypes[] = { + "int", "unsigned", "short", "unsigned short", "long", "unsigned long", + "float", "double" +}; + +constexpr auto nameAttribute = "name"_L1; + +static void formatXmlClass(QXmlStreamWriter &writer, const ClassModelItem &klass); + +static void formatXmlEnum(QXmlStreamWriter &writer, const EnumModelItem &en) +{ + writer.writeStartElement(u"enum-type"_s); + writer.writeAttribute(nameAttribute, en->name()); + writer.writeEndElement(); +} + +static bool useClass(const ClassModelItem &c) +{ + return c->classType() != CodeModel::Union && c->templateParameters().isEmpty() + && !c->name().isEmpty(); // No anonymous structs +} + +static void formatXmlScopeMembers(QXmlStreamWriter &writer, const ScopeModelItem &nsp) +{ + for (const auto &klass : nsp->classes()) { + if (useClass(klass)) + formatXmlClass(writer, klass); + } + for (const auto &en : nsp->enums()) + formatXmlEnum(writer, en); +} + +static bool isPublicCopyConstructor(const FunctionModelItem &f) +{ + return f->functionType() == CodeModel::CopyConstructor + && f->accessPolicy() == Access::Public && !f->isDeleted(); +} + +static void formatXmlLocationComment(QXmlStreamWriter &writer, const CodeModelItem &i) +{ + QString comment; + QTextStream(&comment) << ' ' << i->fileName() << ':' << i->startLine() << ' '; + writer.writeComment(comment); +} + +static void formatXmlClass(QXmlStreamWriter &writer, const ClassModelItem &klass) +{ + // Heuristics for value types: check on public copy constructors. + const auto functions = klass->functions(); + const bool isValueType = std::any_of(functions.cbegin(), functions.cend(), + isPublicCopyConstructor); + formatXmlLocationComment(writer, klass); + writer.writeStartElement(isValueType ? u"value-type"_s + : u"object-type"_s); + writer.writeAttribute(nameAttribute, klass->name()); + formatXmlScopeMembers(writer, klass); + writer.writeEndElement(); +} + +// Check whether a namespace is relevant for type system +// output, that is, has non template classes, functions or enumerations. +static bool hasMembers(const NamespaceModelItem &nsp) +{ + if (!nsp->namespaces().isEmpty() || !nsp->enums().isEmpty() + || !nsp->functions().isEmpty()) { + return true; + } + const auto classes = nsp->classes(); + return std::any_of(classes.cbegin(), classes.cend(), useClass); +} + +static void startXmlNamespace(QXmlStreamWriter &writer, const NamespaceModelItem &nsp) +{ + formatXmlLocationComment(writer, nsp); + writer.writeStartElement(u"namespace-type"_s); + writer.writeAttribute(nameAttribute, nsp->name()); +} + +static void formatXmlNamespaceMembers(QXmlStreamWriter &writer, const NamespaceModelItem &nsp) +{ + auto nestedNamespaces = nsp->namespaces(); + for (auto i = nestedNamespaces.size() - 1; i >= 0; --i) { + if (!hasMembers(nestedNamespaces.at(i))) + nestedNamespaces.removeAt(i); + } + while (!nestedNamespaces.isEmpty()) { + auto current = nestedNamespaces.takeFirst(); + startXmlNamespace(writer, current); + formatXmlNamespaceMembers(writer, current); + if (optJoinNamespaces) { + // Write out members of identical namespaces and remove + const QString name = current->name(); + for (qsizetype i = 0; i < nestedNamespaces.size(); ) { + if (nestedNamespaces.at(i)->name() == name) { + formatXmlNamespaceMembers(writer, nestedNamespaces.at(i)); + nestedNamespaces.removeAt(i); + } else { + ++i; + } + } + } + writer.writeEndElement(); + } + + for (const auto &func : nsp->functions()) { + const QString signature = func->typeSystemSignature(); + if (!signature.contains(u"operator")) { // Skip free operators + writer.writeStartElement(u"function"_s); + writer.writeAttribute(u"signature"_s, signature); + writer.writeEndElement(); + } + } + formatXmlScopeMembers(writer, nsp); +} + +static void formatXmlOutput(const FileModelItem &dom) +{ + QString output; + QXmlStreamWriter writer(&output); + writer.setAutoFormatting(true); + writer.writeStartDocument(); + writer.writeStartElement(u"typesystem"_s); + writer.writeAttribute(u"package"_s, u"insert_name"_s); + writer.writeComment(u"Auto-generated "_s + + QDateTime::currentDateTime().toString(Qt::ISODate)); + for (auto p : primitiveTypes) { + writer.writeStartElement(u"primitive-type"_s); + writer.writeAttribute(nameAttribute, QLatin1StringView(p)); + writer.writeEndElement(); + } + formatXmlNamespaceMembers(writer, dom); + writer.writeEndElement(); + writer.writeEndDocument(); + std::cout << qPrintable(output) << '\n'; +} + +static const char descriptionFormat[] = R"( +Type system dumper + +Parses a C++ header and dumps out the classes found in typesystem XML syntax. +Arguments are arguments to the compiler the last of which should be the header +or source file. +It is recommended to create a .hh include file including the desired headers +and pass that along with the required include paths. + +Based on Qt %1 and LibClang v%2.)"; + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + + QCommandLineParser parser; + parser.setSingleDashWordOptionMode(QCommandLineParser::ParseAsLongOptions); + parser.setOptionsAfterPositionalArgumentsMode(QCommandLineParser::ParseAsPositionalArguments); + const QString description = + QString::fromLatin1(descriptionFormat).arg(QLatin1StringView(qVersion()), + clang::libClangVersion().toString()); + parser.setApplicationDescription(description); + parser.addHelpOption(); + parser.addVersionOption(); + QCommandLineOption verboseOption(u"verbose"_s, + u"Display verbose output about types"_s); + parser.addOption(verboseOption); + QCommandLineOption debugOption(u"debug"_s, + u"Display debug output"_s); + parser.addOption(debugOption); + + QCommandLineOption joinNamespacesOption({u"j"_s, u"join-namespaces"_s}, + u"Join namespaces"_s); + parser.addOption(joinNamespacesOption); + + QCommandLineOption languageLevelOption(u"std"_s, + languageLevelDescription(), + u"level"_s); + parser.addOption(languageLevelOption); + parser.addPositionalArgument(u"argument"_s, + u"C++ compiler argument"_s, + u"argument(s)"_s); + + parser.process(app); + const QStringList &positionalArguments = parser.positionalArguments(); + if (positionalArguments.isEmpty()) + parser.showHelp(1); + + QByteArrayList arguments; + std::transform(positionalArguments.cbegin(), positionalArguments.cend(), + std::back_inserter(arguments), QFile::encodeName); + + LanguageLevel level = LanguageLevel::Default; + if (parser.isSet(languageLevelOption)) { + const QByteArray value = parser.value(languageLevelOption).toLatin1(); + level = clang::languageLevelFromOption(value.constData()); + if (level == LanguageLevel::Default) { + std::cerr << "Invalid value \"" << value.constData() + << "\" for language level option.\n"; + return -2; + } + } + + optJoinNamespaces = parser.isSet(joinNamespacesOption); + + const FileModelItem dom = AbstractMetaBuilderPrivate::buildDom(arguments, true, level, 0); + if (!dom) { + QString message = u"Unable to parse "_s + positionalArguments.join(u' '); + std::cerr << qPrintable(message) << '\n'; + return -2; + } + + if (parser.isSet(debugOption)) + formatDebugOutput(dom, parser.isSet(verboseOption)); + else + formatXmlOutput(dom); + + return 0; +} diff --git a/sources/shiboken6/tests/libminimal/CMakeLists.txt b/sources/shiboken6/tests/libminimal/CMakeLists.txt new file mode 100644 index 000000000..4a10f96bf --- /dev/null +++ b/sources/shiboken6/tests/libminimal/CMakeLists.txt @@ -0,0 +1,21 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +project(libminimal) + +set(libminimal_SRC +containeruser.cpp containeruser.h +libminimalmacros.h +listuser.cpp listuser.h +minbool.h +obj.cpp obj.h +spanuser.cpp spanuser.h +typedef.cpp typedef.h +val.h +) + +add_library(libminimal SHARED ${libminimal_SRC}) +target_include_directories(libminimal PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_compile_definitions(libminimal PRIVATE LIBMINIMAL_BUILD) +set_property(TARGET libminimal PROPERTY PREFIX "") + diff --git a/sources/shiboken6/tests/libminimal/containeruser.cpp b/sources/shiboken6/tests/libminimal/containeruser.cpp new file mode 100644 index 000000000..29af52aef --- /dev/null +++ b/sources/shiboken6/tests/libminimal/containeruser.cpp @@ -0,0 +1,55 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "containeruser.h" + +#include <algorithm> +#include <numeric> + +ContainerUser::ContainerUser() : m_intVector{1, 2, 3}, m_intArray{1, 2, 3} +{ +} + +ContainerUser::~ContainerUser() = default; + +std::vector<int> ContainerUser::createIntVector(int num) +{ + std::vector<int> retval(num); + std::iota(retval.begin(), retval.end(), 0); + return retval; +} + +int ContainerUser::sumIntVector(const std::vector<int> &intVector) +{ + return std::accumulate(intVector.cbegin(), intVector.cend(), 0); +} + +std::vector<int> &ContainerUser::intVector() +{ + return m_intVector; +} + +void ContainerUser::setIntVector(const std::vector<int> &v) +{ + m_intVector = v; +} + +std::array<int, 3> ContainerUser::createIntArray() +{ + return {1, 2, 3}; +} + +int ContainerUser::sumIntArray(const std::array<int, 3> &intArray) +{ + return std::accumulate(intArray.cbegin(), intArray.cend(), 0); +} + +std::array<int, 3> &ContainerUser::intArray() +{ + return m_intArray; +} + +void ContainerUser::setIntArray(const std::array<int, 3> &a) +{ + m_intArray = a; +} diff --git a/sources/shiboken6/tests/libminimal/containeruser.h b/sources/shiboken6/tests/libminimal/containeruser.h new file mode 100644 index 000000000..55e4020ec --- /dev/null +++ b/sources/shiboken6/tests/libminimal/containeruser.h @@ -0,0 +1,36 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef CONTAINERUSER_H +#define CONTAINERUSER_H + +#include "libminimalmacros.h" + +#include <array> +#include <vector> + +/// Exercise simple, sequential containers. More advanced tests are in ListUser +class LIBMINIMAL_API ContainerUser +{ +public: + ContainerUser(); + ~ContainerUser(); + + static std::vector<int> createIntVector(int num); + static int sumIntVector(const std::vector<int> &intVector); + + std::vector<int> &intVector(); + void setIntVector(const std::vector<int> &); + + static std::array<int, 3> createIntArray(); + static int sumIntArray(const std::array<int, 3> &intArray); + + std::array<int, 3> &intArray(); + void setIntArray(const std::array<int, 3> &); + +private: + std::vector<int> m_intVector; + std::array<int, 3> m_intArray; +}; + +#endif // CONTAINERUSER_H diff --git a/sources/shiboken6/tests/libminimal/libminimalmacros.h b/sources/shiboken6/tests/libminimal/libminimalmacros.h new file mode 100644 index 000000000..099c1f1de --- /dev/null +++ b/sources/shiboken6/tests/libminimal/libminimalmacros.h @@ -0,0 +1,49 @@ +// 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 LIBMINIMALMACROS_H +#define LIBMINIMALMACROS_H + +#if defined _WIN32 +# define LIBMINIMAL_EXPORT __declspec(dllexport) +# ifdef _MSC_VER +# define LIBMINIMAL_IMPORT __declspec(dllimport) +# else +# define LIBMINIMAL_IMPORT +# endif +#else +# define LIBMINIMAL_EXPORT __attribute__ ((visibility("default"))) +# define LIBMINIMAL_IMPORT +#endif + +#ifdef LIBMINIMAL_BUILD +# define LIBMINIMAL_API LIBMINIMAL_EXPORT +#else +# define LIBMINIMAL_API LIBMINIMAL_IMPORT +#endif + +#define LIBMINIMAL_DEFAULT_COPY(Class) \ + Class(const Class &) noexcept = default; \ + Class &operator=(const Class &) noexcept = default; + +#define LIBMINIMAL_DISABLE_COPY(Class) \ + Class(const Class &) = delete;\ + Class &operator=(const Class &) = delete; + +#define LIBMINIMAL_DEFAULT_MOVE(Class) \ + Class(Class &&) noexcept = default; \ + Class &operator=(Class &&) noexcept = default; + +#define LIBMINIMAL_DEFAULT_COPY_MOVE(Class) \ + LIBMINIMAL_DEFAULT_COPY(Class) \ + LIBMINIMAL_DEFAULT_MOVE(Class) + +#define LIBMINIMAL_DISABLE_MOVE(Class) \ + Class(Class &&) = delete; \ + Class &operator=(Class &&) = delete; + +#define LIBMINIMAL_DISABLE_COPY_MOVE(Class) \ + LIBMINIMAL_DISABLE_COPY(Class) \ + LIBMINIMAL_DISABLE_MOVE(Class) + +#endif // LIBMINIMALMACROS_H diff --git a/sources/shiboken6/tests/libminimal/listuser.cpp b/sources/shiboken6/tests/libminimal/listuser.cpp new file mode 100644 index 000000000..93c399542 --- /dev/null +++ b/sources/shiboken6/tests/libminimal/listuser.cpp @@ -0,0 +1,133 @@ +// 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 "listuser.h" + +#include <algorithm> +#include <cstdlib> +#include <numeric> + +std::list<int> ListUser::createIntList(int num) +{ + std::list<int> retval(num); + std::iota(retval.begin(), retval.end(), 0); + return retval; +} + +int ListUser::sumIntList(std::list<int> intList) +{ + return std::accumulate(intList.begin(), intList.end(), 0); +} + +int ListUser::sumIntListDefaultParamConstRef(const std::list<int> &intList) +{ + return sumIntList(intList); +} + +int ListUser::sumIntListDefaultParam(std::list<int> intList) +{ + return sumIntList(intList); +} + +std::list<MinBool> ListUser::createMinBoolList(MinBool mb1, MinBool mb2) +{ + std::list<MinBool> retval; + retval.push_back(mb1); + retval.push_back(mb2); + return retval; +} + +MinBool ListUser::oredMinBoolList(std::list<MinBool> minBoolList) +{ + MinBool result(false); + for (const auto &m : minBoolList) + result |= m; + return result; +} + +std::list<Val> ListUser::createValList(int num) +{ + std::list<Val> retval; + for (int i = 0; i < num; ++i) + retval.push_back(Val(i)); + return retval; +} + +int ListUser::sumValList(std::list<Val> valList) +{ + int total = 0; + for (const auto &v : valList) + total += v.valId(); + return total; +} +std::list<Obj*> ListUser::createObjList(Obj* o1, Obj* o2) +{ + std::list<Obj*> retval; + retval.push_back(o1); + retval.push_back(o2); + return retval; +} + +int ListUser::sumObjList(std::list<Obj*> objList) +{ + int total = 0; + for (const auto *obj : objList) + total += obj->objId(); + return total; +} + +std::list<std::list<int> > ListUser::createListOfIntLists(int num) +{ + std::list<std::list<int> > retval; + for (int i = 0; i < num; ++i) + retval.push_back(createIntList(num)); + return retval; +} + +int ListUser::sumListOfIntLists(std::list<std::list<int> > intListList) +{ + int total = 0; + for (const auto &list : intListList) + total += std::accumulate(list.begin(), list.end(), 0); + return total; +} + +void ListUser::setStdIntList(const std::list<int> &l) +{ + m_stdIntList = l; +} + +std::list<int> &ListUser::getIntList() +{ + return m_stdIntList; +} + +const std::list<int> &ListUser::getConstIntList() const +{ + return m_stdIntList; +} + +int ListUser::modifyIntListPtr(std::list<int> *list) const +{ + const int oldSize = int(list->size()); + list->push_back(42); + return oldSize; +} + +std::list<int> *ListUser::returnIntListByPtr() const +{ + return nullptr; +} + +int ListUser::callReturnIntListByPtr() const +{ + auto *list = returnIntListByPtr(); + return list != nullptr ? int(list->size()) : 0; +} + +int ListUser::modifyDoubleListPtr(std::list<double> *list) const +{ + const int oldSize = int(list->size()); + list->push_back(42); + return oldSize; +} diff --git a/sources/shiboken6/tests/libminimal/listuser.h b/sources/shiboken6/tests/libminimal/listuser.h new file mode 100644 index 000000000..9904ef27d --- /dev/null +++ b/sources/shiboken6/tests/libminimal/listuser.h @@ -0,0 +1,72 @@ +// 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 LISTUSER_H +#define LISTUSER_H + +#include "obj.h" +#include "val.h" +#include "minbool.h" + +#include "libminimalmacros.h" + +#include <list> + +struct LIBMINIMAL_API ListUser +{ + LIBMINIMAL_DEFAULT_COPY(ListUser) + LIBMINIMAL_DISABLE_MOVE(ListUser) + + ListUser() noexcept = default; + virtual ~ListUser() = default; + + // List of C++ primitive type items + virtual std::list<int> createIntList(int num); + std::list<int> callCreateIntList(int num) { return createIntList(num); } + virtual int sumIntList(std::list<int> intList); + int callSumIntList(std::list<int> intList) { return sumIntList(intList); } + + int sumIntListDefaultParamConstRef(const std::list<int> &intList = {1, 2, 3}); + int sumIntListDefaultParam(std::list<int> intList = {1, 2, 3}); + + // List of C++ MinBool objects used as primitives in Python + virtual std::list<MinBool> createMinBoolList(MinBool mb1, MinBool mb2); + std::list<MinBool> callCreateMinBoolList(MinBool mb1, MinBool mb2) { return createMinBoolList(mb1, mb2); } + virtual MinBool oredMinBoolList(std::list<MinBool> minBoolList); + MinBool callOredMinBoolList(std::list<MinBool> minBoolList) { return oredMinBoolList(minBoolList); } + + // List of C++ value types + virtual std::list<Val> createValList(int num); + std::list<Val> callCreateValList(int num) { return createValList(num); } + virtual int sumValList(std::list<Val> valList); + int callSumValList(std::list<Val> valList) { return sumValList(valList); } + + // List of C++ object types + virtual std::list<Obj*> createObjList(Obj* o1, Obj* o2); + std::list<Obj*> callCreateObjList(Obj* o1, Obj* o2) { return createObjList(o1, o2); } + virtual int sumObjList(std::list<Obj*> objList); + int callSumObjList(std::list<Obj*> objList) { return sumObjList(objList); } + + // List of lists of C++ primitive type items + virtual std::list<std::list<int> > createListOfIntLists(int num); + std::list<std::list<int> > callCreateListOfIntLists(int num) { return createListOfIntLists(num); } + virtual int sumListOfIntLists(std::list<std::list<int> > intListList); + int callSumListOfIntLists(std::list<std::list<int> > intListList) { return sumListOfIntLists(intListList); } + + void setStdIntList(const std::list<int> &l); + std::list<int> &getIntList(); + const std::list<int> &getConstIntList() const; + + int modifyIntListPtr(std::list<int> *list) const; + + virtual std::list<int> *returnIntListByPtr() const; + + int callReturnIntListByPtr() const; + + int modifyDoubleListPtr(std::list<double> *list) const; + + std::list<int> m_stdIntList; +}; + +#endif // LISTUSER_H + diff --git a/sources/shiboken6/tests/libminimal/minbool.h b/sources/shiboken6/tests/libminimal/minbool.h new file mode 100644 index 000000000..e460f466b --- /dev/null +++ b/sources/shiboken6/tests/libminimal/minbool.h @@ -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 + +#ifndef MINBOOL_H +#define MINBOOL_H + +#include "libminimalmacros.h" + +class LIBMINIMAL_API MinBool +{ +public: + inline explicit MinBool(bool b) : m_value(b) {} + bool value() const { return m_value; } + inline MinBool operator!() const { return MinBool(!m_value); } + inline MinBool& operator|=(const MinBool& other) { + m_value |= other.m_value; + return *this; + } + +private: + bool m_value; +}; + +inline bool operator==(MinBool b1, bool b2) { return (!b1).value() == !b2; } +inline bool operator==(bool b1, MinBool b2) { return (!b1) == (!b2).value(); } +inline bool operator==(MinBool b1, MinBool b2) { return (!b1).value() == (!b2).value(); } +inline bool operator!=(MinBool b1, bool b2) { return (!b1).value() != !b2; } +inline bool operator!=(bool b1, MinBool b2) { return (!b1) != (!b2).value(); } +inline bool operator!=(MinBool b1, MinBool b2) { return (!b1).value() != (!b2).value(); } + +class LIBMINIMAL_API MinBoolUser +{ +public: + LIBMINIMAL_DEFAULT_COPY(MinBoolUser) + LIBMINIMAL_DISABLE_MOVE(MinBoolUser) + + MinBoolUser() noexcept : m_minbool(MinBool(false)) {} + virtual ~MinBoolUser() = default; + inline MinBool minBool() { return m_minbool; } + inline void setMinBool(MinBool minBool) { m_minbool = minBool; } + virtual MinBool invertedMinBool() { return !m_minbool; } + inline MinBool callInvertedMinBool() { return invertedMinBool(); } + +private: + MinBool m_minbool; +}; + +#endif diff --git a/sources/shiboken6/tests/libminimal/obj.cpp b/sources/shiboken6/tests/libminimal/obj.cpp new file mode 100644 index 000000000..a63a9c3c9 --- /dev/null +++ b/sources/shiboken6/tests/libminimal/obj.cpp @@ -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 + +#include "obj.h" + +Obj::Obj(int objId) noexcept : m_objId(objId) +{ +} + +Obj::~Obj() = default; + +bool Obj::virtualMethod(int val) +{ + return !bool(val%2); +} + diff --git a/sources/shiboken6/tests/libminimal/obj.h b/sources/shiboken6/tests/libminimal/obj.h new file mode 100644 index 000000000..be0bfb52b --- /dev/null +++ b/sources/shiboken6/tests/libminimal/obj.h @@ -0,0 +1,34 @@ +// 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 OBJ_H +#define OBJ_H + +#include "libminimalmacros.h" + +class LIBMINIMAL_API Obj +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(Obj) + + explicit Obj(int objId) noexcept; + virtual ~Obj(); + + int objId() const { return m_objId; } + void setObjId(int objId) { m_objId = objId; } + + virtual bool virtualMethod(int val); + bool callVirtualMethod(int val) { return virtualMethod(val); } + + virtual Obj* passObjectType(Obj* obj) { return obj; } + Obj* callPassObjectType(Obj* obj) { return passObjectType(obj); } + + virtual Obj* passObjectTypeReference(Obj& obj) { return &obj; } + Obj* callPassObjectTypeReference(Obj& obj) { return passObjectTypeReference(obj); } + +private: + int m_objId; +}; + +#endif // OBJ_H + diff --git a/sources/shiboken6/tests/libminimal/spanuser.cpp b/sources/shiboken6/tests/libminimal/spanuser.cpp new file mode 100644 index 000000000..fea9cd68e --- /dev/null +++ b/sources/shiboken6/tests/libminimal/spanuser.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "spanuser.h" + +#include <numeric> + +SpanUser::SpanUser() = default; + +bool SpanUser::enabled() +{ +#if __cplusplus >= 202002L + return true; +#else + return false; +#endif +} + +#if __cplusplus >= 202002L +IntSpan3 SpanUser::getIntSpan3() +{ + static int iv[] = {1, 2, 3}; + return IntSpan3(iv); +} + +IntSpan SpanUser::getIntSpan() +{ + static int iv[] = {1, 2, 3}; + return IntSpan(iv); +} + +ConstIntSpan3 SpanUser::getConstIntSpan3() +{ + static const int civ[] = {1, 2, 3}; + return ConstIntSpan3(civ); +} + +IntSpan3 SpanUser::getIntSpan3_OpaqueContainer() +{ + static int iv[] = {1, 2, 3}; + return IntSpan3(iv); +} + +int SpanUser::sumIntSpan3(IntSpan3 isp3) +{ + return std::accumulate(isp3.begin(), isp3.end(), 0); +} + +int SpanUser::sumIntSpan(IntSpan isp) +{ + return std::accumulate(isp.begin(), isp.end(), 0); +} + +int SpanUser::sumConstIntSpan3(ConstIntSpan3 ispc3) +{ + return std::accumulate(ispc3.begin(), ispc3.end(), 0); +} +#endif // C++ 20 diff --git a/sources/shiboken6/tests/libminimal/spanuser.h b/sources/shiboken6/tests/libminimal/spanuser.h new file mode 100644 index 000000000..c78ba35e7 --- /dev/null +++ b/sources/shiboken6/tests/libminimal/spanuser.h @@ -0,0 +1,35 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef SPANUSER_H +#define SPANUSER_H + +#include "libminimalmacros.h" + +#if __cplusplus >= 202002L +# include <span> + +using IntSpan3 = std::span<int, 3>; +using IntSpan = std::span<int>; +using ConstIntSpan3 = std::span<const int, 3>; +#endif + +struct LIBMINIMAL_API SpanUser +{ + SpanUser(); + + static bool enabled(); + +#if __cplusplus >= 202002L + static IntSpan3 getIntSpan3(); + static IntSpan getIntSpan(); + static ConstIntSpan3 getConstIntSpan3(); + static IntSpan3 getIntSpan3_OpaqueContainer(); + + static int sumIntSpan3(IntSpan3 isp3); + static int sumIntSpan(IntSpan isp); + static int sumConstIntSpan3(ConstIntSpan3 ispc3); +#endif // C++ 20 +}; + +#endif // SPANUSER_H diff --git a/sources/shiboken6/tests/libminimal/typedef.cpp b/sources/shiboken6/tests/libminimal/typedef.cpp new file mode 100644 index 000000000..115b7be0a --- /dev/null +++ b/sources/shiboken6/tests/libminimal/typedef.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 "typedef.h" + +// +// Test wrapping of a typedef +// +bool arrayFuncInt(std::vector<int> a) +{ + return a.empty(); +} + +bool arrayFuncIntTypedef(MyArray a) +{ + return arrayFuncInt(a); +} + +std::vector<int> arrayFuncIntReturn(int size) +{ + return std::vector<int>(size); +} + +MyArray arrayFuncIntReturnTypedef(int size) +{ + return arrayFuncIntReturn(size); +} + +// +// Test wrapping of a typedef of a typedef +// +bool arrayFunc(std::vector<int> a) +{ + return a.empty(); +} + +bool arrayFuncTypedef(MyArray a) +{ + return arrayFunc(a); +} + +std::vector<int> arrayFuncReturn(int size) +{ + return std::vector<int>(size); +} + +MyArray arrayFuncReturnTypedef(int size) +{ + return arrayFuncReturn(size); +} diff --git a/sources/shiboken6/tests/libminimal/typedef.h b/sources/shiboken6/tests/libminimal/typedef.h new file mode 100644 index 000000000..7116db1b8 --- /dev/null +++ b/sources/shiboken6/tests/libminimal/typedef.h @@ -0,0 +1,29 @@ +// 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 TYPEDEF_H +#define TYPEDEF_H + +#include "libminimalmacros.h" + +#include <vector> + +// Test wrapping of a typedef +using MyArrayInt = std::vector<int>; + +LIBMINIMAL_API bool arrayFuncInt(std::vector<int> a); +LIBMINIMAL_API bool arrayFuncIntTypedef(MyArrayInt a); + +LIBMINIMAL_API std::vector<int> arrayFuncIntReturn(int size); +LIBMINIMAL_API MyArrayInt arrayFuncIntReturnTypedef(int size); + +// Test wrapping of a typedef of a typedef +using MyArray = MyArrayInt; + +LIBMINIMAL_API bool arrayFunc(std::vector<int> a); +LIBMINIMAL_API bool arrayFuncTypedef(MyArray a); + +LIBMINIMAL_API std::vector<int> arrayFuncReturn(int size); +LIBMINIMAL_API MyArray arrayFuncReturnTypedef(int size); + +#endif diff --git a/sources/shiboken6/tests/libminimal/val.h b/sources/shiboken6/tests/libminimal/val.h new file mode 100644 index 000000000..50f090a7d --- /dev/null +++ b/sources/shiboken6/tests/libminimal/val.h @@ -0,0 +1,36 @@ +// 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 VAL_H +#define VAL_H + +#include "libminimalmacros.h" + +class LIBMINIMAL_API Val +{ +public: + explicit Val(int valId) noexcept : m_valId(valId) {} + LIBMINIMAL_DEFAULT_COPY_MOVE(Val) + + virtual ~Val() = default; + + int valId() const { return m_valId; } + void setValId(int valId) { m_valId = valId; } + + virtual Val passValueType(Val val) { return val; } + Val callPassValueType(Val val) { return passValueType(val); } + + virtual Val* passValueTypePointer(Val* val) { return val; } + Val* callPassValueTypePointer(Val* val) { return passValueTypePointer(val); } + + virtual Val* passValueTypeReference(Val& val) { return &val; } + Val* callPassValueTypeReference(Val& val) { return passValueTypeReference(val); } + + enum ValEnum { One, Other }; + ValEnum oneOrTheOtherEnumValue(ValEnum enumValue) { return enumValue == One ? Other : One; } +private: + int m_valId; +}; + +#endif // VAL_H + diff --git a/sources/shiboken6/tests/libother/CMakeLists.txt b/sources/shiboken6/tests/libother/CMakeLists.txt new file mode 100644 index 000000000..0379d740b --- /dev/null +++ b/sources/shiboken6/tests/libother/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +project(libother) + +set(libother_SRC +extendsnoimplicitconversion.h +libothermacros.h +number.cpp number.h +otherderived.cpp otherderived.h +othermultiplederived.cpp othermultiplederived.h +otherobjecttype.cpp otherobjecttype.h +othertypesystypedef.cpp othertypesystypedef.h +smartptrtester.cpp smartptrtester.h +) + +add_library(libother SHARED ${libother_SRC}) +target_include_directories(libother PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_compile_definitions(libother PRIVATE LIBOTHER_BUILD) +target_link_libraries(libother PUBLIC libsample libsmart) +set_property(TARGET libother PROPERTY PREFIX "") + + diff --git a/sources/shiboken6/tests/libother/extendsnoimplicitconversion.h b/sources/shiboken6/tests/libother/extendsnoimplicitconversion.h new file mode 100644 index 000000000..36d503fe8 --- /dev/null +++ b/sources/shiboken6/tests/libother/extendsnoimplicitconversion.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 EXTENDSNOIMPLICITCONVERSION_H +#define EXTENDSNOIMPLICITCONVERSION_H + +#include "libothermacros.h" +#include "noimplicitconversion.h" + +class ExtendsNoImplicitConversion +{ +public: + explicit ExtendsNoImplicitConversion(int objId) : m_objId(objId) {}; + inline int objId() const { return m_objId; } + inline operator NoImplicitConversion() const { return NoImplicitConversion(m_objId); } + +private: + int m_objId; +}; + +#endif // EXTENDSNOIMPLICITCONVERSION_H diff --git a/sources/shiboken6/tests/libother/libothermacros.h b/sources/shiboken6/tests/libother/libothermacros.h new file mode 100644 index 000000000..567757abd --- /dev/null +++ b/sources/shiboken6/tests/libother/libothermacros.h @@ -0,0 +1,18 @@ +// 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 LIBOTHERMACROS_H +#define LIBOTHERMACROS_H + +#include "../libminimal/libminimalmacros.h" + +#define LIBOTHER_EXPORT LIBMINIMAL_EXPORT +#define LIBOTHER_IMPORT LIBMINIMAL_IMPORT + +#ifdef LIBOTHER_BUILD +# define LIBOTHER_API LIBOTHER_EXPORT +#else +# define LIBOTHER_API LIBOTHER_IMPORT +#endif + +#endif // LIBOTHERMACROS_H diff --git a/sources/shiboken6/tests/libother/number.cpp b/sources/shiboken6/tests/libother/number.cpp new file mode 100644 index 000000000..fbf50dc4a --- /dev/null +++ b/sources/shiboken6/tests/libother/number.cpp @@ -0,0 +1,28 @@ +// 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 "number.h" + +#include <sstream> + +Str Number::toStr() const +{ + std::ostringstream in; + in << m_value; + return in.str().c_str(); +} + +Point operator*(const Point &p, const Number &n) +{ + return {p.x() * n.value(), p.y() * n.value()}; +} + +Complex Number::toComplex() const +{ + return Complex(m_value); +} + +Number Number::fromComplex(Complex cpx) +{ + return Number(cpx.real()); +} diff --git a/sources/shiboken6/tests/libother/number.h b/sources/shiboken6/tests/libother/number.h new file mode 100644 index 000000000..2c480e7f2 --- /dev/null +++ b/sources/shiboken6/tests/libother/number.h @@ -0,0 +1,32 @@ +// 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 NUMBER_H +#define NUMBER_H + +#include "libothermacros.h" +#include "str.h" +#include "point.h" +#include "complex.h" + +class LIBOTHER_API Number +{ +public: + explicit Number(int value) : m_value(value) {}; + inline int value() const { return m_value; } + + Str toStr() const; + inline operator Str() const { return toStr(); } + + friend LIBOTHER_API Point operator*(const Point &, const Number &); + + Complex toComplex() const; + static Number fromComplex(Complex cpx); + +private: + int m_value; +}; + +LIBOTHER_API Point operator*(const Point &, const Number &); + +#endif // NUMBER_H diff --git a/sources/shiboken6/tests/libother/otherderived.cpp b/sources/shiboken6/tests/libother/otherderived.cpp new file mode 100644 index 000000000..93a18876e --- /dev/null +++ b/sources/shiboken6/tests/libother/otherderived.cpp @@ -0,0 +1,33 @@ +// 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 "otherderived.h" + +OtherDerived::OtherDerived(int id) : Abstract(id) +{ +} + +OtherDerived::~OtherDerived() = default; + +Abstract *OtherDerived::createObject() +{ + static int id = 100; + return new OtherDerived(id++); +} + +void OtherDerived::pureVirtual() +{ +} + +void *OtherDerived::pureVirtualReturningVoidPtr() +{ + return nullptr; +} + +void OtherDerived::unpureVirtual() +{ +} + +void OtherDerived::pureVirtualPrivate() +{ +} diff --git a/sources/shiboken6/tests/libother/otherderived.h b/sources/shiboken6/tests/libother/otherderived.h new file mode 100644 index 000000000..d6bde8808 --- /dev/null +++ b/sources/shiboken6/tests/libother/otherderived.h @@ -0,0 +1,43 @@ +// 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 OTHERDERIVED_H +#define OTHERDERIVED_H + +#include "libothermacros.h" +#include "abstract.h" +#include "derived.h" +#include "objecttype.h" +#include "complex.h" + +class ObjectType; + +class LIBOTHER_API OtherDerived : public Abstract +{ +public: + OtherDerived(int id = -1); + ~OtherDerived() override; + void pureVirtual() override; + void *pureVirtualReturningVoidPtr() override; + void unpureVirtual() override; + PrintFormat returnAnEnum() override { return Short; } + + inline void useObjectTypeFromOtherModule(ObjectType *) {} + inline Event useValueTypeFromOtherModule(const Event &e) { return e; } + inline Complex useValueTypeFromOtherModule(const Complex &c) { return c; } + inline void useEnumTypeFromOtherModule(OverloadedFuncEnum) {} + + // factory method + static Abstract *createObject(); + + void hideFunction(HideType*) override {} + +protected: + inline const char *getClassName() { return className(); } + const char *className() const override { return "OtherDerived"; } + +private: + void pureVirtualPrivate() override; +}; + +#endif // OTHERDERIVED_H diff --git a/sources/shiboken6/tests/libother/othermultiplederived.cpp b/sources/shiboken6/tests/libother/othermultiplederived.cpp new file mode 100644 index 000000000..cfbbfb2c2 --- /dev/null +++ b/sources/shiboken6/tests/libother/othermultiplederived.cpp @@ -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 + +#include "othermultiplederived.h" + +VirtualMethods OtherMultipleDerived::returnUselessClass() +{ + return VirtualMethods(); +} + +Base1 *OtherMultipleDerived::createObject(const std::string &objName) +{ + if (objName == "Base1") + return new Base1; + if (objName == "MDerived1") + return new MDerived1; + if (objName == "SonOfMDerived1") + return new SonOfMDerived1; + if (objName == "MDerived3") + return new MDerived3; + if (objName == "OtherMultipleDerived") + return new OtherMultipleDerived; + return nullptr; +} diff --git a/sources/shiboken6/tests/libother/othermultiplederived.h b/sources/shiboken6/tests/libother/othermultiplederived.h new file mode 100644 index 000000000..9f90c43a7 --- /dev/null +++ b/sources/shiboken6/tests/libother/othermultiplederived.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 OTHERMULTIPLEDERIVED_H +#define OTHERMULTIPLEDERIVED_H + +#include "libothermacros.h" +#include "multiple_derived.h" +#include "objecttype.h" +#include "virtualmethods.h" + +class ObjectType; + +class LIBOTHER_API OtherMultipleDerived : public OtherBase, public MDerived1 +{ +public: + // this will use CppCopier from other module (bug#142) + VirtualMethods returnUselessClass(); + static Base1 *createObject(const std::string &objName); +}; + +#endif // OTHERMULTIPLEDERIVED_H diff --git a/sources/shiboken6/tests/libother/otherobjecttype.cpp b/sources/shiboken6/tests/libother/otherobjecttype.cpp new file mode 100644 index 000000000..eaaa231be --- /dev/null +++ b/sources/shiboken6/tests/libother/otherobjecttype.cpp @@ -0,0 +1,20 @@ +// 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 "otherobjecttype.h" + +Collector &operator<<(Collector &collector, const OtherObjectType &obj) +{ + collector << obj.identifier() * 2; + return collector; +} + +int OtherObjectType::enumAsInt(SampleNamespace::SomeClass::PublicScopedEnum value) +{ + return static_cast<int>(value); +} + +int OtherObjectType::enumAsIntForInvisibleNamespace(RemovedNamespace1::RemovedNamespace1_Enum value) +{ + return static_cast<int>(value); +} diff --git a/sources/shiboken6/tests/libother/otherobjecttype.h b/sources/shiboken6/tests/libother/otherobjecttype.h new file mode 100644 index 000000000..844795118 --- /dev/null +++ b/sources/shiboken6/tests/libother/otherobjecttype.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 OTHEROBJECTTYPE_H +#define OTHEROBJECTTYPE_H + +#include "libothermacros.h" +#include "objecttype.h" +#include "collector.h" +#include "samplenamespace.h" +#include "removednamespaces.h" + +class LIBOTHER_API OtherObjectType : public ObjectType +{ +public: + static int enumAsInt(SampleNamespace::SomeClass::PublicScopedEnum value); + static int enumAsIntForInvisibleNamespace(RemovedNamespace1::RemovedNamespace1_Enum value); +}; + +LIBOTHER_API Collector &operator<<(Collector &, const OtherObjectType &); + +#endif // OTHEROBJECTTYPE_H diff --git a/sources/shiboken6/tests/libother/othertypesystypedef.cpp b/sources/shiboken6/tests/libother/othertypesystypedef.cpp new file mode 100644 index 000000000..1a50c4edf --- /dev/null +++ b/sources/shiboken6/tests/libother/othertypesystypedef.cpp @@ -0,0 +1,19 @@ +// 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 "othertypesystypedef.h" + +OtherValueWithUnitUser::OtherValueWithUnitUser() = default; + + +ValueWithUnit<double, LengthUnit::Inch> + OtherValueWithUnitUser::doubleMillimeterToInch(ValueWithUnit<double, LengthUnit::Millimeter> v) +{ + return ValueWithUnit<double, LengthUnit::Inch>(v.value() / 254); +} + +ValueWithUnit<int, LengthUnit::Inch> + OtherValueWithUnitUser::intMillimeterToInch(ValueWithUnit<int, LengthUnit::Millimeter> v) +{ + return ValueWithUnit<int, LengthUnit::Inch>(v.value() / 254); +} diff --git a/sources/shiboken6/tests/libother/othertypesystypedef.h b/sources/shiboken6/tests/libother/othertypesystypedef.h new file mode 100644 index 000000000..999b71fd3 --- /dev/null +++ b/sources/shiboken6/tests/libother/othertypesystypedef.h @@ -0,0 +1,21 @@ +// 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 OTHERTYPESYSTYPEDEF_H +#define OTHERTYPESYSTYPEDEF_H + +#include "libothermacros.h" + +#include <typesystypedef.h> + +class LIBOTHER_API OtherValueWithUnitUser +{ +public: + OtherValueWithUnitUser(); + + static ValueWithUnit<double, LengthUnit::Inch> doubleMillimeterToInch(ValueWithUnit<double, LengthUnit::Millimeter>); + + static ValueWithUnit<int, LengthUnit::Inch> intMillimeterToInch(ValueWithUnit<int, LengthUnit::Millimeter>); +}; + +#endif // OTHERTYPESYSTYPEDEF_H diff --git a/sources/shiboken6/tests/libother/smartptrtester.cpp b/sources/shiboken6/tests/libother/smartptrtester.cpp new file mode 100644 index 000000000..1c6496b1a --- /dev/null +++ b/sources/shiboken6/tests/libother/smartptrtester.cpp @@ -0,0 +1,30 @@ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "smartptrtester.h" + +SharedPtr<Str> SmartPtrTester::createSharedPtrStr(const char *what) +{ + return {new Str(what)}; +} + +std::string SmartPtrTester::valueOfSharedPtrStr(const SharedPtr<Str> &str) +{ + return str->cstring(); +} + +SharedPtr<Integer> SmartPtrTester::createSharedPtrInteger(int v) +{ + auto i = SharedPtr<Integer>(new Integer); + i->m_int = v; + return i; +} + +int SmartPtrTester::valueOfSharedPtrInteger(const SharedPtr<Integer> &v) +{ + return v->m_int; +} + +void SmartPtrTester::fiddleInt(const SharedPtr<int> &) // no binding, should not cause errors +{ +} diff --git a/sources/shiboken6/tests/libother/smartptrtester.h b/sources/shiboken6/tests/libother/smartptrtester.h new file mode 100644 index 000000000..6d7991c06 --- /dev/null +++ b/sources/shiboken6/tests/libother/smartptrtester.h @@ -0,0 +1,24 @@ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef SMARTPTRTESTER_H +#define SMARTPTRTESTER_H + +#include "libothermacros.h" + +#include <smart.h> +#include <str.h> + +class LIBOTHER_API SmartPtrTester +{ +public: + SharedPtr<Str> createSharedPtrStr(const char *what); + std::string valueOfSharedPtrStr(const SharedPtr<Str> &); + + SharedPtr<Integer> createSharedPtrInteger(int v); + int valueOfSharedPtrInteger(const SharedPtr<Integer> &); + + void fiddleInt(const SharedPtr<int> &); +}; + +#endif // SMARTPTRTESTER_H diff --git a/sources/shiboken6/tests/libsample/CMakeLists.txt b/sources/shiboken6/tests/libsample/CMakeLists.txt new file mode 100644 index 000000000..926972340 --- /dev/null +++ b/sources/shiboken6/tests/libsample/CMakeLists.txt @@ -0,0 +1,95 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +project(libsample) + +set(libsample_SRC +abstract.cpp abstract.h +blackbox.cpp blackbox.h +bucket.cpp bucket.h +bytearray.cpp bytearray.h +collector.cpp collector.h +complex.cpp complex.h +ctorconvrule.h +ctparam.cpp ctparam.h +cvlist.h +derived.cpp derived.h +derivedusingct.cpp derivedusingct.h +echo.cpp echo.h +exceptiontest.cpp exceptiontest.h +expression.cpp expression.h +filter.cpp filter.h +functions.cpp functions.h +handle.cpp handle.h +implicitconv.cpp implicitconv.h +injectcode.cpp injectcode.h +intwrapper.cpp intwrapper.h +libsamplemacros.h +list.h +listuser.cpp listuser.h +mapuser.cpp mapuser.h +modelindex.h +modifications.cpp modifications.h +modified_constructor.cpp modified_constructor.h +multiple_derived.cpp multiple_derived.h +noimplicitconversion.h +nondefaultctor.h +nontypetemplate.h +null.h +objectmodel.cpp objectmodel.h +objecttype.cpp objecttype.h +objecttypebyvalue.h +objecttypeholder.cpp objecttypeholder.h +objecttypelayout.cpp objecttypelayout.h +objecttypeoperators.cpp objecttypeoperators.h +objectview.cpp objectview.h +oddbool.cpp oddbool.h +onlycopy.cpp onlycopy.h +overload.cpp overload.h +overloadsort.cpp overloadsort.h +pairuser.cpp pairuser.h +pen.cpp pen.h +photon.cpp photon.h +point.cpp point.h +pointerholder.h +pointf.cpp pointf.h +polygon.cpp polygon.h +privatector.h +privatedtor.h +protected.cpp protected.h +rect.h +reference.cpp reference.h +removednamespaces.h +renaming.cpp renaming.h +sample.cpp sample.h +samplenamespace.cpp samplenamespace.h +sbkdate.cpp sbkdate.h +stdcomplex.cpp stdcomplex.h +simplefile.cpp simplefile.h +size.cpp size.h +snakecasetest.cpp snakecasetest.h +sometime.cpp sometime.h +str.cpp str.h +strlist.cpp strlist.h +templateptr.cpp templateptr.h +transform.cpp transform.h +typesystypedef.cpp typesystypedef.h +valueandvirtual.h +virtualmethods.cpp virtualmethods.h +voidholder.h +) + +# Includes windows.h which is causing clashes between class Polygon and +# wingdi.h's Polygon() function. + +if(WIN32) + set_source_files_properties( + bucket.cpp PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON + ) +endif() + +add_library(libsample SHARED ${libsample_SRC}) +target_include_directories(libsample PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_compile_definitions(libsample PRIVATE LIBSAMPLE_BUILD) +set_property(TARGET libsample PROPERTY PREFIX "") + diff --git a/sources/shiboken6/tests/libsample/abstract.cpp b/sources/shiboken6/tests/libsample/abstract.cpp new file mode 100644 index 000000000..0d67d8630 --- /dev/null +++ b/sources/shiboken6/tests/libsample/abstract.cpp @@ -0,0 +1,71 @@ +// 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 "abstract.h" + +#include <iostream> + +const int Abstract::staticPrimitiveField = 0; + +Abstract::Abstract(int id) noexcept : m_id(id) +{ + bitField = 0; +} + +Abstract::~Abstract() = default; + +void Abstract::unpureVirtual() +{ +} + +void Abstract::callUnpureVirtual() +{ + this->unpureVirtual(); +} + +void Abstract::callPureVirtual() +{ + this->pureVirtual(); +} + +void Abstract::show(PrintFormat format) const +{ + std::cout << '<'; + switch(format) { + case Short: + std::cout << this; + break; + case Verbose: + std::cout << "class " << className() << " | cptr: " << this + << ", id: " << m_id; + break; + case OnlyId: + std::cout << "id: " << m_id; + break; + case ClassNameAndId: + std::cout << className() << " - id: " << m_id; + break; + } + std::cout << '>'; +} + +void Abstract::virtualWithOutParameter(int &x) const +{ + x = 42; +} + +int Abstract::callVirtualWithOutParameter() const +{ + int x; + virtualWithOutParameter(x); + return x; +} + +void Abstract::callVirtualGettingEnum(PrintFormat p) +{ + virtualGettingAEnum(p); +} + +void Abstract::virtualGettingAEnum(Abstract::PrintFormat) +{ +} diff --git a/sources/shiboken6/tests/libsample/abstract.h b/sources/shiboken6/tests/libsample/abstract.h new file mode 100644 index 000000000..4c1b98d90 --- /dev/null +++ b/sources/shiboken6/tests/libsample/abstract.h @@ -0,0 +1,91 @@ +// 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 ABSTRACT_H +#define ABSTRACT_H + +#include "libsamplemacros.h" +#include "point.h" +#include "complex.h" + +class ObjectType; + +// this class is not exported to python +class HideType +{ +}; + +class LIBSAMPLE_API Abstract +{ +private: + enum PrivateEnum { + PrivValue0, + PrivValue1, + PrivValue2 = PrivValue1 + 2 + }; +public: + LIBMINIMAL_DISABLE_COPY_MOVE(Abstract) + + enum PrintFormat { + Short, + Verbose, + OnlyId, + ClassNameAndId, + DummyItemToTestPrivateEnum1 = Abstract::PrivValue1, + DummyItemToTestPrivateEnum2 = PrivValue2, + }; + + enum Type { + TpAbstract, TpDerived + }; + + static const int staticPrimitiveField; + int primitiveField = 123; + Complex userPrimitiveField; + Point valueTypeField{12, 34}; + ObjectType *objectTypeField = nullptr; + int toBeRenamedField = 123; + int readOnlyField = 123; + + explicit Abstract(int id = -1) noexcept; + virtual ~Abstract(); + + inline int id() const { return m_id; } + + // factory method + inline static Abstract *createObject() { return nullptr; } + + // method that receives an Object Type + inline static int getObjectId(Abstract *obj) { return obj->id(); } + + virtual void pureVirtual() = 0; + virtual void *pureVirtualReturningVoidPtr() = 0; + virtual void unpureVirtual(); + + virtual PrintFormat returnAnEnum() = 0; + void callVirtualGettingEnum(PrintFormat p); + virtual void virtualGettingAEnum(PrintFormat p); + + void callPureVirtual(); + void callUnpureVirtual(); + + void show(PrintFormat format = Verbose) const; + virtual Type type() const { return TpAbstract; } + + virtual void hideFunction(HideType *arg) = 0; + + virtual void virtualWithOutParameter(int &x) const; + int callVirtualWithOutParameter() const; + +protected: + virtual const char *className() const { return "Abstract"; } + + // Protected bit-field structure member. + unsigned int bitField: 1; + +private: + virtual void pureVirtualPrivate() = 0; + int m_id; +}; + +#endif // ABSTRACT_H diff --git a/sources/shiboken6/tests/libsample/blackbox.cpp b/sources/shiboken6/tests/libsample/blackbox.cpp new file mode 100644 index 000000000..2ac435d3d --- /dev/null +++ b/sources/shiboken6/tests/libsample/blackbox.cpp @@ -0,0 +1,81 @@ +// 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 "blackbox.h" + +BlackBox::~BlackBox() +{ + // Free all maps. + for (const auto &p :m_objects) + delete p.second; + for (const auto &p : m_points) + delete p.second; +} + +int BlackBox::keepObjectType(ObjectType *object) +{ + ++m_ticket; + m_objects.insert({m_ticket, object}); + object->setParent(nullptr); + + return m_ticket; +} + +ObjectType *BlackBox::retrieveObjectType(int ticket) +{ + const auto it = m_objects.find(ticket); + if (it != m_objects.end()) { + ObjectType *second = it->second; + m_objects.erase(it); + return second; + } + return nullptr; +} + +void BlackBox::disposeObjectType(int ticket) +{ + delete retrieveObjectType(ticket); +} + +int BlackBox::keepPoint(Point *point) +{ + ++m_ticket; + m_points.insert({m_ticket, point}); + return m_ticket; +} + +Point *BlackBox::retrievePoint(int ticket) +{ + const auto it = m_points.find(ticket); + if (it != m_points.end()) { + Point *second = it->second; + m_points.erase(it); + return second; + } + return nullptr; +} + +void BlackBox::disposePoint(int ticket) +{ + delete retrievePoint(ticket); +} + +std::list<ObjectType*> BlackBox::objects() +{ + std::list<ObjectType*> l; + + for (const auto &p : m_objects) + l.push_back(p.second); + + return l; +} + +std::list<Point*> BlackBox::points() +{ + std::list<Point*> l; + + for (const auto &p : m_points) + l.push_back(p.second); + + return l; +} diff --git a/sources/shiboken6/tests/libsample/blackbox.h b/sources/shiboken6/tests/libsample/blackbox.h new file mode 100644 index 000000000..9d32670dd --- /dev/null +++ b/sources/shiboken6/tests/libsample/blackbox.h @@ -0,0 +1,44 @@ +// 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 BLACKBOX_H +#define BLACKBOX_H + +#include "libsamplemacros.h" +#include "objecttype.h" +#include "point.h" + +#include <list> +#include <map> + +class LIBSAMPLE_API BlackBox +{ +public: + using ObjectTypeMap = std::map<int, ObjectType*>; + using PointMap = std::map<int, Point*>; + + LIBMINIMAL_DEFAULT_COPY_MOVE(BlackBox) + BlackBox() noexcept = default; + ~BlackBox(); + + int keepObjectType(ObjectType *object); + ObjectType *retrieveObjectType(int ticket); + void disposeObjectType(int ticket); + + int keepPoint(Point *point); + Point *retrievePoint(int ticket); + void disposePoint(int ticket); + + std::list<ObjectType*> objects(); + std::list<Point*> points(); + + inline void referenceToValuePointer(Point*&) {} + inline void referenceToObjectPointer(ObjectType*&) {} + +private: + ObjectTypeMap m_objects; + PointMap m_points; + int m_ticket = -1; +}; + +#endif // BLACKBOX_H diff --git a/sources/shiboken6/tests/libsample/bucket.cpp b/sources/shiboken6/tests/libsample/bucket.cpp new file mode 100644 index 000000000..cafd382a9 --- /dev/null +++ b/sources/shiboken6/tests/libsample/bucket.cpp @@ -0,0 +1,59 @@ +// 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 "bucket.h" + +#include <iostream> + +#ifdef _WIN32 // _WIN32 is defined by all Windows 32 and 64 bit compilers, but not by others. +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include <windows.h> +# define SLEEP(x) Sleep(x) +#else +# include <unistd.h> +# define SLEEP(x) usleep(x) +#endif + +void Bucket::push(int x) +{ + m_data.push_back(x); +} + +int Bucket::pop(void) +{ + int x = 0; + + if (!m_data.empty()) { + x = m_data.front(); + m_data.pop_front(); + } + + return x; +} + +bool Bucket::empty() +{ + return m_data.empty(); +} + +void Bucket::lock() +{ + m_locked = true; + while (m_locked) { + SLEEP(300); + } +} + +void Bucket::unlock() +{ + m_locked = false; +} + +bool Bucket::virtualBlockerMethod() +{ + lock(); + // The return value was added just for diversity sake. + return true; +} diff --git a/sources/shiboken6/tests/libsample/bucket.h b/sources/shiboken6/tests/libsample/bucket.h new file mode 100644 index 000000000..73e8edd78 --- /dev/null +++ b/sources/shiboken6/tests/libsample/bucket.h @@ -0,0 +1,34 @@ +// 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 BUCKET_H +#define BUCKET_H + +#include "libsamplemacros.h" +#include "objecttype.h" + +#include <list> + +class ObjectType; + +class LIBSAMPLE_API Bucket : public ObjectType +{ +public: + Bucket() = default; + void push(int); + int pop(); + bool empty(); + void lock(); + inline bool locked() { return m_locked; } + void unlock(); + + virtual bool virtualBlockerMethod(); + inline bool callVirtualBlockerMethodButYouDontKnowThis() { return virtualBlockerMethod(); } + +private: + std::list<int> m_data; + + volatile bool m_locked = false; +}; + +#endif // BUCKET_H diff --git a/sources/shiboken6/tests/libsample/bytearray.cpp b/sources/shiboken6/tests/libsample/bytearray.cpp new file mode 100644 index 000000000..78d5162b0 --- /dev/null +++ b/sources/shiboken6/tests/libsample/bytearray.cpp @@ -0,0 +1,166 @@ +// 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 "bytearray.h" + +#include <algorithm> +#include <iterator> +#include <cstring> + +ByteArray::ByteArray() : m_data(1, '\0') +{ +} + +ByteArray::ByteArray(char c) +{ + m_data = std::vector<char>(2); + m_data[0] = c; + m_data[1] = '\0'; +} + +ByteArray::ByteArray(const char *data) +{ + size_t len = std::strlen(data); + m_data = std::vector<char>(len + 1); + memcpy(&m_data[0], data, len); + m_data[len] = '\0'; +} + +ByteArray::ByteArray(const char *data, int len) +{ + m_data = std::vector<char>(len + 1); + memcpy(&m_data[0], data, len); + m_data[len] = '\0'; +} + +int ByteArray::size() const +{ + return m_data.size() - 1; +} + +char ByteArray::at(int pos) const +{ + return m_data[pos]; +} + +const char *ByteArray::data() const +{ + return &(m_data[0]); +} + +ByteArray &ByteArray::append(char c) +{ + m_data.pop_back(); + m_data.push_back(c); + m_data.push_back('\0'); + return *this; +} + +ByteArray &ByteArray::append(const char *data) +{ + m_data.pop_back(); + std::copy(data, data + strlen(data), std::back_inserter(m_data)); + m_data.push_back('\0'); + return *this; +} + +ByteArray &ByteArray::append(const char *data, int len) +{ + m_data.pop_back(); + std::copy(data, data + len, std::back_inserter(m_data)); + m_data.push_back('\0'); + return *this; +} + +ByteArray &ByteArray::append(const ByteArray &other) +{ + m_data.pop_back(); + std::copy(other.m_data.begin(), other.m_data.end(), std::back_inserter(m_data)); + return *this; +} + +static bool compare(const std::vector<char> &mine, const char *other) +{ + for (int i = 0; i < (int)mine.size() - 1; ++i) { + if (mine[i] != other[i]) + return false; + } + return true; +} + +bool ByteArray::operator==(const ByteArray &other) const +{ + return m_data == other.m_data; +} +bool operator==(const ByteArray &ba1, const char *ba2) +{ + return compare(ba1.m_data, ba2); +} + +bool operator==(const char *ba1, const ByteArray &ba2) +{ + return compare(ba2.m_data, ba1); +} + +bool ByteArray::operator!=(const ByteArray &other) const +{ + return m_data != other.m_data; +} + +bool operator!=(const ByteArray &ba1, const char *ba2) +{ + return !(ba1 == ba2); +} + +bool operator!=(const char *ba1, const ByteArray &ba2) +{ + return !(ba1 == ba2); +} + +ByteArray &ByteArray::operator+=(char c) +{ + return append(c); +} + +ByteArray &ByteArray::operator+=(const char *data) +{ + return append(data); +} + +ByteArray &ByteArray::operator+=(const ByteArray &other) +{ + return append(other); +} + +ByteArray operator+(const ByteArray &ba1, const ByteArray &ba2) +{ + return ByteArray(ba1) += ba2; +} + +ByteArray operator+(const ByteArray &ba1, const char *ba2) +{ + return ByteArray(ba1) += ByteArray(ba2); +} + +ByteArray operator+(const char *ba1, const ByteArray &ba2) +{ + return ByteArray(ba1) += ba2; +} + +ByteArray operator+(const ByteArray &ba1, char ba2) +{ + return ByteArray(ba1) += ByteArray(ba2); +} + +ByteArray operator+(char ba1, const ByteArray &ba2) +{ + return ByteArray(ba1) += ba2; +} + +unsigned int ByteArray::hash(const ByteArray &byteArray) +{ + unsigned int result = 0; + for (char c : byteArray.m_data) + result = 5U * result + unsigned(c); + return result; +} diff --git a/sources/shiboken6/tests/libsample/bytearray.h b/sources/shiboken6/tests/libsample/bytearray.h new file mode 100644 index 000000000..35ff22367 --- /dev/null +++ b/sources/shiboken6/tests/libsample/bytearray.h @@ -0,0 +1,64 @@ +// 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 BYTEARRAY_H +#define BYTEARRAY_H + +#include "str.h" +#include "libsamplemacros.h" + +#include <vector> + +class LIBSAMPLE_API ByteArray +{ +public: + ByteArray(); + explicit ByteArray(char data); + explicit ByteArray(const char *data); + explicit ByteArray(const char *data, int len); + + int size() const; + char at(int i) const; + char operator[](int i) const; + + const char *data() const; + + ByteArray &append(char c); + ByteArray &append(const char *data); + ByteArray &append(const char *data, int len); + ByteArray &append(const ByteArray &other); + + bool operator==(const ByteArray &other) const; + bool operator!=(const ByteArray &other) const; + + ByteArray &operator+=(char c); + ByteArray &operator+=(const char *data); + ByteArray &operator+=(const ByteArray &other); + + static unsigned int hash(const ByteArray &byteArray); +private: + std::vector<char> m_data; + friend LIBSAMPLE_API bool operator==(const ByteArray &ba1, const char *ba2); + friend LIBSAMPLE_API bool operator==(const char *ba1, const ByteArray &ba2); + friend LIBSAMPLE_API bool operator!=(const ByteArray &ba1, const char *ba2); + friend LIBSAMPLE_API bool operator!=(const char *ba1, const ByteArray &ba2); + + friend LIBSAMPLE_API ByteArray operator+(const ByteArray &ba1, const ByteArray &ba2); + friend LIBSAMPLE_API ByteArray operator+(const ByteArray &ba1, const char *ba2); + friend LIBSAMPLE_API ByteArray operator+(const char *ba1, const ByteArray &ba2); + friend LIBSAMPLE_API ByteArray operator+(const ByteArray &ba1, char ba2); + friend LIBSAMPLE_API ByteArray operator+(char ba1, const ByteArray &ba2); +}; + +LIBSAMPLE_API bool operator==(const ByteArray &ba1, const char *ba2); +LIBSAMPLE_API bool operator==(const char *ba1, const ByteArray &ba2); +LIBSAMPLE_API bool operator!=(const ByteArray &ba1, const char *ba2); +LIBSAMPLE_API bool operator!=(const char *ba1, const ByteArray &ba2); + +LIBSAMPLE_API ByteArray operator+(const ByteArray &ba1, const ByteArray &ba2); +LIBSAMPLE_API ByteArray operator+(const ByteArray &ba1, const char *ba2); +LIBSAMPLE_API ByteArray operator+(const char *ba1, const ByteArray &ba2); +LIBSAMPLE_API ByteArray operator+(const ByteArray &ba1, char ba2); +LIBSAMPLE_API ByteArray operator+(char ba1, const ByteArray &ba2); + +#endif // BYTEARRAY_H diff --git a/sources/shiboken6/tests/libsample/collector.cpp b/sources/shiboken6/tests/libsample/collector.cpp new file mode 100644 index 000000000..579239bcb --- /dev/null +++ b/sources/shiboken6/tests/libsample/collector.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 "collector.h" + +void Collector::clear() +{ + m_items.clear(); +} + +Collector &Collector::operator<<(ObjectType::Identifier item) +{ + m_items.push_back(item); + return *this; +} + +Collector &Collector::operator<<(const ObjectType *obj) +{ + m_items.push_back(obj->identifier()); + return *this; +} + +std::list<ObjectType::Identifier> Collector::items() +{ + return m_items; +} + +int Collector::size() const +{ + return int(m_items.size()); +} + +Collector &operator<<(Collector &s, const IntWrapper &w) +{ + s << w.toInt(); + return s; +} diff --git a/sources/shiboken6/tests/libsample/collector.h b/sources/shiboken6/tests/libsample/collector.h new file mode 100644 index 000000000..26766847a --- /dev/null +++ b/sources/shiboken6/tests/libsample/collector.h @@ -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 + +#ifndef COLLECTOR_H +#define COLLECTOR_H + +#include "libsamplemacros.h" +#include "intwrapper.h" +#include "objecttype.h" + +#include <list> + +class LIBSAMPLE_API Collector +{ +public: + Collector() noexcept = default; + virtual ~Collector() = default; + LIBMINIMAL_DISABLE_COPY_MOVE(Collector) + + void clear(); + + Collector &operator<<(ObjectType::Identifier item); + + Collector &operator<<(const ObjectType *); + + std::list<ObjectType::Identifier> items(); + int size() const; + +private: + std::list<ObjectType::Identifier> m_items; +}; + +/* Helper for testing external operators */ +LIBSAMPLE_API Collector &operator<<(Collector &, const IntWrapper &); + +#endif // COLLECTOR_H + diff --git a/sources/shiboken6/tests/libsample/complex.cpp b/sources/shiboken6/tests/libsample/complex.cpp new file mode 100644 index 000000000..e3bec9aae --- /dev/null +++ b/sources/shiboken6/tests/libsample/complex.cpp @@ -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 + +#include "complex.h" + +#include <iostream> + +Complex::Complex(double real, double imag) noexcept + : m_real(real), m_imag(imag) +{ +} + +Complex Complex::operator+(const Complex &other) +{ + Complex result; + result.setReal(m_real + other.real()); + result.setImaginary(m_imag + other.imag()); + return result; +} + +void Complex::show() const +{ + std::cout << "(real: " << m_real << ", imag: " << m_imag << ")"; +} diff --git a/sources/shiboken6/tests/libsample/complex.h b/sources/shiboken6/tests/libsample/complex.h new file mode 100644 index 000000000..168fe5c44 --- /dev/null +++ b/sources/shiboken6/tests/libsample/complex.h @@ -0,0 +1,32 @@ +// 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 COMPLEX_H +#define COMPLEX_H + +#include "libsamplemacros.h" + +class LIBSAMPLE_API Complex +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(Complex) + + explicit Complex(double real = 0.0, double imag = 0.0) noexcept; + ~Complex() = default; + + inline double real() const { return m_real; } + inline void setReal(double real) { m_real = real; } + inline double imag() const { return m_imag; } + inline void setImaginary(double imag) { m_imag = imag; } + + Complex operator+(const Complex &other); + + void show() const; + +private: + double m_real; + double m_imag; +}; + +#endif // COMPLEX_H + diff --git a/sources/shiboken6/tests/libsample/ctorconvrule.h b/sources/shiboken6/tests/libsample/ctorconvrule.h new file mode 100644 index 000000000..a5411b749 --- /dev/null +++ b/sources/shiboken6/tests/libsample/ctorconvrule.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 CTORCONVRULE_H +#define CTORCONVRULE_H + +#include "libsamplemacros.h" + +class CtorConvRule +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(CtorConvRule) + + explicit CtorConvRule(long value) noexcept : m_value(value) {} + virtual ~CtorConvRule() = default; + virtual void dummyVirtualMethod() {} + long value() { return m_value; } +private: + long m_value; +}; + +#endif diff --git a/sources/shiboken6/tests/libsample/ctparam.cpp b/sources/shiboken6/tests/libsample/ctparam.cpp new file mode 100644 index 000000000..9bbbcfc3f --- /dev/null +++ b/sources/shiboken6/tests/libsample/ctparam.cpp @@ -0,0 +1,20 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "ctparam.h" + +namespace SampleNamespace +{ + +CtParam::CtParam(int value) : m_value(value) +{ +} + +CtParam::~CtParam() = default; + +int CtParam::value() const +{ + return m_value; +} + +} // namespace SampleNamespace diff --git a/sources/shiboken6/tests/libsample/ctparam.h b/sources/shiboken6/tests/libsample/ctparam.h new file mode 100644 index 000000000..fa241b587 --- /dev/null +++ b/sources/shiboken6/tests/libsample/ctparam.h @@ -0,0 +1,26 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef CTPARAM_H +#define CTPARAM_H + +#include "libsamplemacros.h" + +namespace SampleNamespace +{ + +class LIBSAMPLE_API CtParam +{ +public: + explicit CtParam(int value); + virtual ~CtParam(); + + int value() const; + +private: + int m_value; +}; + +} // namespace SampleNamespace + +#endif // CTPARAM_H diff --git a/sources/shiboken6/tests/libsample/cvlist.h b/sources/shiboken6/tests/libsample/cvlist.h new file mode 100644 index 000000000..e09c7d943 --- /dev/null +++ b/sources/shiboken6/tests/libsample/cvlist.h @@ -0,0 +1,28 @@ +// 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 CONSTVALUELIST_H +#define CONSTVALUELIST_H + +#include <list> +#include "libsamplemacros.h" + +class CVValueType +{ + CVValueType(); +}; + +using const_ptr_value_list = std::list<const CVValueType*>; + +// This tests binding generation for a container of a const value type. The +// class doesn't need to do anything; this is just to verify that the generated +// binding code (the container conversion in particular) is const-valid. + +class CVListUser +{ +public: + static const_ptr_value_list produce() { return {}; } + static void consume(const const_ptr_value_list &l) { (void)l; } +}; + +#endif // LIST_H diff --git a/sources/shiboken6/tests/libsample/derived.cpp b/sources/shiboken6/tests/libsample/derived.cpp new file mode 100644 index 000000000..d20880431 --- /dev/null +++ b/sources/shiboken6/tests/libsample/derived.cpp @@ -0,0 +1,88 @@ +// 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 "derived.h" + +#include <iostream> + +Derived::Derived(int id) noexcept : Abstract(id) +{ +} + +Derived::~Derived() = default; + +Abstract *Derived::createObject() +{ + static int id = 100; + return new Derived(id++); +} + +void Derived::pureVirtual() +{ +} + +void *Derived::pureVirtualReturningVoidPtr() +{ + return nullptr; +} + +void Derived::unpureVirtual() +{ +} + +bool Derived::singleArgument(bool b) +{ + return !b; +} + +double +Derived::defaultValue(int n) +{ + return ((double) n) + 0.1; +} + +OverloadedFuncEnum Derived::overloaded(int, int) +{ + return OverloadedFunc_ii; +} + +OverloadedFuncEnum Derived::overloaded(double) +{ + return OverloadedFunc_d; +} + +Derived::OtherOverloadedFuncEnum Derived::otherOverloaded(int, int, bool, double) +{ + return OtherOverloadedFunc_iibd; +} + +Derived::OtherOverloadedFuncEnum Derived::otherOverloaded(int, double) +{ + return OtherOverloadedFunc_id; +} + +struct SecretClass : public Abstract { + void pureVirtual() override {} + void *pureVirtualReturningVoidPtr() override { return nullptr; } + PrintFormat returnAnEnum() override { return Short; } + void hideFunction(HideType*) override {}; +private: + void pureVirtualPrivate() override {} +}; + +Abstract *Derived::triggerImpossibleTypeDiscovery() +{ + return new SecretClass; +} + +struct AnotherSecretClass : public Derived { +}; + +Abstract *Derived::triggerAnotherImpossibleTypeDiscovery() +{ + return new AnotherSecretClass; +} + +void Derived::pureVirtualPrivate() +{ +} diff --git a/sources/shiboken6/tests/libsample/derived.h b/sources/shiboken6/tests/libsample/derived.h new file mode 100644 index 000000000..cf95cb601 --- /dev/null +++ b/sources/shiboken6/tests/libsample/derived.h @@ -0,0 +1,72 @@ +// 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 DERIVED_H +#define DERIVED_H + +#include "libsamplemacros.h" +#include "abstract.h" + +enum OverloadedFuncEnum { + OverloadedFunc_ii, + OverloadedFunc_d +}; + +class LIBSAMPLE_API Derived : public Abstract +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(Derived) + + enum OtherOverloadedFuncEnum { + OtherOverloadedFunc_iibd, + OtherOverloadedFunc_id + }; + + class SomeInnerClass { + public: + void uselessMethod() {} + SomeInnerClass operator+(const SomeInnerClass &other) { return other; } + bool operator==(const SomeInnerClass &) const { return true; } + }; + + explicit Derived(int id = -1) noexcept; + ~Derived() override; + void pureVirtual() override; + void *pureVirtualReturningVoidPtr() override; + void unpureVirtual() override; + + PrintFormat returnAnEnum() override { return Short; } + Type type() const override { return TpDerived; } + + // factory method + static Abstract *createObject(); + + // single argument + bool singleArgument(bool b); + + // method with default value + double defaultValue(int n = 0); + + // overloads + OverloadedFuncEnum overloaded(int i = 0, int d = 0); + OverloadedFuncEnum overloaded(double n); + + // more overloads + OtherOverloadedFuncEnum otherOverloaded(int a, int b, bool c, double d); + OtherOverloadedFuncEnum otherOverloaded(int a, double b); + + inline SomeInnerClass returnMyParameter(const SomeInnerClass &s) { return s; } + + static Abstract *triggerImpossibleTypeDiscovery(); + static Abstract *triggerAnotherImpossibleTypeDiscovery(); + + void hideFunction(HideType*) override {} +protected: + const char *getClassName() { return className(); } + virtual const char *className() const override { return "Derived"; } + +private: + void pureVirtualPrivate() override; +}; +#endif // DERIVED_H + diff --git a/sources/shiboken6/tests/libsample/derivedusingct.cpp b/sources/shiboken6/tests/libsample/derivedusingct.cpp new file mode 100644 index 000000000..720d0ed96 --- /dev/null +++ b/sources/shiboken6/tests/libsample/derivedusingct.cpp @@ -0,0 +1,9 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "derivedusingct.h" + +void DerivedUsingCt::foo() +{ + delete new DerivedUsingCt(42); +} diff --git a/sources/shiboken6/tests/libsample/derivedusingct.h b/sources/shiboken6/tests/libsample/derivedusingct.h new file mode 100644 index 000000000..6bc026d08 --- /dev/null +++ b/sources/shiboken6/tests/libsample/derivedusingct.h @@ -0,0 +1,17 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef DERIVEDUSINGCT_H +#define DERIVEDUSINGCT_H + +#include "libsamplemacros.h" +#include "ctparam.h" + +class LIBSAMPLE_API DerivedUsingCt : public SampleNamespace::CtParam +{ +public: + using CtParam::CtParam; + + void foo(); +}; +#endif // DERIVEDUSINGCT_H diff --git a/sources/shiboken6/tests/libsample/echo.cpp b/sources/shiboken6/tests/libsample/echo.cpp new file mode 100644 index 000000000..7fa8433d3 --- /dev/null +++ b/sources/shiboken6/tests/libsample/echo.cpp @@ -0,0 +1,4 @@ +// 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 "echo.h" diff --git a/sources/shiboken6/tests/libsample/echo.h b/sources/shiboken6/tests/libsample/echo.h new file mode 100644 index 000000000..01b11a4a6 --- /dev/null +++ b/sources/shiboken6/tests/libsample/echo.h @@ -0,0 +1,60 @@ +// 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 ECHO_H +#define ECHO_H + +#include "libsamplemacros.h" +#include "str.h" + +class ObjectType; + +class Echo +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(Echo) + + Echo() noexcept = default; + ~Echo() = default; + + void doNothingWithConstBool(const bool hi); + void methodWithNamedArg(const Str &string = Str{}); + + Str operator()(const Str &s, const int i) { return s + i; } + + // These method are here just for compilation test purposes + Echo &operator<<(unsigned int item); + Echo &operator<<(signed int item); + Echo &operator<<(const ObjectType *item); + Echo &operator<<(Str str); +}; + +inline void Echo::doNothingWithConstBool(const bool) +{ +} + +inline void Echo::methodWithNamedArg(const Str &) +{ +} + +inline Echo &Echo::operator<<(unsigned int) +{ + return *this; +} + +inline Echo &Echo::operator<<(signed int) +{ + return *this; +} + +inline Echo &Echo::operator<<(const ObjectType *) +{ + return *this; +} + +inline Echo &Echo::operator<<(Str) +{ + return *this; +} + +#endif // ECHO_H diff --git a/sources/shiboken6/tests/libsample/exceptiontest.cpp b/sources/shiboken6/tests/libsample/exceptiontest.cpp new file mode 100644 index 000000000..56144e086 --- /dev/null +++ b/sources/shiboken6/tests/libsample/exceptiontest.cpp @@ -0,0 +1,46 @@ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "exceptiontest.h" + +class TestException : public std::exception +{ +public: + const char *what() const noexcept override + { return "TestException"; } +}; + +ExceptionTest::ExceptionTest() = default; + +int ExceptionTest::intThrowStdException(bool doThrow) +{ + if (doThrow) + throw TestException(); + return 1; +} + +void ExceptionTest::voidThrowStdException(bool doThrow) +{ + if (doThrow) + throw TestException(); +} + +int ExceptionTest::intThrowInt(bool doThrow) +{ + if (doThrow) + throw 42; + return 1; +} + +void ExceptionTest::voidThrowInt(bool doThrow) +{ + if (doThrow) + throw 42; +} + +ExceptionTest *ExceptionTest::create(bool doThrow) +{ + if (doThrow) + throw TestException(); + return new ExceptionTest; +} diff --git a/sources/shiboken6/tests/libsample/exceptiontest.h b/sources/shiboken6/tests/libsample/exceptiontest.h new file mode 100644 index 000000000..b5812a090 --- /dev/null +++ b/sources/shiboken6/tests/libsample/exceptiontest.h @@ -0,0 +1,25 @@ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef EXCEPTIONTEST_H +#define EXCEPTIONTEST_H + +#include "libsamplemacros.h" + +#include <exception> + +class LIBSAMPLE_API ExceptionTest +{ + public: + ExceptionTest(); + + int intThrowStdException(bool doThrow); + void voidThrowStdException(bool doThrow); + + int intThrowInt(bool doThrow); + void voidThrowInt(bool doThrow); + + static ExceptionTest *create(bool doThrow); +}; + +#endif // EXCEPTIONTEST_H diff --git a/sources/shiboken6/tests/libsample/expression.cpp b/sources/shiboken6/tests/libsample/expression.cpp new file mode 100644 index 000000000..6f3c5fdc5 --- /dev/null +++ b/sources/shiboken6/tests/libsample/expression.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 "expression.h" + +#include <sstream> + +Expression::Expression() noexcept = default; + +Expression::Expression(int number) noexcept : m_value(number) +{ +} + +Expression Expression::operator+(const Expression &other) +{ + Expression expr; + expr.m_operation = Add; + expr.m_operand1 = std::make_shared<Expression>(*this); + expr.m_operand2 = std::make_shared<Expression>(other); + return expr; +} + +Expression Expression::operator-(const Expression &other) +{ + Expression expr; + expr.m_operation = Add; + expr.m_operand1 = std::make_shared<Expression>(*this); + expr.m_operand2 = std::make_shared<Expression>(other); + return expr; +} + +Expression Expression::operator<(const Expression &other) +{ + Expression expr; + expr.m_operation = LessThan; + expr.m_operand1 = std::make_shared<Expression>(*this); + expr.m_operand2 = std::make_shared<Expression>(other); + return expr; +} + +Expression Expression::operator>(const Expression &other) +{ + Expression expr; + expr.m_operation = GreaterThan; + expr.m_operand1 = std::make_shared<Expression>(*this); + expr.m_operand2 = std::make_shared<Expression>(other); + return expr; +} + +std::string Expression::toString() const +{ + std::ostringstream s; + if (m_operation == None) { + s << m_value; + return s.str(); + } + + s << '(' << m_operand1->toString(); + switch (m_operation) { + case Add: + s << '+'; + break; + case Sub: + s << '-'; + break; + case LessThan: + s << '<'; + break; + case GreaterThan: + s << '<'; + break; + default: + s << '?'; + break; + } + s << m_operand2->toString() << ')'; + return s.str(); +} diff --git a/sources/shiboken6/tests/libsample/expression.h b/sources/shiboken6/tests/libsample/expression.h new file mode 100644 index 000000000..e7c5b7306 --- /dev/null +++ b/sources/shiboken6/tests/libsample/expression.h @@ -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 + + +#ifndef EXPRESSION_H +#define EXPRESSION_H + +#include "libsamplemacros.h" + +#include <memory> +#include <string> + +class LIBSAMPLE_API Expression +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(Expression) + + enum Operation { + None, Add, Sub, LessThan, GreaterThan + }; + + explicit Expression(int number) noexcept; + ~Expression() = default; + + Expression operator>(const Expression &other); + Expression operator<(const Expression &other); + Expression operator+(const Expression &other); + Expression operator-(const Expression &other); + + std::string toString() const; +private: + int m_value = 0; + Operation m_operation = None; + std::shared_ptr<Expression> m_operand1; + std::shared_ptr<Expression> m_operand2; + + Expression() noexcept; +}; + +#endif // EXPRESSION_H diff --git a/sources/shiboken6/tests/libsample/filter.cpp b/sources/shiboken6/tests/libsample/filter.cpp new file mode 100644 index 000000000..950847985 --- /dev/null +++ b/sources/shiboken6/tests/libsample/filter.cpp @@ -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 + +#include "filter.h" + +Data::Data(Field field, std::string value) + : m_field(field), m_value(value) +{ +} + +Union::Union(const Data &filter) +{ + m_filters.push_back(filter); +} + +Union::Union(const Intersection &filter) +{ + m_filters.push_back(filter); +} + +Intersection::Intersection(const Data &filter) +{ + m_filters.push_back(filter); +} + +Intersection::Intersection(const Union &filter) +{ + m_filters.push_back(filter); +} + +Intersection operator&(const Intersection &a, const Intersection &b) +{ + Intersection filter; + filter.addFilter(a); + filter.addFilter(b); + + return filter; +} diff --git a/sources/shiboken6/tests/libsample/filter.h b/sources/shiboken6/tests/libsample/filter.h new file mode 100644 index 000000000..d82d38eb8 --- /dev/null +++ b/sources/shiboken6/tests/libsample/filter.h @@ -0,0 +1,70 @@ +// 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 FILTER_H +#define FILTER_H + +#include "libsamplemacros.h" + +#include <string> +#include <list> + +class Intersection; + +class LIBSAMPLE_API Filter +{ +}; + +class LIBSAMPLE_API Data : public Filter +{ +public: + enum Field { + Name, + Album, + Year + }; + + explicit Data(Field field, std::string value); + + Field field() const { return m_field; } + std::string value() const { return m_value; } + +private: + Field m_field; + std::string m_value; +}; + +class LIBSAMPLE_API Union : public Filter +{ +public: + + Union(const Data &); + Union(const Intersection &); + Union() = default; + + std::list<Filter> filters() const { return m_filters; } + void addFilter(const Filter &data) { m_filters.push_back(data); } + +private: + std::list<Filter> m_filters; +}; + +class LIBSAMPLE_API Intersection : public Filter +{ +public: + Intersection(const Data &); + Intersection(const Union &); + Intersection() = default; + + std::list<Filter> filters() const { return m_filters; } + void addFilter(const Filter &data) { m_filters.push_back(data); } + +private: + std::list<Filter> m_filters; +}; + +LIBSAMPLE_API Intersection operator&(const Intersection &a, const Intersection &b); + +#endif // FILTER_H + + diff --git a/sources/shiboken6/tests/libsample/functions.cpp b/sources/shiboken6/tests/libsample/functions.cpp new file mode 100644 index 000000000..ad2f4dd5a --- /dev/null +++ b/sources/shiboken6/tests/libsample/functions.cpp @@ -0,0 +1,232 @@ +// 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 "functions.h" +#include "polygon.h" + +#include <cstring> +#include <algorithm> +#include <iostream> +#include <numeric> + +void printSomething() +{ + std::cout << __FUNCTION__ << std::endl; +} + +int gimmeInt() +{ + static int val = 2; + val = val * 1.3; + return val; +} + +double gimmeDouble() +{ + static double val = 7.77; + val = val * 1.3; + return val; +} + +std::list<Complex> gimmeComplexList() +{ + std::list<Complex> lst; + lst.push_back(Complex()); + lst.push_back(Complex(1.1, 2.2)); + lst.push_back(Complex(1.3, 2.4)); + return lst; +} + +Complex sumComplexPair(std::pair<Complex, Complex> cpx_pair) +{ + return cpx_pair.first + cpx_pair.second; +} + +double multiplyPair(std::pair<double, double> pair) +{ + return pair.first * pair.second; +} + +int countCharacters(const char *text) +{ + return text != nullptr ? int(std::strlen(text)) : -1; +} + +char *makeCString() +{ + char *string = new char[std::strlen(__FUNCTION__) + 1]; + std::strcpy(string, __FUNCTION__); + return string; +} + +const char *returnCString() +{ + return __FUNCTION__; +} + +GlobalOverloadFuncEnum overloadedFunc(int) +{ + return GlobalOverloadFunc_i; +} + +GlobalOverloadFuncEnum overloadedFunc(double) +{ + return GlobalOverloadFunc_d; +} + +char *returnNullPrimitivePointer() +{ + return nullptr; +} + +ObjectType *returnNullObjectTypePointer() +{ + return nullptr; +} + +Event *returnNullValueTypePointer() +{ + return nullptr; +} + +unsigned int doubleUnsignedInt(unsigned int value) +{ + return value * 2; +} + +long long doubleLongLong(long long value) +{ + return value * 2; +} + +unsigned long long doubleUnsignedLongLong(unsigned long long value) +{ + return value * 2; +} + +short doubleShort(short value) +{ + return value * 2; +} + +int acceptInt(int x) +{ + return x; +} + +const int *acceptIntReturnPtr(int x) +{ + return new int(x); +} + +unsigned int acceptUInt(unsigned int x) +{ + return x; +} + +long acceptLong(long x) +{ + return x; +} + +unsigned long acceptULong(unsigned long x) +{ + return x; +} + +double acceptDouble(double x) +{ + return x; +} + +int acceptIntReference(int &x) +{ + return x; +} + +OddBool acceptOddBoolReference(OddBool &x) +{ + return x; +} + +int sumIntArray(int array[4]) +{ + return std::accumulate(array, array + 4, 0); +} + +double sumDoubleArray(double array[4]) +{ + return std::accumulate(array, array + 4, double(0)); +} + +int sumIntMatrix(int m[2][3]) +{ + int result = 0; + for (int r = 0; r < 2; ++r) { + for (int c = 0; c < 3; ++c) + result += m[r][c]; + } + return result; +} + +double sumDoubleMatrix(double m[2][3]) +{ + double result = 0; + for (int r = 0; r < 2; ++r) { + for (int c = 0; c < 3; ++c) + result += m[r][c]; + } + return result; +} + +ArrayModifyTest::ArrayModifyTest() = default; + +int ArrayModifyTest::sumIntArray(int n, int *array) +{ + return std::accumulate(array, array + n, 0); +} + +ClassWithFunctionPointer::ClassWithFunctionPointer() +{ + callFunctionPointer(0, &ClassWithFunctionPointer::doNothing); +} + +void ClassWithFunctionPointer::callFunctionPointer(int dummy, void (*fp)(void *)) +{ + size_t a = dummy; + fp(reinterpret_cast<void *>(a)); +} + +void ClassWithFunctionPointer::doNothing(void *operand) +{ + (void) operand; +} + +std::string addStdStrings(const std::string &s1, const std::string &s2) +{ + return s1 + s2; +} + +std::wstring addStdWStrings(const std::wstring &s1, const std::wstring &s2) +{ + return s1 + s2; +} + +void testNullPtrT(std::nullptr_t) +{ + std::cout << __FUNCTION__ << '\n'; +} + +int takePolygon(Polygon &&p) +{ + auto p2 = std::move(p); + std::cout << __FUNCTION__ << ' ' << p2.points().size() << " points\n"; + return int(p2.points().size()); +} + +int takeObjectType(ObjectType &&o) +{ + auto o2 = std::move(o); + std::cout << __FUNCTION__ << ' ' << o2.objectName().cstring() << '\n'; + return o2.objectName().size(); +} diff --git a/sources/shiboken6/tests/libsample/functions.h b/sources/shiboken6/tests/libsample/functions.h new file mode 100644 index 000000000..b745aed6b --- /dev/null +++ b/sources/shiboken6/tests/libsample/functions.h @@ -0,0 +1,91 @@ +// 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 FUNCTIONS_H +#define FUNCTIONS_H + +#include "libsamplemacros.h" +#include "oddbool.h" +#include "complex.h" +#include "objecttype.h" + +#include <list> +#include <utility> + +class Polygon; + +enum GlobalEnum { + NoThing, + FirstThing, + SecondThing, + ThirdThing +}; + +enum GlobalOverloadFuncEnum { + GlobalOverloadFunc_i, + GlobalOverloadFunc_d +}; + +LIBSAMPLE_API void printSomething(); +LIBSAMPLE_API int gimmeInt(); +LIBSAMPLE_API double gimmeDouble(); +LIBSAMPLE_API double multiplyPair(std::pair<double, double> pair); +LIBSAMPLE_API std::list<Complex> gimmeComplexList(); +LIBSAMPLE_API Complex sumComplexPair(std::pair<Complex, Complex> cpx_pair); + +LIBSAMPLE_API int countCharacters(const char *text); +LIBSAMPLE_API char *makeCString(); +LIBSAMPLE_API const char *returnCString(); + +LIBSAMPLE_API char *returnNullPrimitivePointer(); +LIBSAMPLE_API ObjectType *returnNullObjectTypePointer(); +LIBSAMPLE_API Event *returnNullValueTypePointer(); + +// Tests overloading on functions (!methods) +LIBSAMPLE_API GlobalOverloadFuncEnum overloadedFunc(int val); +LIBSAMPLE_API GlobalOverloadFuncEnum overloadedFunc(double val); + +LIBSAMPLE_API unsigned int doubleUnsignedInt(unsigned int value); +LIBSAMPLE_API long long doubleLongLong(long long value); +LIBSAMPLE_API unsigned long long doubleUnsignedLongLong(unsigned long long value); +LIBSAMPLE_API short doubleShort(short value); + +LIBSAMPLE_API int acceptInt(int x); +LIBSAMPLE_API const int *acceptIntReturnPtr(int x); +LIBSAMPLE_API unsigned int acceptUInt(unsigned int x); +LIBSAMPLE_API long acceptLong(long x); +LIBSAMPLE_API unsigned long acceptULong(unsigned long x); +LIBSAMPLE_API double acceptDouble(double x); + +LIBSAMPLE_API int acceptIntReference(int &x); +LIBSAMPLE_API OddBool acceptOddBoolReference(OddBool &x); + +LIBSAMPLE_API int sumIntArray(int array[4]); +LIBSAMPLE_API double sumDoubleArray(double array[4]); +LIBSAMPLE_API int sumIntMatrix(int m[2][3]); +LIBSAMPLE_API double sumDoubleMatrix(double m[2][3]); + +LIBSAMPLE_API std::string addStdStrings(const std::string &s1, const std::string &s2); +LIBSAMPLE_API std::wstring addStdWStrings(const std::wstring &s1, const std::wstring &s2); + +LIBSAMPLE_API void testNullPtrT(std::nullptr_t); + +LIBSAMPLE_API int takePolygon(Polygon &&p); +LIBSAMPLE_API int takeObjectType(ObjectType &&o); + +class LIBSAMPLE_API ArrayModifyTest +{ +public: + ArrayModifyTest(); + int sumIntArray(int n, int *array); +}; + +class LIBSAMPLE_API ClassWithFunctionPointer +{ +public: + explicit ClassWithFunctionPointer(); + void callFunctionPointer(int dummy, void (*fp)(void *)); + static void doNothing(void *operand); +}; + +#endif // FUNCTIONS_H diff --git a/sources/shiboken6/tests/libsample/handle.cpp b/sources/shiboken6/tests/libsample/handle.cpp new file mode 100644 index 000000000..93c2abe47 --- /dev/null +++ b/sources/shiboken6/tests/libsample/handle.cpp @@ -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 + +#include "handle.h" + +SAMPLE_HANDLE HandleHolder::createHandle() +{ + return (SAMPLE_HANDLE) new OBJ; +} + +bool HandleHolder::compare(HandleHolder *other) +{ + return other->m_handle == m_handle; +} + +bool HandleHolder::compare2(HandleHolder *other) +{ + return other->m_handle2 == m_handle2; +} diff --git a/sources/shiboken6/tests/libsample/handle.h b/sources/shiboken6/tests/libsample/handle.h new file mode 100644 index 000000000..07fc89d15 --- /dev/null +++ b/sources/shiboken6/tests/libsample/handle.h @@ -0,0 +1,53 @@ +// 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 HANDLE_H +#define HANDLE_H + +#include "libsamplemacros.h" + +/* See http://bugs.pyside.org/show_bug.cgi?id=1105. */ +namespace Foo { + using SAMPLE_HANDLE = unsigned long; +} + +class LIBSAMPLE_API OBJ +{ +}; + +using SAMPLE_HANDLE = OBJ *; + +class LIBSAMPLE_API HandleHolder +{ +public: + explicit HandleHolder(SAMPLE_HANDLE ptr = nullptr) : m_handle(ptr) {} + explicit HandleHolder(Foo::SAMPLE_HANDLE val): m_handle2(val) {} + + void set(SAMPLE_HANDLE ptr); + inline void set(const Foo::SAMPLE_HANDLE &val) { m_handle2 = val; } + inline SAMPLE_HANDLE handle() const { return m_handle; } + inline Foo::SAMPLE_HANDLE handle2() const { return m_handle2; } + + static SAMPLE_HANDLE createHandle(); + bool compare(HandleHolder *other); + bool compare2(HandleHolder *other); + +private: + SAMPLE_HANDLE m_handle = nullptr; + Foo::SAMPLE_HANDLE m_handle2 = 0; +}; + +inline void HandleHolder::set(SAMPLE_HANDLE) +{ + SAMPLE_HANDLE tmp = m_handle; + m_handle = tmp; +} + +struct LIBSAMPLE_API PrimitiveStruct {}; +using PrimitiveStructPtr = struct PrimitiveStruct *; +struct LIBSAMPLE_API PrimitiveStructPointerHolder +{ + PrimitiveStructPtr primitiveStructPtr; +}; + +#endif // HANDLE_H diff --git a/sources/shiboken6/tests/libsample/implicitconv.cpp b/sources/shiboken6/tests/libsample/implicitconv.cpp new file mode 100644 index 000000000..887fa6b1c --- /dev/null +++ b/sources/shiboken6/tests/libsample/implicitconv.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 "implicitconv.h" + +ImplicitConv::ImplicitConv(const Null &) : + m_ctorEnum(CtorPrimitiveType) +{ +} + +ImplicitConv ImplicitConv::implicitConvCommon(ImplicitConv implicit) +{ + return implicit; +} + +ImplicitConv ImplicitConv::implicitConvDefault(ImplicitConv implicit) +{ + return implicit; +} + +ImplicitConv::ICOverloadedFuncEnum ImplicitConv::implicitConvOverloading(ImplicitConv, int) +{ + return ImplicitConv::OverFunc_Ii; +} + +ImplicitConv::ICOverloadedFuncEnum ImplicitConv::implicitConvOverloading(ImplicitConv, bool) +{ + return ImplicitConv::OverFunc_Ib; +} + +ImplicitConv::ICOverloadedFuncEnum ImplicitConv::implicitConvOverloading(int) +{ + return ImplicitConv::OverFunc_i; +} + +ImplicitConv::ICOverloadedFuncEnum ImplicitConv::implicitConvOverloading(CtorEnum) +{ + return ImplicitConv::OverFunc_C; +} diff --git a/sources/shiboken6/tests/libsample/implicitconv.h b/sources/shiboken6/tests/libsample/implicitconv.h new file mode 100644 index 000000000..5d69eb487 --- /dev/null +++ b/sources/shiboken6/tests/libsample/implicitconv.h @@ -0,0 +1,60 @@ +// 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 IMPLICITCONV_H +#define IMPLICITCONV_H + +#include "libsamplemacros.h" +#include "null.h" + +class ObjectType; + +class LIBSAMPLE_API ImplicitConv +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(ImplicitConv) + + enum CtorEnum { + CtorNone, + CtorOne, + CtorTwo, + CtorThree, + CtorObjectTypeReference, + CtorPrimitiveType + }; + + enum ICOverloadedFuncEnum { + OverFunc_Ii, + OverFunc_Ib, + OverFunc_i, + OverFunc_C + }; + + ImplicitConv() noexcept = default; + ImplicitConv(int objId) noexcept : m_ctorEnum(CtorOne), m_objId(objId) {} + ImplicitConv(CtorEnum ctorEnum) : m_ctorEnum(ctorEnum) {} + ImplicitConv(ObjectType&) : m_ctorEnum(CtorObjectTypeReference) {} + ImplicitConv(double value, bool=true) : m_ctorEnum(CtorNone), m_value(value) {} + ImplicitConv(const Null &null); + ~ImplicitConv() = default; + + inline CtorEnum ctorEnum() const { return m_ctorEnum; } + inline int objId() const { return m_objId; } + inline double value() const { return m_value; } + + static ImplicitConv implicitConvCommon(ImplicitConv implicit); + + static ImplicitConv implicitConvDefault(ImplicitConv implicit = CtorTwo); + + static ICOverloadedFuncEnum implicitConvOverloading(ImplicitConv implicit, int dummyArg); + static ICOverloadedFuncEnum implicitConvOverloading(ImplicitConv implicit, bool dummyArg); + static ICOverloadedFuncEnum implicitConvOverloading(int dummyArg); + static ICOverloadedFuncEnum implicitConvOverloading(CtorEnum dummyArg); + +private: + CtorEnum m_ctorEnum = CtorNone; + int m_objId = -1; + double m_value = -1.0; +}; + +#endif // IMPLICITCONV_H diff --git a/sources/shiboken6/tests/libsample/injectcode.cpp b/sources/shiboken6/tests/libsample/injectcode.cpp new file mode 100644 index 000000000..707d14ed8 --- /dev/null +++ b/sources/shiboken6/tests/libsample/injectcode.cpp @@ -0,0 +1,78 @@ +// 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 "injectcode.h" + +#include <sstream> + +InjectCode::InjectCode() noexcept = default; + +InjectCode::~InjectCode() = default; + +template<typename T> +const char *InjectCode::toStr(const T &value) +{ + std::ostringstream s; + s << value; + m_valueHolder = s.str(); + return m_valueHolder.c_str(); +} + +const char *InjectCode::simpleMethod1(int arg0, int arg1) +{ + return toStr(arg0 + arg1); +} + +const char *InjectCode::simpleMethod2() +{ + return "_"; +} + +const char *InjectCode::simpleMethod3(int argc, char **argv) +{ + for (int i = 0; i < argc; ++i) + m_valueHolder += argv[i]; + return m_valueHolder.c_str(); +} + +const char *InjectCode::overloadedMethod(int arg0, bool arg1) +{ + toStr(arg0); + m_valueHolder += arg1 ? "true" : "false"; + return m_valueHolder.c_str(); +} + +const char *InjectCode::overloadedMethod(int arg0, double arg1) +{ + return toStr(arg0 + arg1); +} + +const char *InjectCode::overloadedMethod(int argc, char **argv) +{ + return simpleMethod3(argc, argv); +} + +const char *InjectCode::virtualMethod(int arg) +{ + return toStr(arg); +} + +int InjectCode::arrayMethod(int count, int *values) const +{ + int ret = 0; + for (int i=0; i < count; i++) + ret += values[i]; + return ret; +} + +int InjectCode::sumArrayAndLength(int *values) const +{ + int sum = 0; + + while (*values) { + sum = sum + *values + 1; + ++values; + } + + return sum; +} diff --git a/sources/shiboken6/tests/libsample/injectcode.h b/sources/shiboken6/tests/libsample/injectcode.h new file mode 100644 index 000000000..74046dad5 --- /dev/null +++ b/sources/shiboken6/tests/libsample/injectcode.h @@ -0,0 +1,44 @@ +// 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 INJECTCODE_H +#define INJECTCODE_H + +#include "libsamplemacros.h" + +#include <utility> +#include <string> + +class LIBSAMPLE_API InjectCode +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(InjectCode) + + InjectCode() noexcept; + virtual ~InjectCode(); + + const char *simpleMethod1(int arg0, int arg1); + const char *simpleMethod2(); + const char *simpleMethod3(int argc, char **argv); + + const char *overloadedMethod(int argc, char **argv); + const char *overloadedMethod(int arg0, double arg1); + const char *overloadedMethod(int arg0, bool arg1); + + virtual int arrayMethod(int count, int *values) const; + inline int callArrayMethod(int count, int *values) const { return arrayMethod(count, values); } + virtual const char *virtualMethod(int arg); + int sumArrayAndLength(int *values) const; + +private: + // This attr is just to retain the memory pointed by all return values, + // So, the memory returned by all methods will be valid until someone call + // another method of this class. + std::string m_valueHolder; + + template<typename T> + const char *toStr(const T &value); +}; + +#endif // INJECTCODE_H + diff --git a/sources/shiboken6/tests/libsample/intwrapper.cpp b/sources/shiboken6/tests/libsample/intwrapper.cpp new file mode 100644 index 000000000..0eaf30465 --- /dev/null +++ b/sources/shiboken6/tests/libsample/intwrapper.cpp @@ -0,0 +1,36 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + + +#include "intwrapper.h" + +int IntWrapper::toInt() const +{ + return m_number; +} + +IntWrapper &IntWrapper::operator ++() +{ + ++m_number; + return *this; +} + +IntWrapper IntWrapper::operator++(int) +{ + IntWrapper result(*this); + ++m_number; + return result; +} + +IntWrapper &IntWrapper::operator--() +{ + --m_number; + return *this; +} + +IntWrapper IntWrapper::operator--(int) +{ + IntWrapper result(*this); + --m_number; + return result; +} diff --git a/sources/shiboken6/tests/libsample/intwrapper.h b/sources/shiboken6/tests/libsample/intwrapper.h new file mode 100644 index 000000000..cfda5adc7 --- /dev/null +++ b/sources/shiboken6/tests/libsample/intwrapper.h @@ -0,0 +1,62 @@ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef INTWRAPPER_H +#define INTWRAPPER_H + +#include "libsamplemacros.h" + +// Wrapper around int for testing operators +class LIBSAMPLE_API IntWrapper +{ +public: + constexpr explicit IntWrapper(int i) noexcept : m_number(i) {} + int toInt() const; + + IntWrapper &operator++(); + IntWrapper operator++(int); // Postfix + + IntWrapper &operator--(); + IntWrapper operator--(int); // Postfix + + friend constexpr inline bool operator==(IntWrapper lhs, IntWrapper rhs) noexcept + { return lhs.m_number == rhs.m_number; } + friend constexpr inline bool operator!=(IntWrapper lhs, IntWrapper rhs) noexcept + { return lhs.m_number != rhs.m_number; } + friend constexpr inline bool operator<(IntWrapper lhs, IntWrapper rhs) noexcept + { return lhs.m_number < rhs.m_number; } + friend constexpr inline bool operator>(IntWrapper lhs, IntWrapper rhs) noexcept + { return lhs.m_number > rhs.m_number; } + friend constexpr inline bool operator<=(IntWrapper lhs, IntWrapper rhs) noexcept + { return lhs.m_number <= rhs.m_number; } + friend constexpr inline bool operator>=(IntWrapper lhs, IntWrapper rhs) noexcept + { return lhs.m_number >= rhs.m_number; } + + constexpr inline IntWrapper &operator+=(IntWrapper i); + constexpr inline IntWrapper &operator-=(const IntWrapper i); + + friend constexpr inline IntWrapper operator+(IntWrapper lhs, IntWrapper rhs) noexcept + { return IntWrapper(lhs.m_number + rhs.m_number); } + friend constexpr inline IntWrapper operator-(IntWrapper lhs, IntWrapper rhs) noexcept + { return IntWrapper(lhs.m_number - rhs.m_number); } + + // FIXME: Test spaceship operator with C++ 20: + // auto operator<=>(IntWrapper) const = default; + +private: + int m_number; +}; + +constexpr inline IntWrapper &IntWrapper::operator+=(IntWrapper i) +{ + m_number += i.m_number; + return *this; +} + +constexpr inline IntWrapper &IntWrapper::operator-=(const IntWrapper i) +{ + m_number -= i.m_number; + return *this; +} + +#endif // INTWRAPPER_H diff --git a/sources/shiboken6/tests/libsample/libsamplemacros.h b/sources/shiboken6/tests/libsample/libsamplemacros.h new file mode 100644 index 000000000..93e549bfb --- /dev/null +++ b/sources/shiboken6/tests/libsample/libsamplemacros.h @@ -0,0 +1,18 @@ +// 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 LIBSAMPLEMACROS_H +#define LIBSAMPLEMACROS_H + +#include "../libminimal/libminimalmacros.h" + +#define LIBSAMPLE_EXPORT LIBMINIMAL_EXPORT +#define LIBSAMPLE_IMPORT LIBMINIMAL_IMPORT + +#ifdef LIBSAMPLE_BUILD +# define LIBSAMPLE_API LIBSAMPLE_EXPORT +#else +# define LIBSAMPLE_API LIBSAMPLE_IMPORT +#endif + +#endif // LIBSAMPLEMACROS_H diff --git a/sources/shiboken6/tests/libsample/list.h b/sources/shiboken6/tests/libsample/list.h new file mode 100644 index 000000000..5e06d2a66 --- /dev/null +++ b/sources/shiboken6/tests/libsample/list.h @@ -0,0 +1,99 @@ +// 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 LIST_H +#define LIST_H + +#include <list> +#include "libsamplemacros.h" +#include "point.h" + +class ObjectType; + +template<class T> +class List : public std::list<T> +{ +}; + +class IntList : public List<int> +{ +public: + LIBMINIMAL_DEFAULT_MOVE(IntList) + + enum CtorEnum { + NoParamsCtor, + IntCtor, + CopyCtor, + ListOfIntCtor + }; + + inline IntList() noexcept : m_ctorUsed(NoParamsCtor) {} + inline explicit IntList(int val) : m_ctorUsed(IntCtor) { push_back(val); } + inline IntList(const List<int> &lst) : List<int>(lst), m_ctorUsed(ListOfIntCtor) {} + ~IntList() = default; + + inline IntList(const IntList &lst) : List<int>(lst), m_ctorUsed(CopyCtor) {} + IntList &operator=(const IntList &) = default; + + inline void append(int v) { insert(end(), v); } + CtorEnum constructorUsed() { return m_ctorUsed; } +private: + CtorEnum m_ctorUsed; +}; + +class PointValueList : public List<Point> +{ +public: + LIBMINIMAL_DEFAULT_MOVE(PointValueList) + + enum CtorEnum { + NoParamsCtor, + PointCtor, + CopyCtor, + ListOfPointValuesCtor + }; + + inline PointValueList() noexcept : m_ctorUsed(NoParamsCtor) {} + inline explicit PointValueList(Point val) : m_ctorUsed(PointCtor) { push_back(val); } + inline PointValueList(const List<Point> &lst) : List<Point>(lst), m_ctorUsed(ListOfPointValuesCtor) {} + + inline PointValueList(const PointValueList &lst) : List<Point>(lst), m_ctorUsed(CopyCtor) {} + PointValueList &operator=(const PointValueList &) = default; + ~PointValueList() = default; + + inline void append(Point v) { insert(end(), v); } + CtorEnum constructorUsed() { return m_ctorUsed; } +private: + CtorEnum m_ctorUsed; +}; + +class ObjectTypePtrList : public List<ObjectType*> +{ +public: + LIBMINIMAL_DEFAULT_MOVE(ObjectTypePtrList) + + enum CtorEnum { + NoParamsCtor, + ObjectTypeCtor, + CopyCtor, + ListOfObjectTypePtrCtor + }; + + inline ObjectTypePtrList() = default; + inline ObjectTypePtrList(const ObjectTypePtrList &lst) : + List<ObjectType*>(lst), m_ctorUsed(CopyCtor) {} + inline explicit ObjectTypePtrList(ObjectType *val) : + m_ctorUsed(ObjectTypeCtor) { push_back(val); } + inline ObjectTypePtrList(const List<ObjectType*> &lst) : + List<ObjectType*>(lst), m_ctorUsed(ListOfObjectTypePtrCtor) {} + ~ObjectTypePtrList() = default; + + ObjectTypePtrList &operator=(const ObjectTypePtrList &) = default; + + inline void append(ObjectType *v) { insert(end(), v); } + CtorEnum constructorUsed() { return m_ctorUsed; } +private: + CtorEnum m_ctorUsed = NoParamsCtor; +}; + +#endif // LIST_H diff --git a/sources/shiboken6/tests/libsample/listuser.cpp b/sources/shiboken6/tests/libsample/listuser.cpp new file mode 100644 index 000000000..9bb7f7798 --- /dev/null +++ b/sources/shiboken6/tests/libsample/listuser.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 "listuser.h" + +#include <numeric> +#include <cstdlib> + +std::list<int> ListUser::callCreateList() +{ + return createList(); +} + +ListUser::ListUser() = default; +ListUser::ListUser(const ListUser &other) = default; +ListUser::ListUser(ListUser &&other) noexcept = default; +ListUser &ListUser::operator=(const ListUser &other) = default; +ListUser &ListUser::operator=(ListUser &&other) noexcept = default; +ListUser::~ListUser() = default; + +std::list<int> ListUser::createList() +{ + std::list<int> retval; + for (int i = 0; i < 4; i++) + retval.push_front(rand()); + return retval; +} + +std::list<Complex> ListUser::createComplexList(Complex cpx0, Complex cpx1) +{ + std::list<Complex> retval; + retval.push_back(cpx0); + retval.push_back(cpx1); + return retval; +} + +double ListUser::sumList(std::list<int> vallist) +{ + return std::accumulate(vallist.begin(), vallist.end(), 0.0); +} + +double ListUser::sumList(std::list<double> vallist) +{ + return std::accumulate(vallist.begin(), vallist.end(), 0.0); +} + +ListUser::ListOfSomething ListUser::listOfPoints(const std::list<Point> &) +{ + return ListOfPoint; +} + +ListUser::ListOfSomething ListUser::listOfPoints(const std::list<PointF> &) +{ + return ListOfPointF; +} + +void ListUser::multiplyPointList(PointList &points, double multiplier) +{ + for (auto *point : points) { + point->setX(point->x() * multiplier); + point->setY(point->y() * multiplier); + } +} diff --git a/sources/shiboken6/tests/libsample/listuser.h b/sources/shiboken6/tests/libsample/listuser.h new file mode 100644 index 000000000..96781ed16 --- /dev/null +++ b/sources/shiboken6/tests/libsample/listuser.h @@ -0,0 +1,53 @@ +// 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 LISTUSER_H +#define LISTUSER_H + +#include "complex.h" +#include "point.h" +#include "pointf.h" + +#include "libsamplemacros.h" + +#include <list> + +class LIBSAMPLE_API ListUser +{ +public: + using PointList = std::list<Point *>; + + enum ListOfSomething { + ListOfPoint, + ListOfPointF + }; + + ListUser(); + ListUser(const ListUser &other); + ListUser(ListUser &&other) noexcept; + ListUser &operator=(const ListUser &other); + ListUser &operator=(ListUser &&other) noexcept; + virtual ~ListUser(); + + virtual std::list<int> createList(); + std::list<int> callCreateList(); + + static std::list<Complex> createComplexList(Complex cpx0, Complex cpx1); + + double sumList(std::list<int> vallist); + double sumList(std::list<double> vallist); + + static ListOfSomething listOfPoints(const std::list<Point> &pointlist); + static ListOfSomething listOfPoints(const std::list<PointF> &pointlist); + + static void multiplyPointList(PointList &points, double multiplier); + + inline void setList(std::list<int> lst) { m_lst = lst; } + inline std::list<int> getList() const { return m_lst; } + +private: + std::list<int> m_lst; +}; + +#endif // LISTUSER_H + diff --git a/sources/shiboken6/tests/libsample/main.cpp b/sources/shiboken6/tests/libsample/main.cpp new file mode 100644 index 000000000..1b44642ae --- /dev/null +++ b/sources/shiboken6/tests/libsample/main.cpp @@ -0,0 +1,209 @@ +// 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 <iostream> +#include <list> +#include "abstract.h" +#include "derived.h" +#include "kindergarten.h" +#include "complex.h" +#include "point.h" +#include "size.h" +#include "listuser.h" +#include "samplenamespace.h" + +int +main(int argv, char **argc) +{ + std::cout << std::endl; + + Derived derived; + + std::cout << std::endl; + + derived.unpureVirtual(); + derived.pureVirtual(); + derived.callPureVirtual(); + + std::cout << std::endl; + auto *abs = Abstract::createObject(); + std::cout << "Abstract::createObject(): " << abs << std::endl << std::endl; + delete abs; + + abs = Derived::createObject(); + std::cout << "Derived::createObject() : "; + abs->show(); + std::cout << std::endl; + delete abs; + std::cout << std::endl; + + abs = Derived::createObject(); + std::cout << "Derived::createObject() : "; + abs->show(); + std::cout << std::endl; + delete abs; + std::cout << std::endl; + + std::cout << "\n-----------------------------------------\n"; + + KinderGarten kg; + Derived *d[] = { 0, 0, 0 }; + + for (int i = 0; i < 3; i++) { + d[i] = new Derived(i); + d[i]->show(); + std::cout << std::endl; + kg.addChild(d[i]); + } + + kg.show(); + std::cout << std::endl; + + std::cout << "\n* kill child "; + d[2]->show(); + std::cout << " ----------------\n"; + kg.killChild(d[2]); + kg.show(); + std::cout << std::endl; + + std::cout << "\n* release child "; + d[1]->show(); + std::cout << " -------------\n"; + Abstract *released = kg.releaseChild(d[1]); + std::cout << "released: "; + released->show(); + std::cout << std::endl; + kg.show(); + std::cout << "\n\n* kill children ------------------------------------\n"; + kg.killChildren(); + kg.show(); + std::cout << "\n\n-----------------------------------------\n"; + ListUser lu; + std::cout << "ListUser::createList()\n"; + std::list<int> intlist = lu.createList(); + for (std::list<int>::iterator it = intlist.begin(); it != intlist.end(); it++) + std::cout << "* " << *it << std::endl; + + std::cout << "ListUser::createComplexList\n"; + std::list<Complex> cpxlist = ListUser::createComplexList(Complex(1.1, 2.2), Complex(3.3, 4.4)); + for (std::list<Complex>::iterator it = cpxlist.begin(); it != cpxlist.end(); it++) { + std::cout << "* "; + (*it).show(); + std::cout << std::endl; + } + std::cout << "\n-----------------------------------------\n" + << "SampleNamespace\n"; + + std::cout << "SampleNamespace::RandomNumber: "; + std::cout << SampleNamespace::getNumber(SampleNamespace::RandomNumber); + std::cout << std::endl; + std::cout << "SampleNamespace::UnixTime: "; + std::cout << SampleNamespace::getNumber(SampleNamespace::UnixTime); + std::cout << std::endl; + double val_d = 1.3; + std::cout << "SampleNamespace::powerOfTwo(" << val_d << "): "; + std::cout << SampleNamespace::powerOfTwo(val_d) << std::endl; + int val_i = 7; + std::cout << "SampleNamespace::powerOfTwo(" << val_i << "): "; + std::cout << SampleNamespace::powerOfTwo(val_i) << std::endl; + std::cout << std::endl; + + std::cout << "-----------------------------------------" << std::endl; + std::cout << "Point" << std::endl; + + Point p1(1.1, 2.2); + std::cout << "p1: "; + p1.show(); + std::cout << std::endl; + + Point p2(3.4, 5.6); + std::cout << "p2: "; + p2.show(); + std::cout << std::endl; + + std::cout << "p1 + p2 == "; + (p1 + p2).show(); + std::cout << std::endl; + + std::cout << "p1 * 2.0 == "; + (p1 * 2.0).show(); + std::cout << std::endl; + + std::cout << "1.5 * p2 == "; + (1.5 * p2).show(); + std::cout << std::endl; + + std::cout << "p1: "; + p1.show(); + std::cout << std::endl << "p2: "; + p2.show(); + std::cout << std::endl << "p1 += p2" << std::endl; + p1 += p2; + std::cout << "p1: "; + p1.show(); + std::cout << std::endl; + + std::cout << "p1 == p2 ? " << ((p1 == p2) ? "true" : "false") << std::endl; + std::cout << "p1 == p1 ? " << ((p1 == p1) ? "true" : "false") << std::endl; + std::cout << "p2 == p2 ? " << ((p2 == p2) ? "true" : "false") << std::endl; + + std::cout << "-----------------------------------------" << std::endl; + std::cout << "Size" << std::endl; + + Size s1(2, 2); + std::cout << "s1: "; + s1.show(); + std::cout << ", area: " << s1.calculateArea(); + std::cout << std::endl; + + Size s2(3, 5); + std::cout << "s2: "; + s2.show(); + std::cout << ", area: " << s2.calculateArea(); + std::cout << std::endl; + + std::cout << std::endl; + + std::cout << "s1 == s2 ? " << ((s1 == s2) ? "true" : "false") << std::endl; + std::cout << "s1 != s2 ? " << ((s1 != s2) ? "true" : "false") << std::endl; + + std::cout << "s1 < s2 ? " << ((s1 < s2) ? "true" : "false") << std::endl; + std::cout << "s1 <= s2 ? " << ((s1 <= s2) ? "true" : "false") << std::endl; + std::cout << "s1 > s2 ? " << ((s1 > s2) ? "true" : "false") << std::endl; + std::cout << "s1 >= s2 ? " << ((s1 >= s2) ? "true" : "false") << std::endl; + + std::cout << "s1 < 10 ? " << ((s1 < 10) ? "true" : "false") << std::endl; + std::cout << "s1 <= 10 ? " << ((s1 <= 10) ? "true" : "false") << std::endl; + std::cout << "s1 > 10 ? " << ((s1 > 10) ? "true" : "false") << std::endl; + std::cout << "s1 >= 10 ? " << ((s1 >= 10) ? "true" : "false") << std::endl; + std::cout << "s2 < 10 ? " << ((s2 < 10) ? "true" : "false") << std::endl; + std::cout << "s2 <= 10 ? " << ((s2 <= 10) ? "true" : "false") << std::endl; + std::cout << "s2 > 10 ? " << ((s2 > 10) ? "true" : "false") << std::endl; + std::cout << "s2 >= 10 ? " << ((s2 >= 10) ? "true" : "false") << std::endl; + std::cout << std::endl; + + std::cout << "s1: "; + s1.show(); + std::cout << std::endl << "s2: "; + s2.show(); + std::cout << std::endl << "s1 += s2" << std::endl; + s1 += s2; + std::cout << "s1: "; + s1.show(); + std::cout << std::endl; + + std::cout << std::endl; + + std::cout << "s1: "; + s1.show(); + std::cout << std::endl << "s1 *= 2.0" << std::endl; + s1 *= 2.0; + std::cout << "s1: "; + s1.show(); + std::cout << std::endl; + + std::cout << std::endl; + + return 0; +} + diff --git a/sources/shiboken6/tests/libsample/mapuser.cpp b/sources/shiboken6/tests/libsample/mapuser.cpp new file mode 100644 index 000000000..40059bbcd --- /dev/null +++ b/sources/shiboken6/tests/libsample/mapuser.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 "mapuser.h" + +#include <iostream> + +std::map<std::string, std::pair<Complex, int> > MapUser::callCreateMap() +{ + return createMap(); +} + +std::map<std::string, std::pair<Complex, int> > MapUser::createMap() +{ + std::map<std::string, std::pair<Complex, int> > retval; + + std::pair<Complex, int> value{Complex(1.2, 3.4), 2}; + retval.insert({"zero", value}); + + value = {Complex(5.6, 7.8), 3}; + retval.insert({"one", value}); + + value = {Complex(9.1, 2.3), 5}; + retval.insert({"two", value}); + + return retval; +} + +void MapUser::showMap(std::map<std::string, int> mapping) +{ + std::cout << __FUNCTION__ << std::endl; + for (const auto &p : mapping) + std::cout << p.first << " => " << p.second << std::endl; +} + +void MapUser::pointerToMap(std::map<std::string, std::string> *) +{ +} + +void MapUser::referenceToMap(std::map<std::string, std::string> &) +{ +} + +std::map<int, std::list<std::list<double> > > MapUser::foo() const +{ + std::map<int, std::list<std::list<double> > > result; + return result; +} diff --git a/sources/shiboken6/tests/libsample/mapuser.h b/sources/shiboken6/tests/libsample/mapuser.h new file mode 100644 index 000000000..1677a4bfb --- /dev/null +++ b/sources/shiboken6/tests/libsample/mapuser.h @@ -0,0 +1,45 @@ +// 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 MAPUSER_H +#define MAPUSER_H + +#include "libsamplemacros.h" + +#include "complex.h" +#include "bytearray.h" + +#include <map> +#include <list> +#include <utility> +#include <string> + +class LIBSAMPLE_API MapUser +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(MapUser) + + MapUser() noexcept = default; + virtual ~MapUser() = default; + + virtual std::map<std::string, std::pair<Complex, int> > createMap(); + std::map<std::string, std::pair<Complex, int> > callCreateMap(); + + void showMap(std::map<std::string, int> mapping); + + inline void setMap(std::map<std::string, std::list<int> > map) { m_map = map; } + inline std::map<std::string, std::list<int> > getMap() { return m_map; } + + // Compile test + static void pointerToMap(std::map<std::string, std::string> *arg); + static void referenceToMap(std::map<std::string, std::string> &arg); + + inline const std::map<int, ByteArray> &passMapIntValueType(const std::map<int, ByteArray>& arg) { return arg; } + + std::map<int, std::list<std::list<double> > > foo() const; + +private: + std::map<std::string, std::list<int> > m_map; +}; + +#endif // MAPUSER_H diff --git a/sources/shiboken6/tests/libsample/modelindex.h b/sources/shiboken6/tests/libsample/modelindex.h new file mode 100644 index 000000000..48e1b7de3 --- /dev/null +++ b/sources/shiboken6/tests/libsample/modelindex.h @@ -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 + +#ifndef MODELINDEX_H +#define MODELINDEX_H + +class ModelIndex +{ +public: + ModelIndex() = default; + + inline void setValue(int value) { m_value = value; } + inline int value() const { return m_value; } + static int getValue(const ModelIndex &index) { return index.value(); } + +private: + int m_value = 0; +}; + +class ReferentModelIndex +{ +public: + ReferentModelIndex() = default; + + explicit ReferentModelIndex(const ModelIndex &index) : m_index(index) {} + + inline void setValue(int value) { m_index.setValue(value); } + inline int value() const { return m_index.value(); } + operator const ModelIndex&() const { return m_index; } + +private: + ModelIndex m_index; +}; + +class PersistentModelIndex +{ +public: + PersistentModelIndex() = default; + + explicit PersistentModelIndex(const ModelIndex &index) : m_index(index) {} + + inline void setValue(int value) { m_index.setValue(value); } + inline int value() const { return m_index.value(); } + operator ModelIndex() const { return m_index; } + +private: + ModelIndex m_index; +}; + +#endif // MODELINDEX_H diff --git a/sources/shiboken6/tests/libsample/modifications.cpp b/sources/shiboken6/tests/libsample/modifications.cpp new file mode 100644 index 000000000..6d627c4c1 --- /dev/null +++ b/sources/shiboken6/tests/libsample/modifications.cpp @@ -0,0 +1,207 @@ +// 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 "modifications.h" +#include "objecttype.h" + +#include <iostream> + +Modifications::Modifications() + : m_object(new ObjectType()) +{ + m_object->setObjectName("MyObject"); +} + +Modifications::~Modifications() +{ + delete m_object; +} + +Modifications::OverloadedModFunc Modifications::overloaded(int, bool, Point, Point) +{ + return Overloaded_ibPP; +} + +Modifications::OverloadedModFunc Modifications::overloaded(int, bool, int, int) +{ + return Overloaded_ibii; +} + +Modifications::OverloadedModFunc Modifications::overloaded(int, bool, int, Point) +{ + return Overloaded_ibiP; +} + +Modifications::OverloadedModFunc Modifications::overloaded(int, bool, int, bool) +{ + return Overloaded_ibib; +} + +Modifications::OverloadedModFunc Modifications::overloaded(int, bool, int, double) +{ + return Overloaded_ibid; +} + +void Modifications::argRemoval0(int, bool, int, int) +{ +} + +void Modifications::argRemoval0(int, bool, int, bool) +{ +} + +void Modifications::argRemoval1(int, bool, Point, Point, int) +{ +} + +void Modifications::argRemoval1(int, bool, int, bool) +{ +} + +void Modifications::argRemoval2(int, bool, Point, Point, int) +{ +} + +void Modifications::argRemoval3(int, Point, bool, Point, int) +{ +} + +void Modifications::argRemoval4(int, Point, bool, Point, int) +{ +} + +void Modifications::argRemoval5(int, bool, Point, Point, int) +{ +} + +void Modifications::argRemoval5(int, bool, int, bool) +{ +} + +std::pair<double, double> Modifications::pointToPair(Point pt, bool *ok) +{ + std::pair<double, double> retval(pt.x(), pt.y()); + *ok = true; + return retval; +} + +double Modifications::multiplyPointCoordsPlusValue(bool *ok, Point pt, double value) +{ + double retval = (pt.x() * pt.y()) + value; + *ok = true; + return retval; +} + +int Modifications::doublePlus(int value, int plus) +{ + return (2 * value) + plus; +} + +int Modifications::power(int base, int exponent) +{ + if (exponent == 0) + return 1; + int retval = base; + for (int i = 1; i < exponent; i++) + retval = retval * base; + return retval; +} + +int Modifications::timesTen(int number) +{ + return number * 10; +} + +int Modifications::increment(int number) +{ + return ++number; +} + +void Modifications::exclusiveCppStuff() +{ + std::cout << __FUNCTION__ << std::endl; +} + +int Modifications::cppMultiply(int a, int b) +{ + return a * b; +} + +const char *Modifications::className() +{ + return "Modifications"; +} + +Point Modifications::sumPointArray(int arraySize, const Point pointArray[]) +{ + Point point; + for (int i = 0; i < arraySize; ++i) + point = point + pointArray[i]; + return point; +} + +int Modifications::getSize(const void *data, int size) +{ + (void)data; + return size; +} + +int Modifications::sumPointCoordinates(const Point *point) +{ + return point->x() + point->y(); +} + +double Modifications::differenceOfPointCoordinates(const Point *pt, bool *ok) +{ + if (!pt) { + *ok = false; + return 0.0; + } + *ok = true; + double result = pt->x() - pt->y(); + if (result < 0) + result = result * -1.0; + return result; +} + +bool Modifications::nonConversionRuleForArgumentWithDefaultValue(ObjectType **object) +{ + if (object) + *object = m_object; + return true; +} + +void Modifications::setEnumValue(TestEnum e) +{ + m_enumValue = e; +} + +Modifications::TestEnum Modifications::enumValue() const +{ + return m_enumValue; +} + +Modifications::TestEnum Modifications::defaultEnumValue() const +{ + return TestEnumValue2; +} + +bool Modifications::wasGetAttroCalled() const +{ + return m_getAttroCalled; +} + +void Modifications::notifyGetAttroCalled() +{ + m_getAttroCalled = true; +} + +bool Modifications::wasSetAttroCalled() const +{ + return m_setAttroCalled; +} + +void Modifications::notifySetAttroCalled() +{ + m_setAttroCalled = true; +} diff --git a/sources/shiboken6/tests/libsample/modifications.h b/sources/shiboken6/tests/libsample/modifications.h new file mode 100644 index 000000000..5bd1bac47 --- /dev/null +++ b/sources/shiboken6/tests/libsample/modifications.h @@ -0,0 +1,145 @@ +// 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 MODIFICATIONS_H +#define MODIFICATIONS_H + +#include "libsamplemacros.h" +#include "point.h" +#include "oddbool.h" + +#include <utility> + +class ObjectType; + +class LIBSAMPLE_API Modifications +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(Modifications) + + Modifications(); + virtual ~Modifications(); + + enum OverloadedModFunc { + OverloadedNone, + Overloaded_ibid, + Overloaded_ibib, + Overloaded_ibiP, + Overloaded_ibii, + Overloaded_ibPP + }; + + enum TestEnum { + TestEnumValue1, + TestEnumValue2 + }; + + // those overloaded methods should be heavily modified + // to push the overload decisor to its limits + OverloadedModFunc overloaded(int a0, bool b0, int c0, double d0); + OverloadedModFunc overloaded(int a1, bool b1, int c1, bool d1); + OverloadedModFunc overloaded(int a2, bool b2, int c2, Point d2); + OverloadedModFunc overloaded(int a3, bool b3, int c3 = 123, int d3 = 456); + OverloadedModFunc overloaded(int a4, bool b4, Point c4, Point d4); + + void argRemoval0(int a0, bool a1, int a2 = 123, int a3 = 456); + void argRemoval0(int a0, bool a1, int a2, bool a3); + + void argRemoval1(int a0, bool a1, Point a2 = Point(1, 2), Point a3 = Point(3, 4), + int a4 = 333); + void argRemoval1(int a0, bool a1, int a2, bool a3); + + void argRemoval2(int a0, bool a1, Point a2 = Point(1, 2), Point a3 = Point(3, 4), + int a4 = 333); + + void argRemoval3(int a0, Point a1 = Point(1, 2), bool a2 = true, Point a3 = Point(3, 4), + int a4 = 333); + + void argRemoval4(int a0, Point a1, bool a2, Point a3 = Point(3, 4), int a4 = 333); + + void argRemoval5(int a0, bool a1, Point a2 = Point(1, 2), Point a3 = Point(3, 4), + int a4 = 333); + void argRemoval5(int a0, bool a1, int a2, bool a3); + + // 'ok' must be removed and the return value will be changed + // to a tuple (PyObject*) containing the expected result plus + // the 'ok' value as a Python boolean + std::pair<double, double> pointToPair(Point pt, bool *ok); + + // same as 'pointToPair' except that this time 'ok' is the first argument + double multiplyPointCoordsPlusValue(bool *ok, Point pt, double value); + + // completely remove 'plus' from the Python side + int doublePlus(int value, int plus = 0); + + // the default value for both arguments must be changed in Python + int power(int base = 1, int exponent = 0); + + // in Python set argument default value to 10 + int timesTen(int number); + + // in Python remove the argument default value + int increment(int number = 0); + + // don't export this method to Python + void exclusiveCppStuff(); + + // change the name of this regular method + int cppMultiply(int a, int b); + + // change the name of this virtual method + virtual const char *className(); + + Point sumPointArray(int arraySize, const Point pointArray[]); + + // Replace 'const void*' by 'ByteArray&'. + int getSize(const void *data, int size); + + // Mark the argument with a <no-null-pointer/> tag; + // the test implementation must expect point never to be null. + int sumPointCoordinates(const Point *point); + + // Modify the return value of a virtual method. + virtual double differenceOfPointCoordinates(const Point *pt, bool *ok); + double callDifferenceOfPointCoordinates(const Point *pt, bool *ok) + { return differenceOfPointCoordinates(pt, ok); } + + // Sets an ObjectType in the argument and returns true. + bool nonConversionRuleForArgumentWithDefaultValue(ObjectType **object = nullptr); + ObjectType *getObject() const { return m_object; } + + // Inject code with a %CONVERTTOPYTHON that receives an user's primitive type. + static inline OddBool passOddBool(OddBool ob) { return ob; } + + void setEnumValue(TestEnum e = TestEnumValue1); + TestEnum enumValue() const; + TestEnum defaultEnumValue() const; + + bool wasGetAttroCalled() const; + void notifyGetAttroCalled(); + + bool wasSetAttroCalled() const; + void notifySetAttroCalled(); + +private: + ObjectType *m_object; + TestEnum m_enumValue = TestEnumValue1; + bool m_getAttroCalled = false; + bool m_setAttroCalled = false; +}; + +class LIBSAMPLE_API AbstractModifications : public Modifications +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(AbstractModifications) + + AbstractModifications() noexcept = default; + ~AbstractModifications() override = default; + + inline bool invert(bool value) { return !value; } + + // completely remove this method in Python + virtual void pointlessPureVirtualMethod() = 0; +}; + +#endif // MODIFICATIONS_H diff --git a/sources/shiboken6/tests/libsample/modified_constructor.cpp b/sources/shiboken6/tests/libsample/modified_constructor.cpp new file mode 100644 index 000000000..c39c97738 --- /dev/null +++ b/sources/shiboken6/tests/libsample/modified_constructor.cpp @@ -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 + +#include "modified_constructor.h" + +ModifiedConstructor::ModifiedConstructor(int first_arg) +{ + m_stored_value = first_arg; +} + +int ModifiedConstructor::retrieveValue() const +{ + return m_stored_value; +} + + diff --git a/sources/shiboken6/tests/libsample/modified_constructor.h b/sources/shiboken6/tests/libsample/modified_constructor.h new file mode 100644 index 000000000..a27899f3f --- /dev/null +++ b/sources/shiboken6/tests/libsample/modified_constructor.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 MODIFIEDCONSTRUCTOR_H +#define MODIFIEDCONSTRUCTOR_H + +#include "libsamplemacros.h" + +class LIBSAMPLE_API ModifiedConstructor +{ +public: + + explicit ModifiedConstructor(int first_arg); + int retrieveValue() const; + +private: + int m_stored_value; +}; + +#endif // MODIFIEDCONSTRUCTOR_H + diff --git a/sources/shiboken6/tests/libsample/multiple_derived.cpp b/sources/shiboken6/tests/libsample/multiple_derived.cpp new file mode 100644 index 000000000..be535c62f --- /dev/null +++ b/sources/shiboken6/tests/libsample/multiple_derived.cpp @@ -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 + +#include "multiple_derived.h" + +MDerived1::MDerived1() noexcept = default; + +MDerived2::MDerived2() noexcept = default; + +MDerived3::MDerived3() noexcept = default; + +MDerived4::MDerived4() noexcept = default; + +MDerived5::MDerived5() noexcept = default; + +MDerived1 *MDerived1::transformFromBase1(Base1 *self) +{ + return dynamic_cast<MDerived1*>(self); +} + +MDerived1 *MDerived1::transformFromBase2(Base2 *self) +{ + return dynamic_cast<MDerived1*>(self); +} diff --git a/sources/shiboken6/tests/libsample/multiple_derived.h b/sources/shiboken6/tests/libsample/multiple_derived.h new file mode 100644 index 000000000..8c2143ed6 --- /dev/null +++ b/sources/shiboken6/tests/libsample/multiple_derived.h @@ -0,0 +1,202 @@ +// 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 MDERIVED_H +#define MDERIVED_H + +#include "libsamplemacros.h" + +#include <string> + +class Base1 +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(Base1) + + Base1() noexcept = default; + virtual ~Base1() = default; + + virtual int base1Method() { return m_value; } + + virtual void publicMethod() {}; + +private: + int m_value = 1; +}; + +class Base2 +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(Base2) + + Base2() noexcept = default; + virtual ~Base2() = default; + virtual int base2Method() { return m_value; } + +private: + int m_value = 2; +}; + +class LIBSAMPLE_API MDerived1 : public Base1, public Base2 +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(MDerived1) + + MDerived1() noexcept; + ~MDerived1() override = default; + + int mderived1Method() { return m_value; } + int base1Method () override { return Base1::base1Method() * 10; } + int base2Method() override { return Base2::base2Method() * 10; } + + inline Base1 *castToBase1() { return (Base1*) this; } + inline Base2 *castToBase2() { return (Base2*) this; } + + static MDerived1 *transformFromBase1(Base1 *self); + static MDerived1 *transformFromBase2(Base2 *self); + +private: + void publicMethod() override {} + int m_value = 100; +}; + +class SonOfMDerived1 : public MDerived1 +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(SonOfMDerived1) + + SonOfMDerived1() noexcept = default; + ~SonOfMDerived1() = default; + + inline MDerived1 *castToMDerived1() { return this; } + + int sonOfMDerived1Method() { return m_value; } + +private: + int m_value = 0; +}; + +class Base3 +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(Base3) + + explicit Base3(int val = 3) noexcept : m_value(val) {} + virtual ~Base3() = default; + int base3Method() { return m_value; } + +private: + int m_value; +}; + +class Base4 +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(Base4) + + Base4() noexcept = default; + virtual ~Base4() = default; + int base4Method() { return m_value; } + +private: + int m_value = 4; +}; + +class Base5 +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(Base5) + + Base5() noexcept = default; + virtual ~Base5() = default; + virtual int base5Method() { return m_value; } + +private: + int m_value = 5; +}; + +class Base6 +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(Base6) + + Base6() noexcept = default; + virtual ~Base6() = default; + virtual int base6Method() { return m_value; } + +private: + int m_value = 6; +}; + +class LIBSAMPLE_API MDerived2 : public Base3, public Base4, public Base5, public Base6 +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(MDerived2) + + MDerived2() noexcept; + virtual ~MDerived2() = default; + + inline int base4Method() { return Base3::base3Method() * 10; } + inline int mderived2Method() { return m_value; } + + inline Base3 *castToBase3() { return this; } + inline Base4 *castToBase4() { return this; } + inline Base5 *castToBase5() { return this; } + inline Base6 *castToBase6() { return this; } + +private: + int m_value = 200; +}; + +class LIBSAMPLE_API MDerived3 : public MDerived1, public MDerived2 +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(MDerived3) + + MDerived3() noexcept; + virtual ~MDerived3() = default; + + inline virtual int mderived3Method() { return m_value; } + + inline MDerived1 *castToMDerived1() { return this; } + inline MDerived2 *castToMDerived2() { return this; } + + inline Base3 *castToBase3() { return (Base3*) this; } + +private: + int m_value = 3000; +}; + +class LIBSAMPLE_API MDerived4 : public Base3, public Base4 +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(MDerived4) + + MDerived4() noexcept; + ~MDerived4() = default; + + inline int mderived4Method() { return 0; } + inline int justDummyMethod() { return m_value; } + + inline Base3 *castToBase3() { return this; } + inline Base4 *castToBase4() { return this; } + +private: + int m_value; +}; + +class LIBSAMPLE_API MDerived5 : public Base3, public Base4 +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(MDerived5) + + MDerived5() noexcept; + virtual ~MDerived5() = default; + + virtual int mderived5Method() { return 0; } + + inline Base3 *castToBase3() { return this; } + inline Base4 *castToBase4() { return this; } +}; + +#endif // MDERIVED_H diff --git a/sources/shiboken6/tests/libsample/noimplicitconversion.h b/sources/shiboken6/tests/libsample/noimplicitconversion.h new file mode 100644 index 000000000..a0b91380b --- /dev/null +++ b/sources/shiboken6/tests/libsample/noimplicitconversion.h @@ -0,0 +1,27 @@ +// 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 NOIMPLICITCONVERSION_H +#define NOIMPLICITCONVERSION_H + +#include "libsamplemacros.h" + +// This class must not have implicit conversions AND +// no conversion operators should be defined in its own module. +class NoImplicitConversion +{ +public: + explicit NoImplicitConversion(int objId) : m_objId(objId) {} + inline int objId() const { return m_objId; } + inline static int receivesNoImplicitConversionByValue(NoImplicitConversion arg) + { return arg.m_objId; } + inline static int receivesNoImplicitConversionByPointer(NoImplicitConversion *arg) + { return arg->m_objId; } + inline static int receivesNoImplicitConversionByReference(NoImplicitConversion &arg) + { return arg.m_objId; } +private: + int m_objId; +}; + +#endif // NOIMPLICITCONVERSION_H + diff --git a/sources/shiboken6/tests/libsample/nondefaultctor.h b/sources/shiboken6/tests/libsample/nondefaultctor.h new file mode 100644 index 000000000..fa97b8859 --- /dev/null +++ b/sources/shiboken6/tests/libsample/nondefaultctor.h @@ -0,0 +1,54 @@ +// 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 NONDEFAULTCTOR_H +#define NONDEFAULTCTOR_H + +#include "libsamplemacros.h" + +class NonDefaultCtor +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(NonDefaultCtor) + + explicit NonDefaultCtor(int value) noexcept : m_value(value) + { + } + + virtual ~NonDefaultCtor() = default; + + inline int value() const + { + return m_value; + } + + inline NonDefaultCtor returnMyself() + { + return *this; + } + + inline NonDefaultCtor returnMyself(int) + { + return *this; + } + + inline NonDefaultCtor returnMyself(int, NonDefaultCtor) + { + return *this; + } + + virtual NonDefaultCtor returnMyselfVirtual() + { + return *this; + } + + inline NonDefaultCtor callReturnMyselfVirtual() + { + return returnMyselfVirtual(); + } + +private: + int m_value; +}; + +#endif // NONDEFAULTCTOR_H diff --git a/sources/shiboken6/tests/libsample/nontypetemplate.h b/sources/shiboken6/tests/libsample/nontypetemplate.h new file mode 100644 index 000000000..e41c21604 --- /dev/null +++ b/sources/shiboken6/tests/libsample/nontypetemplate.h @@ -0,0 +1,27 @@ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef NONTYPETEMPLATE_H +#define NONTYPETEMPLATE_H + +#include "libsamplemacros.h" + +#include <algorithm> +#include <numeric> + +template <int Size> class IntArray +{ +public: + explicit IntArray(const int *data) { std::copy(data, data + Size, m_array); } + explicit IntArray(int v) { std::fill(m_array, m_array + Size, v); } + + int sum() const { return std::accumulate(m_array, m_array + Size, int(0)); } + +private: + int m_array[Size]; +}; + +using IntArray2 = IntArray<2>; +using IntArray3 = IntArray<3>; + +#endif // NONTYPETEMPLATE_H diff --git a/sources/shiboken6/tests/libsample/null.h b/sources/shiboken6/tests/libsample/null.h new file mode 100644 index 000000000..945a89fa2 --- /dev/null +++ b/sources/shiboken6/tests/libsample/null.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 NULL_H +#define NULL_H + +class Null +{ +public: + Null(bool value) : m_isNull(value) {} + Null() = default; + + void setIsNull(bool flag) { m_isNull = flag; } + +private: + bool m_isNull = false; +}; + +#endif // NULL_H diff --git a/sources/shiboken6/tests/libsample/objectmodel.cpp b/sources/shiboken6/tests/libsample/objectmodel.cpp new file mode 100644 index 000000000..56ed86577 --- /dev/null +++ b/sources/shiboken6/tests/libsample/objectmodel.cpp @@ -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 + +#include "objectmodel.h" + +void ObjectModel::setData(ObjectType *data) +{ + m_data = data; +} + +ObjectType *ObjectModel::data() const +{ + return m_data; +} + +ObjectModel::MethodCalled ObjectModel::receivesObjectTypeFamily(const ObjectModel &) +{ + return ObjectModel::ObjectModelCalled; +} + +ObjectModel::MethodCalled ObjectModel::receivesObjectTypeFamily(const ObjectType &) +{ + return ObjectModel::ObjectTypeCalled; +} diff --git a/sources/shiboken6/tests/libsample/objectmodel.h b/sources/shiboken6/tests/libsample/objectmodel.h new file mode 100644 index 000000000..6d2f97aee --- /dev/null +++ b/sources/shiboken6/tests/libsample/objectmodel.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 OBJECTMODEL_H +#define OBJECTMODEL_H + +#include "objecttype.h" +#include "libsamplemacros.h" + +class LIBSAMPLE_API ObjectModel : public ObjectType +{ +public: + explicit ObjectModel(ObjectType *parent = nullptr) + : ObjectType(parent) {} + + void setData(ObjectType *data); + virtual ObjectType *data() const; + + // The MethodCalled enum and related static methods were created to + // test bug #630 [http://bugs.openbossa.org/show_bug.cgi?id=630] + enum MethodCalled { ObjectTypeCalled, ObjectModelCalled }; + static MethodCalled receivesObjectTypeFamily(const ObjectType &object); + static MethodCalled receivesObjectTypeFamily(const ObjectModel &object); + +private: + // The model holds only one piece of data. + // (This is just a test after all.) + ObjectType *m_data = nullptr; +}; + +#endif // OBJECTMODEL_H diff --git a/sources/shiboken6/tests/libsample/objecttype.cpp b/sources/shiboken6/tests/libsample/objecttype.cpp new file mode 100644 index 000000000..fa3e7357c --- /dev/null +++ b/sources/shiboken6/tests/libsample/objecttype.cpp @@ -0,0 +1,264 @@ +// 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 "objecttype.h" +#include "objecttypelayout.h" + +#include <algorithm> +#include <iostream> +#include <string> +#include <assert.h> + +ObjectType::ObjectType(ObjectType *parent) +{ + setParent(parent); +} + +ObjectType::ObjectType(ObjectType &&) noexcept = default; +ObjectType &ObjectType::operator=(ObjectType &&) noexcept = default; + +ObjectType::~ObjectType() +{ + for (auto *o : m_children) + delete o; +} + +ObjectType *ObjectType::createWithChild() +{ + ObjectType *parent = create(); + ObjectType *child = create(); + child->setObjectName("child"); + child->setParent(parent); + return parent; +} + +void ObjectType::removeChild(ObjectType *child) +{ + if (!child) + return; + + auto child_iter = std::find(m_children.begin(), m_children.end(), child); + if (child_iter != m_children.end()) { + m_children.erase(child_iter); + child->m_parent = nullptr; + } +} + +ObjectType *ObjectType::takeChild(ObjectType *child) +{ + if (!child) + return nullptr; + + auto child_iter = std::find(m_children.begin(), m_children.end(), child); + if (child_iter != m_children.end()) { + m_children.erase(child_iter); + child->m_parent = nullptr; + return child; + } + return nullptr; +} + +ObjectType *ObjectType::takeChild(const Str &name) +{ + return takeChild(findChild(name)); + +} + +ObjectTypeList::iterator ObjectType::findChildByName(const Str &name) +{ + return std::find_if(m_children.begin(), m_children.end(), + [&name](const ObjectType *o) { + return o->objectName() == name; + }); +} + +ObjectType *ObjectType::findChild(const Str &name) +{ + auto it = findChildByName(name); + return it != m_children.end() ? *it : nullptr; +} + +void ObjectType::killChild(const Str &name) +{ + auto it = findChildByName(name); + if (it != m_children.end()) { + ObjectType *child = *it; + removeChild(child); + delete child; + } +} + +void ObjectType::setParent(ObjectType *parent) +{ + if (m_parent == parent) + return; + + if (m_parent) + m_parent->removeChild(this); + + m_parent = parent; + if (m_parent) + m_parent->m_children.push_back(this); +} + +void ObjectType::setObjectName(const Str &name) +{ + m_objectName = name; +} + +Str ObjectType::objectName() const +{ + return m_objectName; +} + +bool ObjectType::causeEvent(Event::EventType eventType) +{ + Event e(eventType); + return event(&e); +} + +bool ObjectType::event(Event *) +{ + return true; +} + +int ObjectType::processEvent(ObjectTypeList objects, Event *event) +{ + return std::count_if(objects.begin(), objects.end(), + [event] (ObjectType *o) { + return o->event(event); + }); +} + +void ObjectType::callInvalidateEvent(Event *event) +{ + invalidateEvent(event); +} + +void ObjectType::invalidateEvent(Event *) +{ +} + +void ObjectType::setLayout(ObjectTypeLayout *l) +{ + if (!l) { + std::cerr << "[WARNING] ObjectType::setLayout: Cannot set layout to 0.\n"; + return; + } + + if (layout()) { + if (layout() != l) { + std::cerr << "[WARNING] ObjectType::setLayout: Attempting to set ObjectTypeLayout '" + << l->objectName().cstring() + << "' on ObjectType '" << objectName().cstring() + << "', which already has a layout.\n"; + } + return; + } + + ObjectType *oldParent = l->parent(); + if (oldParent && oldParent != this) { + if (oldParent->isLayoutType()) { + std::cerr << "[WARNING] ObjectType::setLayout: Attempting to set ObjectTypeLayout '" + << l->objectName().cstring() + << "' on ObjectType '" << objectName().cstring() + << "', when the ObjectTypeLayout already has a parent layout.\n"; + return; + } + // Steal the layout from an ObjectType parent. + oldParent->takeLayout(); + } + + m_layout = l; + if (oldParent != this) { + l->setParent(this); + l->reparentChildren(this); + } +} + +ObjectTypeLayout *ObjectType::takeLayout() +{ + ObjectTypeLayout *l = layout(); + if (!l) + return nullptr; + m_layout = nullptr; + l->setParent(nullptr); + return l; +} + +unsigned int objectTypeHash(const ObjectType *objectType) +{ + return reinterpret_cast<std::size_t>(objectType); +} + +unsigned char ObjectType::callWithEnum(const Str &, Event::EventType, unsigned char value) +{ + return value * value; +} + +unsigned char ObjectType::callWithEnum(const Str &, unsigned char value) +{ + return value; +} + +void ObjectType::setObjectSplittedName(const char *, const Str &prefix, const Str &suffix) +{ + std::string result(prefix.cstring()); + result += suffix.cstring(); + m_objectName = result.c_str(); +} + +void ObjectType::setObjectNameWithSize(const char *, int size, const Str &name) +{ + std::string result(name.cstring(), size); + m_objectName = result.c_str(); +} + +void ObjectType::setObjectNameWithSize(const Str &name, int size) +{ + setObjectNameWithSize("", size, name); +} + +void ObjectType::setObject(ObjectType *) +{ + m_call_id = 0; +} + +void ObjectType::setObject(const Null&) +{ + m_call_id = 1; +} + +int ObjectType::callId() const +{ + return m_call_id; +} + +void ObjectType::callVirtualCreateChild() +{ + auto *fake_parent = new ObjectType(); + ObjectType *fake_child = createChild(fake_parent); + assert(fake_child->isPython()); + (void)fake_child; + delete fake_parent; +} + +ObjectType *ObjectType::createChild(ObjectType *parent) +{ + return new ObjectType(parent); +} + +std::size_t ObjectType::createObjectType() +{ + void *addr = new ObjectType(); + return (std::size_t) addr; +} + +OtherBase::~OtherBase() = default; + +ObjectTypeDerived::~ObjectTypeDerived() = default; + +bool ObjectTypeDerived::event(Event *) +{ + return true; +} diff --git a/sources/shiboken6/tests/libsample/objecttype.h b/sources/shiboken6/tests/libsample/objecttype.h new file mode 100644 index 000000000..498556459 --- /dev/null +++ b/sources/shiboken6/tests/libsample/objecttype.h @@ -0,0 +1,166 @@ +// 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 OBJECTTYPE_H +#define OBJECTTYPE_H + +#include "str.h" +#include "null.h" + +#include "libsamplemacros.h" + +#include <list> + +struct Event +{ + enum EventType { + NO_EVENT, + BASIC_EVENT, + SOME_EVENT, + ANY_EVENT + }; + + enum class EventTypeClass { + Value1, + Value2 + }; + + explicit Event(EventType eventType) : m_eventType(eventType) {} + EventType eventType() const { return m_eventType; } + + void setEventType(EventType et) { m_eventType = et; } + void setEventTypeByConstRef(const EventType &et) { m_eventType = et; } + void setEventTypeByConstPtr(const EventType *etPtr) { m_eventType = *etPtr; } + +private: + EventType m_eventType; +}; + +class ObjectTypeLayout; +class ObjectType; +using ObjectTypeList = std::list<ObjectType*>; + +class LIBSAMPLE_API ObjectType +{ +public: + // ### Fixme: Use uintptr_t in C++ 11 + using Identifier = size_t; + + explicit ObjectType(ObjectType *parent = nullptr); + virtual ~ObjectType(); + ObjectType(const ObjectType &) = delete; + ObjectType &operator=(const ObjectType &) = delete; + ObjectType(ObjectType &&) noexcept; + ObjectType &operator=(ObjectType &&) noexcept; + + // factory method + inline static ObjectType *create() { return new ObjectType(); } + static ObjectType *createWithChild(); + + void setParent(ObjectType *parent); + inline ObjectType *parent() const { return m_parent; } + inline const ObjectTypeList &children() const { return m_children; } + void killChild(const Str &name); + void removeChild(ObjectType *child); + ObjectType *takeChild(ObjectType *child); + virtual ObjectType *takeChild(const Str &name); + ObjectType *findChild(const Str &name); + + Str objectName() const; + void setObjectName(const Str &name); + + inline Identifier identifier() const { return reinterpret_cast<Identifier>(this); } + + bool causeEvent(Event::EventType eventType); + + // Returns true if the event is processed. + virtual bool event(Event *event); + static int processEvent(ObjectTypeList objects, Event *event); + + void callInvalidateEvent(Event *event); + virtual void invalidateEvent(Event *event); + + // This nonsense method emulate QWidget.setLayout method + // All layout objects will became children of this object. + void setLayout(ObjectTypeLayout *layout); + inline ObjectTypeLayout *layout() const { return m_layout; } + + // This method should be reimplemented by ObjectTypeLayout. + virtual bool isLayoutType() { return false; } + + unsigned char callWithEnum(const Str &prefix, Event::EventType type, + unsigned char value=80); + unsigned char callWithEnum(const Str &prefix, unsigned char value=0); + + //Functions used in test with named arguments + void setObjectSplittedName(const char *, const Str &prefix = Str("<unk"), + const Str &suffix = Str("nown>")); + void setObjectNameWithSize(const char *, int size=9, + const Str &name = Str("<unknown>")); + void setObjectNameWithSize(const Str &name = Str("<unknown>"), int size = 9); + + //Function used to confuse the generator when two values accept Null as arg + void setObject(ObjectType *); + void setObject(const Null &); + int callId() const; + + //Function used to create a parent from C++ + virtual bool isPython() { return false; } + void callVirtualCreateChild(); + virtual ObjectType *createChild(ObjectType *parent); + static std::size_t createObjectType(); + + //return a parent from C++ + ObjectType *getCppParent() { + if (!m_parent) { + ObjectType *parent = new ObjectType(); + setParent(parent); + } + return m_parent; + } + + void destroyCppParent() { + delete m_parent; + } + + //Deprecated test + bool deprecatedFunction() { return true; } + + // nextInFocusChain simply returns the parent to test object cycles; the parent + // may be returned by the QWidget's implementation but isn't always returned + ObjectType *nextInFocusChain() { return m_parent; } + +private: + ObjectTypeLayout *takeLayout(); + ObjectTypeList::iterator findChildByName(const Str &name); + + Str m_objectName; + ObjectType *m_parent = nullptr; + ObjectTypeList m_children; + + ObjectTypeLayout *m_layout = nullptr; + //used on overload null test + int m_call_id = -1; +}; + +LIBSAMPLE_API unsigned int objectTypeHash(const ObjectType *objectType); + +class LIBSAMPLE_API OtherBase { +public: + LIBMINIMAL_DISABLE_COPY_MOVE(OtherBase) + + OtherBase() noexcept = default; + virtual ~OtherBase(); +}; + +class LIBSAMPLE_API ObjectTypeDerived: public ObjectType, public OtherBase { +public: + LIBMINIMAL_DISABLE_COPY_MOVE(ObjectTypeDerived) + + ObjectTypeDerived() noexcept = default; + + bool event(Event *event) override; + ~ObjectTypeDerived() override; +}; + +#endif // OBJECTTYPE_H diff --git a/sources/shiboken6/tests/libsample/objecttypebyvalue.h b/sources/shiboken6/tests/libsample/objecttypebyvalue.h new file mode 100644 index 000000000..7b12ff945 --- /dev/null +++ b/sources/shiboken6/tests/libsample/objecttypebyvalue.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 OBJECTTYPEBYVALUE_H +#define OBJECTTYPEBYVALUE_H + +#include "protected.h" + +#include <list> + +class ObjectTypeByValue +{ +public: + ObjectTypeByValue returnSomeKindOfMe() { return {}; } + void acceptKindOfMeAsValue(ObjectTypeByValue kindOfMe); + + void acceptListOfObjectTypeByValue(std::list<ObjectTypeByValue> listOfMe); + + // prop used to check for segfaults + ProtectedProperty prop; +}; + +inline void ObjectTypeByValue::acceptKindOfMeAsValue(ObjectTypeByValue) +{ +} + +inline void ObjectTypeByValue::acceptListOfObjectTypeByValue(std::list<ObjectTypeByValue>) +{ +} + +#endif // OBJECTTYPEBYVALUE_H diff --git a/sources/shiboken6/tests/libsample/objecttypeholder.cpp b/sources/shiboken6/tests/libsample/objecttypeholder.cpp new file mode 100644 index 000000000..c0950d09c --- /dev/null +++ b/sources/shiboken6/tests/libsample/objecttypeholder.cpp @@ -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 + +#include "objecttypeholder.h" + +ObjectTypeHolder::ObjectTypeHolder(const char *objectName) +{ + auto *object = new ObjectType(); + object->setObjectName(objectName); + m_objectType = object; +} + +ObjectTypeHolder::ObjectTypeHolder(const ObjectType *object) noexcept : + m_objectType(object) +{ +} + +ObjectTypeHolder::~ObjectTypeHolder() +{ + delete m_objectType; +} + +Str ObjectTypeHolder::passObjectTypeAsReference(const ObjectType &objectType) +{ + return objectType.objectName(); +} + +Str ObjectTypeHolder::callPassObjectTypeAsReference() +{ + return passObjectTypeAsReference(*m_objectType); +} diff --git a/sources/shiboken6/tests/libsample/objecttypeholder.h b/sources/shiboken6/tests/libsample/objecttypeholder.h new file mode 100644 index 000000000..190664608 --- /dev/null +++ b/sources/shiboken6/tests/libsample/objecttypeholder.h @@ -0,0 +1,29 @@ +// 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 OBJECTTYPEHOLDER_H +#define OBJECTTYPEHOLDER_H + +#include "libsamplemacros.h" +#include "objecttype.h" +#include "str.h" + +class LIBSAMPLE_API ObjectTypeHolder +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(ObjectTypeHolder) + + explicit ObjectTypeHolder(const char *objectName); + explicit ObjectTypeHolder(const ObjectType *object) noexcept; + virtual ~ObjectTypeHolder(); + + const ObjectType *getObjectType() const { return m_objectType; } + + virtual Str passObjectTypeAsReference(const ObjectType &objectType); + Str callPassObjectTypeAsReference(); + +private: + const ObjectType *m_objectType; +}; + +#endif // OBJECTTYPEHOLDER_H diff --git a/sources/shiboken6/tests/libsample/objecttypelayout.cpp b/sources/shiboken6/tests/libsample/objecttypelayout.cpp new file mode 100644 index 000000000..3fa02917c --- /dev/null +++ b/sources/shiboken6/tests/libsample/objecttypelayout.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 "objecttypelayout.h" + +#include <iostream> + +void ObjectTypeLayout::addObject(ObjectType *obj) +{ + if (obj->isLayoutType()) { + auto *l = reinterpret_cast<ObjectTypeLayout*>(obj); + if (l->parent()) { + std::cerr << "[WARNING] ObjectTypeLayout::addObject: layout '" + << l->objectName().cstring() << "' already has a parent.\n"; + return; + } + + l->setParent(this); + + if (parent() && !parent()->isLayoutType()) + l->reparentChildren(parent()); + } + + m_objects.push_back(obj); +} + +std::list<ObjectType*> ObjectTypeLayout::objects() const +{ + return m_objects; +} + +void ObjectTypeLayout::reparentChildren(ObjectType *parent) +{ + for (auto *o : m_objects) { + if (o->isLayoutType()) + reinterpret_cast<ObjectTypeLayout *>(o)->reparentChildren(parent); + else + o->setParent(parent); + } +} diff --git a/sources/shiboken6/tests/libsample/objecttypelayout.h b/sources/shiboken6/tests/libsample/objecttypelayout.h new file mode 100644 index 000000000..0aa9fad6e --- /dev/null +++ b/sources/shiboken6/tests/libsample/objecttypelayout.h @@ -0,0 +1,32 @@ +// 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 OBJECTTYPELAYOUT_H +#define OBJECTTYPELAYOUT_H + +#include "libsamplemacros.h" +#include "objecttype.h" + +#include <list> + +class ObjectType; + +class LIBSAMPLE_API ObjectTypeLayout : public ObjectType +{ +public: + void addObject(ObjectType *obj); + std::list<ObjectType*> objects() const; + + bool isLayoutType() override { return true; } + inline static ObjectTypeLayout *create() { return new ObjectTypeLayout(); } + + ObjectType *takeChild(const Str &name) override { return ObjectType::takeChild(name); } + +private: + std::list<ObjectType*> m_objects; + + void reparentChildren(ObjectType *parent); + friend LIBSAMPLE_API void ObjectType::setLayout(ObjectTypeLayout *l); +}; + +#endif // OBJECTTYPELAYOUT_H diff --git a/sources/shiboken6/tests/libsample/objecttypeoperators.cpp b/sources/shiboken6/tests/libsample/objecttypeoperators.cpp new file mode 100644 index 000000000..c78387a3e --- /dev/null +++ b/sources/shiboken6/tests/libsample/objecttypeoperators.cpp @@ -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 + +#include "objecttypeoperators.h" + +ObjectTypeOperators::ObjectTypeOperators(const std::string key) : m_key(key) +{ +} + +bool ObjectTypeOperators::operator==(const ObjectTypeOperators &other) const +{ + return m_key == other.m_key; +} + +const ObjectTypeOperators &ObjectTypeOperators::operator<(const ObjectTypeOperators &other) const +{ + return m_key < other.m_key ? *this : other; +} + +bool operator==(const ObjectTypeOperators *obj, const std::string &str) +{ + return obj->key() == str; +} + +bool operator==(const std::string &str, const ObjectTypeOperators *obj) +{ + return str == obj->key(); +} + +std::string operator+(const ObjectTypeOperators *obj, const std::string &str) +{ + return obj->key() + str; +} + +std::string operator+(const std::string &str, const ObjectTypeOperators *obj) +{ + return str + obj->key(); +} diff --git a/sources/shiboken6/tests/libsample/objecttypeoperators.h b/sources/shiboken6/tests/libsample/objecttypeoperators.h new file mode 100644 index 000000000..6144952ca --- /dev/null +++ b/sources/shiboken6/tests/libsample/objecttypeoperators.h @@ -0,0 +1,36 @@ +// 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 OBJECTTYPEOPERATORS_H +#define OBJECTTYPEOPERATORS_H + +#include "libsamplemacros.h" + +#include <string> + +class LIBSAMPLE_API ObjectTypeOperators +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(ObjectTypeOperators) + + explicit ObjectTypeOperators(const std::string key); + virtual ~ObjectTypeOperators() = default; + + bool operator==(const ObjectTypeOperators &other) const; + const ObjectTypeOperators &operator<(const ObjectTypeOperators &other) const; + + // chaos! + virtual void operator>(const ObjectTypeOperators &) { m_key.append("operator>"); } + + std::string key() const { return m_key; } + +private: + std::string m_key; +}; + +LIBSAMPLE_API bool operator==(const ObjectTypeOperators *obj, const std::string &str); +LIBSAMPLE_API bool operator==(const std::string &str, const ObjectTypeOperators *obj); +LIBSAMPLE_API std::string operator+(const ObjectTypeOperators *obj, const std::string &str); +LIBSAMPLE_API std::string operator+(const std::string &str, const ObjectTypeOperators *obj); + +#endif // OBJECTTYPEOPERATORS_H diff --git a/sources/shiboken6/tests/libsample/objectview.cpp b/sources/shiboken6/tests/libsample/objectview.cpp new file mode 100644 index 000000000..1b727f88c --- /dev/null +++ b/sources/shiboken6/tests/libsample/objectview.cpp @@ -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 + +#include "objectview.h" +#include "objectmodel.h" +#include "str.h" + +Str ObjectView::displayModelData() +{ + if (!m_model) + return {"(NULL)"}; + return Str("Name: %VAR").arg(m_model->objectName()); +} + +void ObjectView::modifyModelData(Str &data) +{ + if (m_model) + m_model->setObjectName(data); +} + +ObjectType *ObjectView::getRawModelData() +{ + return m_model->data(); +} diff --git a/sources/shiboken6/tests/libsample/objectview.h b/sources/shiboken6/tests/libsample/objectview.h new file mode 100644 index 000000000..2567deee5 --- /dev/null +++ b/sources/shiboken6/tests/libsample/objectview.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 OBJECTVIEW_H +#define OBJECTVIEW_H + +#include "objecttype.h" +#include "libsamplemacros.h" + +class Str; +class ObjectModel; + +class LIBSAMPLE_API ObjectView : public ObjectType +{ +public: + explicit ObjectView(ObjectModel *model = nullptr, ObjectType *parent = nullptr) + : ObjectType(parent), m_model(model) {} + + inline void setModel(ObjectModel *model) { m_model = model; } + inline ObjectModel *model() const { return m_model; } + + Str displayModelData(); + void modifyModelData(Str &data); + + ObjectType *getRawModelData(); + +private: + ObjectModel *m_model; +}; + +#endif // OBJECTVIEW_H diff --git a/sources/shiboken6/tests/libsample/oddbool.cpp b/sources/shiboken6/tests/libsample/oddbool.cpp new file mode 100644 index 000000000..bc1ee833f --- /dev/null +++ b/sources/shiboken6/tests/libsample/oddbool.cpp @@ -0,0 +1,27 @@ +// 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 "oddbool.h" + +ComparisonTester::ComparisonTester(int v) : m_value(v) +{ +} + +ComparisonTester &ComparisonTester::operator=(int v) +{ + m_value = v; + return *this; +} + +int ComparisonTester::compare(const ComparisonTester &rhs) const +{ + if (m_value < rhs.m_value) + return -1; + if (m_value > rhs.m_value) + return 1; + return 0; +} + +SpaceshipComparisonTester::SpaceshipComparisonTester(int v) : m_value(v) +{ +} diff --git a/sources/shiboken6/tests/libsample/oddbool.h b/sources/shiboken6/tests/libsample/oddbool.h new file mode 100644 index 000000000..dd2d32604 --- /dev/null +++ b/sources/shiboken6/tests/libsample/oddbool.h @@ -0,0 +1,106 @@ +// 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 ODDBOOL_H +#define ODDBOOL_H + +#include "libsamplemacros.h" + +#include <type_traits> + +#if __cplusplus >= 202002 || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002) +# include <compare> +#endif + +class OddBool +{ + +public: + inline explicit OddBool(bool b) noexcept : m_value(b) {} + bool value() const { return m_value; } + + inline OddBool operator!() const { return OddBool(!m_value); } + +private: + bool m_value; +}; + +inline bool operator==(OddBool b1, bool b2) { return (!b1).value() == !b2; } +inline bool operator==(bool b1, OddBool b2) { return (!b1) == (!b2).value(); } +inline bool operator==(OddBool b1, OddBool b2) { return (!b1).value() == (!b2).value(); } +inline bool operator!=(OddBool b1, bool b2) { return (!b1).value() != !b2; } +inline bool operator!=(bool b1, OddBool b2) { return (!b1) != (!b2).value(); } +inline bool operator!=(OddBool b1, OddBool b2) { return (!b1).value() != (!b2).value(); } + +class OddBoolUser +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(OddBoolUser) + + OddBoolUser() noexcept : m_oddbool(OddBool(false)) {} + OddBoolUser(const OddBool &oddBool) : m_oddbool(oddBool) {} + virtual ~OddBoolUser() = default; + + inline OddBool oddBool() { return m_oddbool; } + inline void setOddBool(OddBool oddBool) { m_oddbool = oddBool; } + + virtual OddBool invertedOddBool() + { + return !m_oddbool; + } + + inline OddBool callInvertedOddBool() + { + return invertedOddBool(); + } + + static inline OddBool getOddBool(const OddBoolUser &oddBoolUser) + { + return oddBoolUser.m_oddbool; + } + +private: + OddBool m_oddbool; +}; + +class LIBSAMPLE_API ComparisonTester +{ +public: + explicit ComparisonTester(int v); + ComparisonTester &operator=(int v); + + int compare(const ComparisonTester &rhs) const; + +private: + int m_value; +}; + +// Hide the comparison operators from the clang parser (see typesystem_sample.xml:184, +// oddbool_test.py) + +inline std::enable_if<std::is_assignable<ComparisonTester, int>::value, bool>::type + operator==(const ComparisonTester &c1, const ComparisonTester &c2) +{ return c1.compare(c2) == 0; } + +inline std::enable_if<std::is_assignable<ComparisonTester, int>::value, bool>::type + operator!=(const ComparisonTester &c1, const ComparisonTester &c2) +{ return c1.compare(c2) != 0; } + +class LIBSAMPLE_API SpaceshipComparisonTester +{ +public: + explicit SpaceshipComparisonTester(int v); + +#if __cplusplus >= 202002 || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002) + auto operator<=>(const SpaceshipComparisonTester &rhs) const = default; + + enum Enabled { HasSpaceshipOperator = 1 }; +#else + enum Enabled { HasSpaceshipOperator = 0 }; +#endif // C++ 20 + +private: + int m_value; +}; + +#endif // ODDBOOL_H diff --git a/sources/shiboken6/tests/libsample/onlycopy.cpp b/sources/shiboken6/tests/libsample/onlycopy.cpp new file mode 100644 index 000000000..981ea88a4 --- /dev/null +++ b/sources/shiboken6/tests/libsample/onlycopy.cpp @@ -0,0 +1,36 @@ +// 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 "onlycopy.h" + +class OnlyCopyPrivate +{ +public: + explicit OnlyCopyPrivate(int v = 0) : value(v) {} + + int value; +}; + +OnlyCopy::OnlyCopy(int value) : d(std::make_shared<OnlyCopyPrivate>(value)) +{ +} + +OnlyCopy::~OnlyCopy() = default; + +int OnlyCopy::value() const +{ + return d->value; +} + +OnlyCopy FriendOfOnlyCopy::createOnlyCopy(int value) +{ + return OnlyCopy(value); +} + +std::list<OnlyCopy> FriendOfOnlyCopy::createListOfOnlyCopy(int quantity) +{ + std::list<OnlyCopy> list; + for (int i = 0; i < quantity; ++i) + list.push_back(createOnlyCopy(i)); + return list; +} diff --git a/sources/shiboken6/tests/libsample/onlycopy.h b/sources/shiboken6/tests/libsample/onlycopy.h new file mode 100644 index 000000000..7dc3e0069 --- /dev/null +++ b/sources/shiboken6/tests/libsample/onlycopy.h @@ -0,0 +1,42 @@ +// 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 ONLYCOPYCLASS_H +#define ONLYCOPYCLASS_H + +#include "libsamplemacros.h" + +#include <list> +#include <memory> + +// These classes simulate a situation found in QWebEngineHistoryItem. + +class OnlyCopyPrivate; + +class LIBSAMPLE_API OnlyCopy +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(OnlyCopy) + + ~OnlyCopy(); + + int value() const; + static int getValue(OnlyCopy onlyCopy) { return onlyCopy.value(); } + static int getValueFromReference(const OnlyCopy &onlyCopy) { return onlyCopy.value(); } + +private: + friend class FriendOfOnlyCopy; + + explicit OnlyCopy(int value); + + std::shared_ptr<OnlyCopyPrivate> d; +}; + +class LIBSAMPLE_API FriendOfOnlyCopy +{ +public: + static OnlyCopy createOnlyCopy(int value); + static std::list<OnlyCopy> createListOfOnlyCopy(int quantity); +}; + +#endif // ONLYCOPYCLASS_H diff --git a/sources/shiboken6/tests/libsample/overload.cpp b/sources/shiboken6/tests/libsample/overload.cpp new file mode 100644 index 000000000..34da28e03 --- /dev/null +++ b/sources/shiboken6/tests/libsample/overload.cpp @@ -0,0 +1,203 @@ +// 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 "overload.h" + +Overload::FunctionEnum Overload::overloaded() +{ + return Function0; +} + +Overload::FunctionEnum Overload::overloaded(Size *) +{ + return Function1; +} + +Overload::FunctionEnum Overload::overloaded(Point *, ParamEnum) +{ + return Function2; +} + +Overload::FunctionEnum Overload::overloaded(const Point &) +{ + return Function3; +} + +void Overload::differentReturnTypes(ParamEnum) +{ + +} + +int Overload::differentReturnTypes(ParamEnum, int val) +{ + return val; +} + +int Overload::intOverloads(const Point &, double) +{ + return 1; +} + +int Overload::intOverloads(int, int) +{ + return 2; +} + +int Overload::intOverloads(int, int, double) +{ + return 3; +} + +Overload::FunctionEnum Overload::intDoubleOverloads(double, double) const +{ + return Function1; +} + +Overload::FunctionEnum Overload::intDoubleOverloads(int, int) const +{ + return Function0; +} + +void Overload::singleOverload(Point *) +{ +} + +Overload::FunctionEnum Overload::wrapperIntIntOverloads(const Polygon &, int, int) +{ + return Function1; +} + +Overload::FunctionEnum Overload::wrapperIntIntOverloads(const Point &, int, int) +{ + return Function0; +} + +Overload::FunctionEnum Overload::strBufferOverloads(const Str &, const char *, bool) +{ + return Function0; +} + +Overload::FunctionEnum Overload::strBufferOverloads(unsigned char *, int) +{ + return Function1; +} + +Overload::FunctionEnum Overload::drawText(const PointF &, const Str &) +{ + return Function1; +} + +Overload::FunctionEnum Overload::drawText(const Point &, const Str &) +{ + return Function0; +} + +Overload::FunctionEnum Overload::drawText(const RectF &, const Str &, const Echo &) +{ + return Function4; +} + +Overload::FunctionEnum Overload::drawText(const RectF &, int, const Str &) +{ + return Function3; +} + +Overload::FunctionEnum Overload::drawText(const Rect &, int, const Str &) +{ + return Function2; +} + +Overload::FunctionEnum Overload::drawText(int, int, const Str &) +{ + return Function5; +} + +Overload::FunctionEnum Overload::drawText(int, int, int, int, int, const Str &) +{ + return Function6; +} + +Overload::FunctionEnum Overload::drawText2(const PointF &, const Str &) +{ + return Function1; +} + +Overload::FunctionEnum Overload::drawText2(const Point &, const Str &) +{ + return Function0; +} + +Overload::FunctionEnum Overload::drawText2(int, int, const Str &) +{ + return Function5; +} + +Overload::FunctionEnum Overload::drawText2(const RectF &, const Str &, const Echo &) +{ + return Function4; +} + +Overload::FunctionEnum Overload::drawText2(const RectF &, int, const Str &) +{ + return Function3; +} + +Overload::FunctionEnum Overload::drawText2(const Rect &, int, const Str &) +{ + return Function2; +} + +Overload::FunctionEnum Overload::drawText2(int, int, int, int, int, const Str &) +{ + return Function6; +} + +Overload::FunctionEnum Overload::drawText3(const Str &, const Str &, const Str &) +{ + return Function0; +} + +Overload::FunctionEnum Overload::drawText3(int, int, int, int, int) +{ + return Function1; +} + +Overload::FunctionEnum Overload::drawText4(int, int, int) +{ + return Function0; +} + +Overload::FunctionEnum Overload::drawText4(int, int, int, int, int) +{ + return Function1; +} + +Overload::FunctionEnum Overload::acceptSequence() +{ + return Function0; +} + +Overload::FunctionEnum Overload::acceptSequence(const Str &, ParamEnum) +{ + return Function2; +} + +Overload::FunctionEnum Overload::acceptSequence(int, int) +{ + return Function1; +} + +Overload::FunctionEnum Overload::acceptSequence(void *) +{ + return Function5; +} + +Overload::FunctionEnum Overload::acceptSequence(const char *const[]) +{ + return Function4; +} + +Overload::FunctionEnum Overload::acceptSequence(const Size &) +{ + return Function3; +} diff --git a/sources/shiboken6/tests/libsample/overload.h b/sources/shiboken6/tests/libsample/overload.h new file mode 100644 index 000000000..b640bf7c7 --- /dev/null +++ b/sources/shiboken6/tests/libsample/overload.h @@ -0,0 +1,121 @@ +// 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 OVERLOAD_H +#define OVERLOAD_H + +#include "echo.h" +#include "str.h" +#include "size.h" +#include "point.h" +#include "pointf.h" +#include "polygon.h" +#include "rect.h" + +#include "libsamplemacros.h" + +class LIBSAMPLE_API Overload +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(Overload) + + enum FunctionEnum { + Function0, + Function1, + Function2, + Function3, + Function4, + Function5, + Function6 + }; + + enum ParamEnum { + Param0, + Param1 + }; + + Overload() noexcept = default; + virtual ~Overload() = default; + + FunctionEnum overloaded(); + FunctionEnum overloaded(Size *size); + FunctionEnum overloaded(Point *point, ParamEnum param); + FunctionEnum overloaded(const Point &point); + + void differentReturnTypes(ParamEnum param = Param0); + int differentReturnTypes(ParamEnum param, int val); + + int intOverloads(const Point &p, double d); + int intOverloads(int i, int i2); + int intOverloads(int i, int removedArg, double d); + + FunctionEnum intDoubleOverloads(int a0, int a1) const; + FunctionEnum intDoubleOverloads(double a0, double a1) const; + + void singleOverload(Point *x); + Point *singleOverload() { return new Point(); } + + // Similar to QImage::trueMatrix(QMatrix,int,int) and QImage::trueMatrix(QTransform,int,int) + FunctionEnum wrapperIntIntOverloads(const Point &arg0, int arg1, int arg2); + FunctionEnum wrapperIntIntOverloads(const Polygon &arg0, int arg1, int arg2); + + // Similar to QImage constructor + FunctionEnum strBufferOverloads(const Str &arg0, const char *arg1 = nullptr, + bool arg2 = true); + FunctionEnum strBufferOverloads(unsigned char *arg0, int arg1); + FunctionEnum strBufferOverloads() { return Function2; } + + // Similar to QPainter::drawText(...) + FunctionEnum drawText(const Point &a0, const Str &a1); + FunctionEnum drawText(const PointF &a0, const Str &a1); + FunctionEnum drawText(const Rect &a0, int a1, const Str &a2); + FunctionEnum drawText(const RectF &a0, int a1, const Str &a2); + FunctionEnum drawText(const RectF &a0, const Str &a1, const Echo &a2 = Echo()); + FunctionEnum drawText(int a0, int a1, const Str &a2); + FunctionEnum drawText(int a0, int a1, int a2, int a3, int a4, const Str &a5); + + // A variant of the one similar to QPainter::drawText(...) + FunctionEnum drawText2(const Point &a0, const Str &a1); + FunctionEnum drawText2(const PointF &a0, const Str &a1); + FunctionEnum drawText2(const Rect &a0, int a1, const Str &a2); + FunctionEnum drawText2(const RectF &a0, int a1, const Str &a2); + FunctionEnum drawText2(const RectF &a0, const Str &a1, const Echo &a2 = Echo()); + FunctionEnum drawText2(int a0, int a1, const Str &a2); + FunctionEnum drawText2(int a0, int a1, int a2, int a3 = 0, int a4 = 0, + const Str &a5 = Str()); + + // A simpler variant of the one similar to QPainter::drawText(...) + FunctionEnum drawText3(const Str &a0, const Str &a1, const Str &a2); + FunctionEnum drawText3(int a0, int a1, int a2, int a3, int a4); + + // Another simpler variant of the one similar to QPainter::drawText(...) + FunctionEnum drawText4(int a0, int a1, int a2); + FunctionEnum drawText4(int a0, int a1, int a2, int a3, int a4); + + FunctionEnum acceptSequence(); + FunctionEnum acceptSequence(int a0, int a1); + FunctionEnum acceptSequence(const Str &a0, ParamEnum a1 = Param0); + FunctionEnum acceptSequence(const Size &a0); + // The type must be changed to PySequence. + FunctionEnum acceptSequence(const char *const a0[]); + FunctionEnum acceptSequence(void *a0); +}; + +class LIBSAMPLE_API Overload2 : public Overload +{ +public: + // test bug#616, public and private method differ only by const + void doNothingInPublic() const {} + void doNothingInPublic(int) {} + virtual void doNothingInPublic3() const {} + void doNothingInPublic3(int) const {} +protected: + void doNothingInPublic2() const {} + void doNothingInPublic2(int) {} +private: + void doNothingInPublic() {} + void doNothingInPublic2() {} + void doNothingInPublic3() {} +}; + +#endif // OVERLOAD_H diff --git a/sources/shiboken6/tests/libsample/overloadsort.cpp b/sources/shiboken6/tests/libsample/overloadsort.cpp new file mode 100644 index 000000000..a9b4b0972 --- /dev/null +++ b/sources/shiboken6/tests/libsample/overloadsort.cpp @@ -0,0 +1,49 @@ +// 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 "overloadsort.h" + +const char *SortedOverload::overload(int) +{ + return "int"; +} + +const char *SortedOverload::overload(double) +{ + return "double"; +} + +const char *SortedOverload::overload(ImplicitBase) +{ + return "ImplicitBase"; +} + +const char *SortedOverload::overload(ImplicitTarget) +{ + return "ImplicitTarget"; +} + +const char *SortedOverload::overload(const std::list<ImplicitBase> &) +{ + return "list(ImplicitBase)"; +} + +int SortedOverload::implicit_overload(const ImplicitBase &) +{ + return 1; +} + +const char *SortedOverload::overloadDeep(int, ImplicitBase &) +{ + return "ImplicitBase"; +} + +int CustomOverloadSequence::overload(short v) const +{ + return v + int(sizeof(v)); +} + +int CustomOverloadSequence::overload(int v) const +{ + return v + 4; +} diff --git a/sources/shiboken6/tests/libsample/overloadsort.h b/sources/shiboken6/tests/libsample/overloadsort.h new file mode 100644 index 000000000..ee269cc21 --- /dev/null +++ b/sources/shiboken6/tests/libsample/overloadsort.h @@ -0,0 +1,54 @@ +// 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 OVERLOADSORT_H +#define OVERLOADSORT_H + +#include "libsamplemacros.h" + +#include <list> + +class ImplicitTarget +{ +public: + ImplicitTarget() = default; +}; + +class ImplicitBase +{ +public: + ImplicitBase() = default; + ImplicitBase(const ImplicitTarget &b); +}; + +inline ImplicitBase::ImplicitBase(const ImplicitTarget &) +{ +} + +class LIBSAMPLE_API SortedOverload +{ +public: + + const char *overload(int x); + const char *overload(double x); + const char *overload(ImplicitBase x); + const char *overload(ImplicitTarget x); + const char *overload(const std::list<ImplicitBase> &x); + + int implicit_overload(const ImplicitBase &x); + + const char *overloadDeep(int x, ImplicitBase &y); + + inline const char *pyObjOverload(int, int) { return "int,int"; } + inline const char *pyObjOverload(unsigned char *, int) + { return "PyObject,int"; } +}; + +class LIBSAMPLE_API CustomOverloadSequence +{ +public: + int overload(short v) const; + int overload(int v) const; +}; + +#endif // OVERLOADSORT_H diff --git a/sources/shiboken6/tests/libsample/pairuser.cpp b/sources/shiboken6/tests/libsample/pairuser.cpp new file mode 100644 index 000000000..5b7eb4d8c --- /dev/null +++ b/sources/shiboken6/tests/libsample/pairuser.cpp @@ -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 + +#include "pairuser.h" + +std::pair<int, int> PairUser::callCreatePair() +{ + return createPair(); +} + +std::pair<int, int> PairUser::createPair() +{ + return {10, 20}; +} + +std::pair<Complex, Complex> PairUser::createComplexPair(Complex cpx0, Complex cpx1) +{ + return {cpx0, cpx1}; +} + +double PairUser::sumPair(std::pair<int, double> pair) +{ + return ((double) pair.first) + pair.second; +} diff --git a/sources/shiboken6/tests/libsample/pairuser.h b/sources/shiboken6/tests/libsample/pairuser.h new file mode 100644 index 000000000..ee51d818e --- /dev/null +++ b/sources/shiboken6/tests/libsample/pairuser.h @@ -0,0 +1,32 @@ +// 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 PAIRUSER_H +#define PAIRUSER_H + +#include "libsamplemacros.h" +#include "complex.h" + +#include <utility> + +class LIBSAMPLE_API PairUser +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(PairUser) + + PairUser() noexcept = default; + virtual ~PairUser() = default; + + virtual std::pair<int, int> createPair(); + std::pair<int, int> callCreatePair(); + static std::pair<Complex, Complex> createComplexPair(Complex cpx0, Complex cpx1); + double sumPair(std::pair<int, double> pair); + + inline void setPair(std::pair<int, int> pair) { m_pair = pair; } + inline std::pair<int, int> getPair() { return m_pair; } + +private: + std::pair<int, int> m_pair; +}; + +#endif // PAIRUSER_H diff --git a/sources/shiboken6/tests/libsample/pen.cpp b/sources/shiboken6/tests/libsample/pen.cpp new file mode 100644 index 000000000..76473a264 --- /dev/null +++ b/sources/shiboken6/tests/libsample/pen.cpp @@ -0,0 +1,83 @@ +// 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 "pen.h" + +Color::Color(SampleNamespace::InValue) : m_null(false) +{ +} + +Color::Color(unsigned int) : m_null(false) +{ +} + +bool Color::isNull() const +{ + return m_null; +} + +Brush::Brush(const Color &c) : m_color(c) +{ +} + +Brush::operator bool() const +{ + return !m_color.isNull(); +} + +Brush::Style Brush::style() const +{ + return m_style; +} + +void Brush::setStyle(Style newStyle) +{ + m_style = newStyle; +} + +const Color &Brush::color() const +{ + return m_color; +} + +void Brush::setColor(const Color &newColor) +{ + m_color = newColor; +} + +Pen::Pen() = default; + +Pen::Pen(SampleNamespace::Option) : m_ctor(EnumCtor) +{ +} + +Pen::Pen(const Color &) : m_ctor(ColorCtor) +{ +} + +Pen::Pen(const Pen &) : m_ctor(CopyCtor) +{ +} + +Pen::Pen(Pen &&) noexcept = default; +Pen &Pen::operator=(const Pen &pen) = default; +Pen &Pen::operator=(Pen &&) noexcept = default; + +int Pen::ctorType() +{ + return m_ctor; +} + +void Pen::drawLine(int, int, int, int, RenderHints) +{ +} + +Pen::RenderHints Pen::getRenderHints() const +{ + return m_renderHints; +} + +void Pen::setRenderHints(RenderHints h) +{ + m_renderHints = h; +} diff --git a/sources/shiboken6/tests/libsample/pen.h b/sources/shiboken6/tests/libsample/pen.h new file mode 100644 index 000000000..6f528f0f9 --- /dev/null +++ b/sources/shiboken6/tests/libsample/pen.h @@ -0,0 +1,72 @@ +// 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 PEN_H +#define PEN_H + +#include "libsamplemacros.h" +#include "samplenamespace.h" + +class LIBSAMPLE_API Color +{ +public: + Color() = default; + Color(SampleNamespace::InValue arg); + Color(unsigned int arg); + + bool isNull() const; + +private: + bool m_null = true; +}; + +class LIBSAMPLE_API Brush +{ +public: + enum Style { Solid, Cross }; + + explicit Brush(const Color &c = {}); + + operator bool() const; + + Style style() const; + void setStyle(Style newStyle); + + const Color &color() const; + void setColor(const Color &newColor); + +private: + Style m_style = Solid; + Color m_color; +}; + +class LIBSAMPLE_API Pen +{ +public: + enum { EmptyCtor, EnumCtor, ColorCtor, CopyCtor }; + + enum RenderHints { None = 0, Antialiasing = 0x1, TextAntialiasing = 0x2 }; + + Pen(); + Pen(SampleNamespace::Option option); + Pen(const Color &color); + Pen(const Pen &pen); + Pen(Pen &&) noexcept; + Pen &operator=(const Pen &pen); + Pen &operator=(Pen &&) noexcept; + ~Pen() = default; + + // PYSIDE-1325, default initializer + void drawLine(int x1, int y1, int x2, int y2, RenderHints renderHints = {}); + + int ctorType(); + + RenderHints getRenderHints() const; + void setRenderHints(RenderHints h); + +private: + int m_ctor = EmptyCtor; + RenderHints m_renderHints = None; +}; + +#endif diff --git a/sources/shiboken6/tests/libsample/photon.cpp b/sources/shiboken6/tests/libsample/photon.cpp new file mode 100644 index 000000000..2a7f20e33 --- /dev/null +++ b/sources/shiboken6/tests/libsample/photon.cpp @@ -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 + +#include "photon.h" + +namespace Photon +{ + +const ClassType Base::staticType; + +int callCalculateForValueDuplicatorPointer(ValueDuplicator *value) +{ + return value->calculate(); +} + +int callCalculateForValueDuplicatorReference(ValueDuplicator &value) +{ + return value.calculate(); +} + +int countValueIdentities(const std::list<ValueIdentity> &values) +{ + return values.size(); +} + +int countValueDuplicators(const std::list<TemplateBase<DuplicatorType> > &values) +{ + return values.size(); +} + +} // namespace Photon diff --git a/sources/shiboken6/tests/libsample/photon.h b/sources/shiboken6/tests/libsample/photon.h new file mode 100644 index 000000000..2debe47d1 --- /dev/null +++ b/sources/shiboken6/tests/libsample/photon.h @@ -0,0 +1,110 @@ +// 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 PHOTON_H +#define PHOTON_H + +#include "libsamplemacros.h" + +#include <list> + +// This namespace and classes simulate +// situations found in Qt's phonon module. + +namespace Photon +{ + +enum ClassType { + BaseType = 0, + IdentityType = 1, + DuplicatorType = 2 +}; + +class LIBSAMPLE_API Base +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(Base) + + explicit Base(int value) noexcept : m_value(value) {} + virtual ~Base() = default; + + inline void setValue(int value) { m_value = value; } + inline int value() const { return m_value; } + + template <class T> bool isType() { return type() == T::staticType; } + bool isType(ClassType t) { return type() == t; } + + virtual ClassType type() const { return BaseType; }; + static const ClassType staticType = BaseType; + +protected: + int m_value; +}; + +template<ClassType CLASS_TYPE> +class LIBSAMPLE_API TemplateBase : public Base +{ +public: + explicit TemplateBase(int value) : Base(value) {} + inline int multiplicator() const { return int(CLASS_TYPE); } + inline int calculate() const { return m_value * (int(CLASS_TYPE)); } + static inline ClassType classType() { return CLASS_TYPE; } + + inline int sumValueUsingPointer(TemplateBase<CLASS_TYPE> *other) const + { return m_value + other->m_value; } + inline int sumValueUsingReference(TemplateBase<CLASS_TYPE> &other) const + { return m_value + other.m_value; } + + inline std::list<TemplateBase<CLASS_TYPE> > getListOfThisTemplateBase() + { + std::list<TemplateBase<CLASS_TYPE> > objs; + objs.push_back(*this); + objs.push_back(*this); + return objs; + } + + static inline TemplateBase<CLASS_TYPE> *passPointerThrough(TemplateBase<CLASS_TYPE> *obj) + { return obj; } + + ClassType type() const override { return CLASS_TYPE; } + static const ClassType staticType = CLASS_TYPE; +}; + +#if defined _WIN32 || defined __CYGWIN__ +template class LIBSAMPLE_API TemplateBase<IdentityType>; +template class LIBSAMPLE_API TemplateBase<DuplicatorType>; +#endif + +using ValueIdentity = TemplateBase<IdentityType>; +using ValueDuplicator = TemplateBase<DuplicatorType>; + +LIBSAMPLE_API int callCalculateForValueDuplicatorPointer(ValueDuplicator *value); +LIBSAMPLE_API int callCalculateForValueDuplicatorReference(ValueDuplicator &value); +LIBSAMPLE_API int countValueIdentities(const std::list<ValueIdentity> &values); +LIBSAMPLE_API int countValueDuplicators(const std::list<TemplateBase<DuplicatorType> > &values); + +class Pointer +{ +public: + Pointer() noexcept = default; + explicit Pointer(int *p) : px(p) {} + + void reset() noexcept { Pointer().swap(*this); } + + int *get() const noexcept { return px; } + int &operator*() const { return *px; } + + void swap(Pointer &rhs) noexcept + { + int *tmp = px; + px = rhs.px; + rhs.px = tmp; + } + +private: + int *px = nullptr; +}; + +} // namespace Photon + +#endif // PHOTON_H diff --git a/sources/shiboken6/tests/libsample/point.cpp b/sources/shiboken6/tests/libsample/point.cpp new file mode 100644 index 000000000..0a28e877f --- /dev/null +++ b/sources/shiboken6/tests/libsample/point.cpp @@ -0,0 +1,111 @@ +// 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 "point.h" + +#include <iostream> + +Point::Point(int x, int y) noexcept : m_x(x), m_y(y) +{ +} + +Point::Point(double x, double y) noexcept : m_x(x), m_y(y) +{ +} + +void Point::midpoint(const Point &other, Point *midpoint) const +{ + if (!midpoint) + return; + midpoint->setX((m_x + other.m_x) / 2.0); + midpoint->setY((m_y + other.m_y) / 2.0); +} + +Point *Point::copy() const +{ + Point *pt = new Point(); + pt->m_x = m_x; + pt->m_y = m_y; + return pt; +} + +void Point::show() const +{ + std::cout << "(x: " << m_x << ", y: " << m_y << ")"; +} + +bool Point::operator==(const Point &other) const +{ + return m_x == other.m_x && m_y == other.m_y; +} + +Point Point::operator+(const Point &other) +{ + return {m_x + other.m_x, m_y + other.m_y}; +} + +Point Point::operator-(const Point &other) +{ + return {m_x - other.m_x, m_y - other.m_y}; +} + +Point &Point::operator+=(Point &other) +{ + m_x += other.m_x; + m_y += other.m_y; + return *this; +} + +Point &Point::operator-=(Point &other) +{ + m_x -= other.m_x; + m_y -= other.m_y; + return *this; +} + +Point operator*(const Point &pt, double mult) +{ + return Point(pt.m_x * mult, pt.m_y * mult); +} + +Point operator*(const Point &pt, int mult) +{ + return {int(pt.m_x) * mult, int(pt.m_y) * mult}; +} + +Point operator*(double mult, const Point &pt) +{ + return {pt.m_x * mult, pt.m_y * mult}; +} + +Point operator*(int mult, const Point &pt) +{ + return {int(pt.m_x) * mult, int(pt.m_y) * mult}; +} + +Point operator-(const Point &pt) +{ + return {-pt.m_x, -pt.m_y}; +} + +bool operator!(const Point &pt) +{ + return pt.m_x == 0.0 && pt.m_y == 0.0; +} + +Point Point::operator/(int operand) +{ + return {m_x/operand, m_y/operand}; +} + +Complex transmutePointIntoComplex(const Point &point) +{ + Complex cpx(point.x(), point.y()); + return cpx; +} + +Point transmuteComplexIntoPoint(const Complex &cpx) +{ + Point pt(cpx.real(), cpx.imag()); + return pt; +} diff --git a/sources/shiboken6/tests/libsample/point.h b/sources/shiboken6/tests/libsample/point.h new file mode 100644 index 000000000..7e5d128ab --- /dev/null +++ b/sources/shiboken6/tests/libsample/point.h @@ -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 + +#ifndef POINT_H +#define POINT_H + +#include "libsamplemacros.h" +#include "complex.h" + +#include <utility> + +class LIBSAMPLE_API Point +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(Point) + + Point(int x = 0, int y = 0) noexcept; + Point(double x, double y) noexcept; + ~Point() = default; + + inline double x() const { return m_x; } + inline double y() const { return m_y; } + + inline void setX(double x) { m_x = x; } + inline void setY(double y) { m_y = y; } + inline void setXAsUint(unsigned int x) { m_x = x; } + inline void setYAsUint(unsigned int y) { m_y = y; } + + // This method could simply return the midpoint, + // but the interesting part of the test is to set the + // result in the pointer argument. + void midpoint(const Point &other, Point *midpoint) const; + + Point *copy() const; + + inline const Point &getConstReferenceToSelf() const { return *this; } + inline const Point *getSelf() const { return this; } + + // The != operator is not implemented for the purpose of testing + // for the absense of the __ne__ method in the Python binding. + bool operator==(const Point &other) const; + + Point operator+(const Point &other); + Point operator-(const Point &other); + Point operator/(int operand); + + friend LIBSAMPLE_API Point operator*(const Point &pt, double mult); + friend LIBSAMPLE_API Point operator*(const Point &pt, int mult); + friend LIBSAMPLE_API Point operator*(double mult, const Point &pt); + friend LIBSAMPLE_API Point operator*(int mult, const Point &pt); + friend LIBSAMPLE_API Point operator-(const Point &pt); + friend LIBSAMPLE_API bool operator!(const Point &pt); + + Point &operator+=(Point &other); + Point &operator-=(Point &other); + + void show() const; + +private: + double m_x; + double m_y; +}; + +LIBSAMPLE_API Point operator*(const Point &pt, double mult); +LIBSAMPLE_API Point operator*(const Point &pt, int mult); +LIBSAMPLE_API Point operator*(double mult, const Point &pt); +LIBSAMPLE_API Point operator*(int mult, const Point &pt); +LIBSAMPLE_API Point operator-(const Point &pt); +LIBSAMPLE_API bool operator!(const Point &pt); + +LIBSAMPLE_API Complex transmutePointIntoComplex(const Point &point); +LIBSAMPLE_API Point transmuteComplexIntoPoint(const Complex &cpx); + +LIBSAMPLE_API Point operator*(const Point &pt, double multiplier); + +#endif // POINT_H diff --git a/sources/shiboken6/tests/libsample/pointerholder.h b/sources/shiboken6/tests/libsample/pointerholder.h new file mode 100644 index 000000000..26f1cf0a6 --- /dev/null +++ b/sources/shiboken6/tests/libsample/pointerholder.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 POINTERHOLDER_H +#define POINTERHOLDER_H + +#include "libsamplemacros.h" + +class PointerHolder +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(PointerHolder) + + explicit PointerHolder(void *ptr) : m_pointer(ptr) {} + ~PointerHolder() = default; + + inline void *pointer() const { return m_pointer; } + +private: + void *m_pointer; +}; + +#endif // POINTERHOLDER_H diff --git a/sources/shiboken6/tests/libsample/pointf.cpp b/sources/shiboken6/tests/libsample/pointf.cpp new file mode 100644 index 000000000..736a5c6b5 --- /dev/null +++ b/sources/shiboken6/tests/libsample/pointf.cpp @@ -0,0 +1,86 @@ +// 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 "pointf.h" + +#include <iostream> + +PointF::PointF(const Point &point) noexcept : m_x(point.x()), m_y(point.y()) +{ +} + +PointF::PointF(double x, double y) noexcept : m_x(x), m_y(y) +{ +} + +void PointF::midpoint(const PointF &other, PointF *midpoint) const +{ + if (!midpoint) + return; + midpoint->setX((m_x + other.m_x) / 2.0); + midpoint->setY((m_y + other.m_y) / 2.0); +} + +void PointF::show() const +{ + std::cout << "(x: " << m_x << ", y: " << m_y << ")"; +} + +bool PointF::operator==(const PointF &other) const +{ + return m_x == other.m_x && m_y == other.m_y; +} + +PointF PointF::operator+(const PointF &other) +{ + return {m_x + other.m_x, m_y + other.m_y}; +} + +PointF PointF::operator-(const PointF &other) +{ + return {m_x - other.m_x, m_y - other.m_y}; +} + +PointF &PointF::operator+=(PointF &other) +{ + m_x += other.m_x; + m_y += other.m_y; + return *this; +} + +PointF &PointF::operator-=(PointF &other) +{ + m_x -= other.m_x; + m_y -= other.m_y; + return *this; +} + +PointF operator*(const PointF &pt, double mult) +{ + return {pt.m_x * mult, pt.m_y * mult}; +} + +PointF operator*(const PointF &pt, int mult) +{ + return PointF(int(pt.m_x) * mult, int(pt.m_y) * mult); +} + +PointF operator*(double mult, const PointF &pt) +{ + return {pt.m_x * mult, pt.m_y * mult}; +} + +PointF operator*(int mult, const PointF &pt) +{ + return PointF(int(pt.m_x) * mult, int(pt.m_y) * mult); +} + +PointF operator-(const PointF &pt) +{ + return {-pt.m_x, -pt.m_y}; +} + +bool operator!(const PointF &pt) +{ + return pt.m_x == 0.0 && pt.m_y == 0.0; +} diff --git a/sources/shiboken6/tests/libsample/pointf.h b/sources/shiboken6/tests/libsample/pointf.h new file mode 100644 index 000000000..49e009467 --- /dev/null +++ b/sources/shiboken6/tests/libsample/pointf.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 POINTF_H +#define POINTF_H + +#include "libsamplemacros.h" +#include "point.h" + +#include <utility> + +class LIBSAMPLE_API PointF +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(PointF) + + PointF(const Point &point) noexcept; + PointF(double x = 0.0, double y = 0.0) noexcept; + ~PointF() noexcept = default; + + inline double x() const { return m_x; } + inline double y() const { return m_y; } + + inline void setX(double x) { m_x = x; } + inline void setY(double y) { m_y = y; } + + // This method could simply return the midpoint, + // but the interesting part of the test is to set the + // result in the pointer argument. + void midpoint(const PointF &other, PointF *midpoint) const; + + // The != operator is not implemented for the purpose of testing + // for the absence of the __ne__ method in the Python binding. + bool operator==(const PointF &other) const; + + PointF operator+(const PointF &other); + PointF operator-(const PointF &other); + + friend LIBSAMPLE_API PointF operator*(const PointF &pt, double mult); + friend LIBSAMPLE_API PointF operator*(const PointF &pt, int mult); + friend LIBSAMPLE_API PointF operator*(double mult, const PointF &pt); + friend LIBSAMPLE_API PointF operator*(int mult, const PointF &pt); + friend LIBSAMPLE_API PointF operator-(const PointF &pt); + friend LIBSAMPLE_API bool operator!(const PointF &pt); + + PointF &operator+=(PointF &other); + PointF &operator-=(PointF &other); + + void show() const; + +private: + double m_x; + double m_y; +}; + +LIBSAMPLE_API PointF operator*(const PointF &pt, double mult); +LIBSAMPLE_API PointF operator*(const PointF &pt, int mult); +LIBSAMPLE_API PointF operator*(double mult, const PointF &pt); +LIBSAMPLE_API PointF operator*(int mult, const PointF &pt); +LIBSAMPLE_API PointF operator-(const PointF &pt); +LIBSAMPLE_API bool operator!(const PointF &pt); + +LIBSAMPLE_API PointF operator*(const PointF &pt, double multiplier); + +#endif // POINTF_H diff --git a/sources/shiboken6/tests/libsample/polygon.cpp b/sources/shiboken6/tests/libsample/polygon.cpp new file mode 100644 index 000000000..6af597192 --- /dev/null +++ b/sources/shiboken6/tests/libsample/polygon.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 "polygon.h" + +Polygon::Polygon(double x, double y) : m_points({Point(x, y)}) +{ +} + +Polygon::Polygon(Point point) : m_points({point}) +{ +} + +Polygon::Polygon(PointList points) : m_points(points) +{ +} + +void Polygon::addPoint(Point point) +{ + m_points.push_back(point); +} + +Polygon Polygon::doublePolygonScale(Polygon polygon) +{ + Polygon result; + for (const auto &point : polygon.points()) + result.addPoint(point * 2.0); + return result; +} + +void Polygon::stealOwnershipFromPython(Point *point) +{ + delete point; +} + +void Polygon::stealOwnershipFromPython(Polygon *polygon) +{ + delete polygon; +} diff --git a/sources/shiboken6/tests/libsample/polygon.h b/sources/shiboken6/tests/libsample/polygon.h new file mode 100644 index 000000000..2424ddd51 --- /dev/null +++ b/sources/shiboken6/tests/libsample/polygon.h @@ -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 + +#ifndef POLYGON_H +#define POLYGON_H + +#include "libsamplemacros.h" +#include "point.h" + +#include <list> + +class LIBSAMPLE_API Polygon // should be moveable +{ +public: + using PointList = std::list<Point>; + + Polygon() noexcept = default; + Polygon(double x, double y); + Polygon(Point point); + Polygon(PointList points); + + void addPoint(Point point); + + inline const PointList &points() const { return m_points; } + + // This method intentionally receives and returns copies of a Polygon object. + static Polygon doublePolygonScale(Polygon polygon); + + // This method invalidates the argument to be used for Polygon(Point) implicit conversion. + static void stealOwnershipFromPython(Point *point); + + // This method invalidates the argument to be used in a call to doublePolygonScale(Polygon). + static void stealOwnershipFromPython(Polygon *polygon); + +private: + PointList m_points; +}; + +#endif // POLYGON_H diff --git a/sources/shiboken6/tests/libsample/privatector.h b/sources/shiboken6/tests/libsample/privatector.h new file mode 100644 index 000000000..3b38414f8 --- /dev/null +++ b/sources/shiboken6/tests/libsample/privatector.h @@ -0,0 +1,42 @@ +// 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 PRIVATECTOR_H +#define PRIVATECTOR_H + +#include "libsamplemacros.h" + +class PrivateCtor +{ +public: + inline static PrivateCtor *instance() + { + static PrivateCtor self; + self.m_instantiations++; + return &self; + } + + inline int instanceCalls() + { + return m_instantiations; + } + +private: + int m_instantiations = 0; + + PrivateCtor() = default; +}; + +class DeletedDefaultCtor +{ +public: + DeletedDefaultCtor() = delete; + + DeletedDefaultCtor(const DeletedDefaultCtor &) = default; + DeletedDefaultCtor(DeletedDefaultCtor &&) = default; + DeletedDefaultCtor &operator=(const DeletedDefaultCtor &) = default; + DeletedDefaultCtor &operator=(DeletedDefaultCtor &&) = default; + ~DeletedDefaultCtor() = default; +}; + +#endif // PRIVATECTOR_H diff --git a/sources/shiboken6/tests/libsample/privatedtor.h b/sources/shiboken6/tests/libsample/privatedtor.h new file mode 100644 index 000000000..05f18ea53 --- /dev/null +++ b/sources/shiboken6/tests/libsample/privatedtor.h @@ -0,0 +1,36 @@ +// 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 PRIVATEDTOR_H +#define PRIVATEDTOR_H + +#include "libsamplemacros.h" + +class PrivateDtor +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(PrivateDtor) + + inline static PrivateDtor *instance() + { + static PrivateDtor self; + self.m_instantiations++; + return &self; + } + + inline int instanceCalls() + { + return m_instantiations; + } + +protected: + inline int protectedInstanceCalls() { return m_instantiations; } + +private: + int m_instantiations = 0; + + PrivateDtor() noexcept = default; + ~PrivateDtor() = default; +}; + +#endif // PRIVATEDTOR_H diff --git a/sources/shiboken6/tests/libsample/protected.cpp b/sources/shiboken6/tests/libsample/protected.cpp new file mode 100644 index 000000000..7ab52d22b --- /dev/null +++ b/sources/shiboken6/tests/libsample/protected.cpp @@ -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 + +#include "protected.h" + +int ProtectedVirtualDestructor::dtor_called = 0; + +const char *ProtectedNonPolymorphic::dataTypeName(void *) const +{ + return "pointer"; +} + +const char *ProtectedNonPolymorphic::dataTypeName(int) const +{ + return "integer"; +} diff --git a/sources/shiboken6/tests/libsample/protected.h b/sources/shiboken6/tests/libsample/protected.h new file mode 100644 index 000000000..059cced5d --- /dev/null +++ b/sources/shiboken6/tests/libsample/protected.h @@ -0,0 +1,139 @@ +// 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 PROTECTED_H +#define PROTECTED_H + +#include "libsamplemacros.h" +#include "objecttype.h" +#include "point.h" + +#include <string> +#include <list> + +class LIBSAMPLE_API ProtectedNonPolymorphic +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(ProtectedNonPolymorphic) + + explicit ProtectedNonPolymorphic(const char *name) : m_name(name) {} + ~ProtectedNonPolymorphic() = default; + + inline const char *publicName() { return m_name.c_str(); } + + inline static ProtectedNonPolymorphic *create() + { return new ProtectedNonPolymorphic("created"); } + +protected: + inline const char *protectedName() { return m_name.c_str(); } + inline int protectedSum(int a0, int a1) { return a0 + a1; } + inline int modifiedProtectedSum(int a0, int a1) { return a0 + a1; } + inline static const char *protectedStatic() { return "protectedStatic"; } + const char *dataTypeName(void *data = nullptr) const; + const char *dataTypeName(int data) const; + +private: + std::string m_name; +}; + +class LIBSAMPLE_API ProtectedPolymorphic +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(ProtectedPolymorphic) + + explicit ProtectedPolymorphic(const char *name) : m_name(name) {} + virtual ~ProtectedPolymorphic() = default; + + inline static ProtectedPolymorphic *create() + { return new ProtectedPolymorphic("created"); } + inline const char *publicName() { return m_name.c_str(); } + inline const char *callProtectedName() { return protectedName(); } + +protected: + virtual const char *protectedName() { return m_name.c_str(); } + +private: + std::string m_name; +}; + +class LIBSAMPLE_API ProtectedPolymorphicDaughter : public ProtectedPolymorphic +{ +public: + explicit ProtectedPolymorphicDaughter(const char *name) : + ProtectedPolymorphic(name) {} + inline static ProtectedPolymorphicDaughter *create() + { return new ProtectedPolymorphicDaughter("created"); } +}; + +class LIBSAMPLE_API ProtectedPolymorphicGrandDaughter: public ProtectedPolymorphicDaughter +{ +public: + explicit ProtectedPolymorphicGrandDaughter(const char *name) : + ProtectedPolymorphicDaughter(name) {} + inline static ProtectedPolymorphicGrandDaughter *create() + { return new ProtectedPolymorphicGrandDaughter("created"); } +}; + +class LIBSAMPLE_API ProtectedVirtualDestructor +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(ProtectedVirtualDestructor) + + ProtectedVirtualDestructor() noexcept = default; + inline static ProtectedVirtualDestructor *create() + { return new ProtectedVirtualDestructor(); } + inline static int dtorCalled() { return dtor_called; } + inline static void resetDtorCounter() { dtor_called = 0; } +protected: + virtual ~ProtectedVirtualDestructor() { dtor_called++; } +private: + static int dtor_called; +}; + +class LIBSAMPLE_API ProtectedEnumClass +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(ProtectedEnumClass) + + ProtectedEnumClass() noexcept = default; + virtual ~ProtectedEnumClass() = default; + enum PublicEnum { + PublicItem0, + PublicItem1 + }; +protected: + enum ProtectedEnum { + ProtectedItem0, + ProtectedItem1 + }; + ProtectedEnum callProtectedEnumMethod(ProtectedEnum in) + { return protectedEnumMethod(in); } + inline PublicEnum callPublicEnumMethod(PublicEnum in) + { return publicEnumMethod(in); } + + virtual ProtectedEnum protectedEnumMethod(ProtectedEnum in) { return in; } + virtual PublicEnum publicEnumMethod(PublicEnum in) { return in; } +}; + +class LIBSAMPLE_API ProtectedProperty +{ +public: + ProtectedProperty() = default; + +protected: + // This is deliberately the first member to test wrapper registration + // for value type members sharing the same memory address. + Point protectedValueTypeProperty{0, 0}; + int protectedProperty = 0; + std::list<int> protectedContainerProperty; + Event::EventType protectedEnumProperty = Event::NO_EVENT; + Point *protectedValueTypePointerProperty = nullptr; + ObjectType *protectedObjectTypeProperty = nullptr; +}; + +LIBSAMPLE_API inline ProtectedProperty *createProtectedProperty() +{ + return new ProtectedProperty; +} + +#endif // PROTECTED_H diff --git a/sources/shiboken6/tests/libsample/rect.h b/sources/shiboken6/tests/libsample/rect.h new file mode 100644 index 000000000..53296d26c --- /dev/null +++ b/sources/shiboken6/tests/libsample/rect.h @@ -0,0 +1,54 @@ +// 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 RECT_H +#define RECT_H + +#include "libsamplemacros.h" + +class LIBSAMPLE_API Rect +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(Rect) + + Rect() noexcept = default; + explicit Rect(int left, int top, int right, int bottom) noexcept + : m_left(left), m_top(top), m_right(right), m_bottom(bottom) { } + ~Rect() = default; + + inline int left() const { return m_left; } + inline int top() const { return m_top; } + inline int right() const { return m_right; } + inline int bottom() const { return m_bottom; } +private: + int m_left = 0; + int m_top = 0; + int m_right = -1; + int m_bottom = -1; +}; + +class LIBSAMPLE_API RectF +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(RectF) + + RectF() noexcept = default; + explicit RectF(int left, int top, int right, int bottom) noexcept + : m_left(left), m_top(top), m_right(right), m_bottom(bottom) { } + RectF(const Rect &other) noexcept : + m_left(other.left()), m_top(other.top()), + m_right(other.right()), m_bottom(other.bottom()) {} + ~RectF() = default; + + inline double left() const { return m_left; } + inline double top() const { return m_top; } + inline double right() const { return m_right; } + inline double bottom() const { return m_bottom; } +private: + double m_left = 0; + double m_top = 0; + double m_right = -1; + double m_bottom = -1; +}; + +#endif // RECT_H diff --git a/sources/shiboken6/tests/libsample/reference.cpp b/sources/shiboken6/tests/libsample/reference.cpp new file mode 100644 index 000000000..29dcfc054 --- /dev/null +++ b/sources/shiboken6/tests/libsample/reference.cpp @@ -0,0 +1,53 @@ +// 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 "reference.h" + +#include <iostream> + +void Reference::show() const +{ + std::cout << "Reference.objId: " << m_objId << ", address: " << this; +} + +Reference &Reference::returnMySecondArg(int, Reference &ref) +{ + return ref; +} + +int Reference::usesReferenceVirtual(Reference &r, int inc) +{ + return r.m_objId + inc; +} + +int Reference::usesConstReferenceVirtual(const Reference &r, int inc) +{ + return r.m_objId + inc; +} + +int Reference::callUsesReferenceVirtual(Reference &r, int inc) +{ + return usesReferenceVirtual(r, inc); +} + +int Reference::callUsesConstReferenceVirtual(const Reference &r, int inc) +{ + return usesConstReferenceVirtual(r, inc); +} + +void Reference::alterReferenceIdVirtual(Reference &r) +{ + r.setObjId(r.objId() * Reference::multiplier()); +} + +void Reference::callAlterReferenceIdVirtual(Reference &r) +{ + alterReferenceIdVirtual(r); +} + +ObjTypeReference::~ObjTypeReference() = default; + +ObjTypeReference &ObjTypeReference::returnMySecondArg(int, ObjTypeReference &ref) +{ + return ref; +} diff --git a/sources/shiboken6/tests/libsample/reference.h b/sources/shiboken6/tests/libsample/reference.h new file mode 100644 index 000000000..52818d9ea --- /dev/null +++ b/sources/shiboken6/tests/libsample/reference.h @@ -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 + +#ifndef REFERENCE_H +#define REFERENCE_H + +#include "libsamplemacros.h" + +class LIBSAMPLE_API Reference +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(Reference) + + explicit Reference(int objId = -1) noexcept + : m_objId(objId) {} + virtual ~Reference() = default; + + inline int objId() const { return m_objId; } + inline void setObjId(int objId) { m_objId = objId; } + + inline static int usesReference(Reference &r) { return r.m_objId; } + inline static int usesConstReference(const Reference &r) { return r.m_objId; } + + virtual int usesReferenceVirtual(Reference &r, int inc); + virtual int usesConstReferenceVirtual(const Reference &r, int inc); + + int callUsesReferenceVirtual(Reference &r, int inc); + int callUsesConstReferenceVirtual(const Reference &r, int inc); + + virtual void alterReferenceIdVirtual(Reference &r); + void callAlterReferenceIdVirtual(Reference &r); + + void show() const; + + inline static int multiplier() { return 10; } + + virtual Reference &returnMyFirstArg(Reference &ref) { return ref; } + virtual Reference &returnMySecondArg(int a, Reference &ref); + + // nonsense operator to test if Shiboken is ignoring dereference operators. + int operator*() { return m_objId; } + +private: + int m_objId; +}; + +class LIBSAMPLE_API ObjTypeReference +{ +public: + LIBMINIMAL_DISABLE_MOVE(ObjTypeReference) + + ObjTypeReference() noexcept = default; + ObjTypeReference(const ObjTypeReference &) noexcept = default; + ObjTypeReference &operator=(const ObjTypeReference &) = delete; + virtual ~ObjTypeReference(); + + virtual ObjTypeReference &returnMyFirstArg(ObjTypeReference &ref) { return ref; } + virtual ObjTypeReference &returnMySecondArg(int a, ObjTypeReference &ref); + virtual ObjTypeReference &justAPureVirtualFunc(ObjTypeReference &ref) = 0; +}; + +#endif // REFERENCE_H diff --git a/sources/shiboken6/tests/libsample/removednamespaces.h b/sources/shiboken6/tests/libsample/removednamespaces.h new file mode 100644 index 000000000..669f2ebf0 --- /dev/null +++ b/sources/shiboken6/tests/libsample/removednamespaces.h @@ -0,0 +1,48 @@ +// 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 REMOVEDNAMESPACE_H +#define REMOVEDNAMESPACE_H + +#include "libsamplemacros.h" + +namespace RemovedNamespace1 +{ + +enum RemovedNamespace1_Enum { RemovedNamespace1_Enum_Value0 = 0, + RemovedNamespace1_Enum_Value1 = 1 }; + +enum { RemovedNamespace1_AnonymousEnum_Value0 }; + +inline int mathSum(int x, int y) { return x + y; } + +struct ObjectOnInvisibleNamespace +{ + bool exists() const { return true; } + static int toInt(RemovedNamespace1_Enum e) { return static_cast<int>(e); } + static ObjectOnInvisibleNamespace consume(const ObjectOnInvisibleNamespace &other) { return other; } +}; + +namespace RemovedNamespace2 +{ + +enum RemovedNamespace2_Enum { RemovedNamespace2_Enum_Value0 }; + +} // namespace RemovedNamespace2 +} // namespace RemovedNamespace1 + +namespace UnremovedNamespace +{ + +namespace RemovedNamespace3 +{ + enum RemovedNamespace3_Enum { RemovedNamespace3_Enum_Value0 }; + + enum { RemovedNamespace3_AnonymousEnum_Value0 }; + + inline int nestedMathSum(int x, int y) { return x + y; } + +} // namespace RemovedNamespace3 +} // namespace UnremovedNamespace + +#endif // REMOVEDNAMESPACE_H diff --git a/sources/shiboken6/tests/libsample/renaming.cpp b/sources/shiboken6/tests/libsample/renaming.cpp new file mode 100644 index 000000000..d67b42a51 --- /dev/null +++ b/sources/shiboken6/tests/libsample/renaming.cpp @@ -0,0 +1,21 @@ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "renaming.h" + +#include <iostream> + +int ToBeRenamedValue::value() const +{ + return m_value; +} + +void ToBeRenamedValue::setValue(int v) +{ + m_value = v; +} + +void RenamedUser::useRenamedValue(const ToBeRenamedValue &v) +{ + std::cout << __FUNCTION__ << ' ' << v.value() << '\n'; +} diff --git a/sources/shiboken6/tests/libsample/renaming.h b/sources/shiboken6/tests/libsample/renaming.h new file mode 100644 index 000000000..787ccc2f7 --- /dev/null +++ b/sources/shiboken6/tests/libsample/renaming.h @@ -0,0 +1,25 @@ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef RENAMING_H +#define RENAMING_H + +#include "libsamplemacros.h" + +class LIBSAMPLE_API ToBeRenamedValue +{ +public: + int value() const; + void setValue(int v); + +private: + int m_value = 42; +}; + +class LIBSAMPLE_API RenamedUser +{ +public: + void useRenamedValue(const ToBeRenamedValue &v); +}; + +#endif // POINT_H diff --git a/sources/shiboken6/tests/libsample/sample.cpp b/sources/shiboken6/tests/libsample/sample.cpp new file mode 100644 index 000000000..5b5f8588b --- /dev/null +++ b/sources/shiboken6/tests/libsample/sample.cpp @@ -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 + +#include "sample.h" + +namespace sample +{ + +sample::sample(int value) : m_value(value) +{ +} + +int sample::value() const +{ + return m_value; +} + +bool operator==(const sample &s1, const sample &s2) +{ + return s1.value() == s2.value(); +} +} // namespace sample diff --git a/sources/shiboken6/tests/libsample/sample.h b/sources/shiboken6/tests/libsample/sample.h new file mode 100644 index 000000000..27909571a --- /dev/null +++ b/sources/shiboken6/tests/libsample/sample.h @@ -0,0 +1,28 @@ +// 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 SAMPLE_H +#define SAMPLE_H + +#include "libsamplemacros.h" + +// namespace with the same name of the current package to try to mess up with the generator +namespace sample +{ + // to increase the mess we add a class with the same name of the package/namespace + class LIBSAMPLE_API sample + { + public: + sample(int value = 0); + int value() const; + private: + int m_value; + }; + + // shiboken must not generate richcompare for namespace sample + LIBSAMPLE_API bool operator==(const sample &s1, const sample &s2); + + const int INT_CONSTANT = 42; +} + +#endif // SAMPLE_H diff --git a/sources/shiboken6/tests/libsample/samplenamespace.cpp b/sources/shiboken6/tests/libsample/samplenamespace.cpp new file mode 100644 index 000000000..eae5af2d2 --- /dev/null +++ b/sources/shiboken6/tests/libsample/samplenamespace.cpp @@ -0,0 +1,101 @@ +// 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 "samplenamespace.h" + +#include <iostream> +#include <cstdlib> +#include <ctime> + +namespace SampleNamespace +{ + +// PYSIDE-817, scoped enums must not be converted to int in the wrappers generated +// for the protected hacks +SomeClass::PublicScopedEnum SomeClass::protectedMethodReturningPublicScopedEnum() const +{ + return PublicScopedEnum::v1; +} + +OutValue enumInEnumOut(InValue in) +{ + auto retval = OutValue(-1); + switch(in) { + case ZeroIn: + retval = ZeroOut; + break; + case OneIn: + retval = OneOut; + break; + case TwoIn: + retval = TwoOut; + break; + default: + break; + } + return retval; +} + +Option enumArgumentWithDefaultValue(Option opt) +{ + return opt; +} + +int getNumber(Option opt) +{ + int retval; + switch(opt) { + case RandomNumber: + retval = rand() % 100; + break; + case UnixTime: + retval = int(std::time(nullptr)); + break; + default: + retval = 0; + break; + } + return retval; +} + +void doSomethingWithArray(const unsigned char *, unsigned int, const char *) +{ + // This function does nothing in fact. + // It is here as a dummy copy of QPixmap.loadFromData method + // to check compilation issues, i.e. if it compiles, it's ok. +} + +int enumItemAsDefaultValueToIntArgument(int value) +{ + return value; +} + +void forceDecisorSideA(ObjectType *) +{ +} + +void forceDecisorSideA(const Point &, const Str &, ObjectType *) +{ +} + +void forceDecisorSideB(int, ObjectType *) +{ +} + +void forceDecisorSideB(int, const Point &, const Str &, ObjectType *) +{ +} + +double passReferenceToValueType(const Point &point, double multiplier) +{ + return (point.x() + point.y()) * multiplier; +} + +int passReferenceToObjectType(const ObjectType &obj, int multiplier) +{ + return obj.objectName().size() * multiplier; +} + +int variableInNamespace = 42; + +} // namespace SampleNamespace diff --git a/sources/shiboken6/tests/libsample/samplenamespace.h b/sources/shiboken6/tests/libsample/samplenamespace.h new file mode 100644 index 000000000..99a0787ee --- /dev/null +++ b/sources/shiboken6/tests/libsample/samplenamespace.h @@ -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 + +#ifndef SAMPLENAMESPACE_H +#define SAMPLENAMESPACE_H + +#include "libsamplemacros.h" +#include "str.h" +#include "point.h" +#include "objecttype.h" + +#include <list> + +// Anonymous global enum +enum { + AnonymousGlobalEnum_Value0, + AnonymousGlobalEnum_Value1 +}; + +namespace SampleNamespace +{ + +inline namespace InlineNamespace +{ + enum EnumWithinInlineNamespace { EWIN_Value0, EWIN_Value1 }; + + class LIBSAMPLE_API ClassWithinInlineNamespace { + public: + LIBMINIMAL_DEFAULT_COPY_MOVE(ClassWithinInlineNamespace) + + ClassWithinInlineNamespace() noexcept = default; + ~ClassWithinInlineNamespace() = default; + + void setValue(EnumWithinInlineNamespace v) { m_value = v; } + EnumWithinInlineNamespace value() const { return m_value; } + + private: + EnumWithinInlineNamespace m_value = EWIN_Value0; + }; +} // inline ns + +enum Option { + None_, + RandomNumber, + UnixTime +}; + +enum InValue { + ZeroIn, + OneIn, + TwoIn +}; + +enum OutValue { + ZeroOut, + OneOut, + TwoOut +}; + +// Anonymous non-global enum. +// This counts as a class enum, since C++ namespaces +// are represented as classes in Python. +enum { + AnonymousClassEnum_Value0, + AnonymousClassEnum_Value1 +}; + +LIBSAMPLE_API OutValue enumInEnumOut(InValue in); + +LIBSAMPLE_API Option enumArgumentWithDefaultValue(Option opt = UnixTime); + +LIBSAMPLE_API int getNumber(Option opt); + +inline double powerOfTwo(double num) { + return num * num; +} + +LIBSAMPLE_API void doSomethingWithArray(const unsigned char *data, unsigned int size, + const char *format = nullptr); + +LIBSAMPLE_API int enumItemAsDefaultValueToIntArgument(int value = ZeroIn); + +class LIBSAMPLE_API SomeClass +{ +public: + enum class PublicScopedEnum { v1, v2 }; + + class SomeInnerClass + { + public: + class OkThisIsRecursiveEnough + { + public: + LIBMINIMAL_DISABLE_COPY_MOVE(OkThisIsRecursiveEnough) + + OkThisIsRecursiveEnough() noexcept = default; + virtual ~OkThisIsRecursiveEnough() = default; + enum NiceEnum { + NiceValue1, NiceValue2 + }; + + enum class NiceEnumClass { + NiceClassValue1, NiceClassValue2 + }; + + inline int someMethod(SomeInnerClass *) { return 0; } + virtual OkThisIsRecursiveEnough *someVirtualMethod(OkThisIsRecursiveEnough *arg) + { return arg; } + }; + protected: + enum ProtectedEnum { + ProtectedItem0, + ProtectedItem1 + }; + }; + struct SomeOtherInnerClass { + std::list<SomeInnerClass> someInnerClasses; + }; +protected: + enum ProtectedEnum { + ProtectedItem0, + ProtectedItem1 + }; + + PublicScopedEnum protectedMethodReturningPublicScopedEnum() const; +}; + +LIBSAMPLE_API inline int enumAsInt(SomeClass::PublicScopedEnum value) +{ return static_cast<int>(value); } + +class DerivedFromNamespace : public SomeClass::SomeInnerClass::OkThisIsRecursiveEnough +{ +public: + // FIXME Uncomment this when the fix for MSVC is available + // only to cause namespace confusion +// enum SampleNamespace { +// }; + virtual OkThisIsRecursiveEnough *someVirtualMethod(OkThisIsRecursiveEnough *arg) { return arg; } + inline OkThisIsRecursiveEnough *methodReturningTypeFromParentScope() { return nullptr; } +}; + +// The combination of the following two overloaded methods could trigger a +// problematic behaviour on the overload decisor, if it isn't working properly. +LIBSAMPLE_API void forceDecisorSideA(ObjectType *object = nullptr); +LIBSAMPLE_API void forceDecisorSideA(const Point &pt, const Str &text, + ObjectType *object = nullptr); + +// The combination of the following two overloaded methods could trigger a +// problematic behaviour on the overload decisor, if it isn't working properly. +// This is a variation of forceDecisorSideB. +LIBSAMPLE_API void forceDecisorSideB(int a, ObjectType *object = nullptr); +LIBSAMPLE_API void forceDecisorSideB(int a, const Point &pt, const Str &text, + ObjectType *object = nullptr); + +// Add a new signature on type system with only a Point value as parameter. +LIBSAMPLE_API double passReferenceToValueType(const Point &point, double multiplier); +// Add a new signature on type system with only a ObjectType pointer as parameter. +LIBSAMPLE_API int passReferenceToObjectType(const ObjectType &obj, int multiplier); + +extern LIBSAMPLE_API int variableInNamespace; + +} // namespace SampleNamespace + +#endif // SAMPLENAMESPACE_H diff --git a/sources/shiboken6/tests/libsample/sbkdate.cpp b/sources/shiboken6/tests/libsample/sbkdate.cpp new file mode 100644 index 000000000..fd408f637 --- /dev/null +++ b/sources/shiboken6/tests/libsample/sbkdate.cpp @@ -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 + +#include "sbkdate.h" + +SbkDate::SbkDate(int d, int m, int y) : m_d(d), m_m(m), m_y(y) +{ +} + +int SbkDate::day() const +{ + return m_d; +} + +int SbkDate::month() const +{ + return m_m; +} + +int SbkDate::year() const +{ + return m_y; +} diff --git a/sources/shiboken6/tests/libsample/sbkdate.h b/sources/shiboken6/tests/libsample/sbkdate.h new file mode 100644 index 000000000..5e1dd0b84 --- /dev/null +++ b/sources/shiboken6/tests/libsample/sbkdate.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 SBKDATE_H +#define SBKDATE_H + +#include "libsamplemacros.h" + +class LIBSAMPLE_API SbkDate +{ +public: + explicit SbkDate(int d, int m, int y); + + int day() const; + int month() const; + int year() const; + +private: + int m_d; + int m_m; + int m_y; +}; + +#endif // SBKDATE_H diff --git a/sources/shiboken6/tests/libsample/simplefile.cpp b/sources/shiboken6/tests/libsample/simplefile.cpp new file mode 100644 index 000000000..e51b14088 --- /dev/null +++ b/sources/shiboken6/tests/libsample/simplefile.cpp @@ -0,0 +1,73 @@ +// 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 "simplefile.h" + +#include <cstdlib> +#include <cstdio> +#include <string> +#include <filesystem> + +class SimpleFilePrivate +{ +public: + LIBMINIMAL_DISABLE_COPY_MOVE(SimpleFilePrivate) + + SimpleFilePrivate(const char *filename) : m_filename(filename) {} + ~SimpleFilePrivate() = default; + + std::string m_filename; + FILE *m_descriptor = nullptr; + long m_size = 0; +}; + +SimpleFile::SimpleFile(const char *filename) : + p(std::make_unique<SimpleFilePrivate>(filename)) +{ +} + +SimpleFile::~SimpleFile() +{ + close(); +} + +const char *SimpleFile::filename() +{ + return p->m_filename.c_str(); +} + +long SimpleFile::size() const +{ + return p->m_size; +} + +bool SimpleFile::open() +{ + auto *descriptor = std::fopen(p->m_filename.c_str(), "rb"); + if (descriptor == nullptr) + return false; + + p->m_descriptor = descriptor; + const auto size = std::filesystem::file_size(std::filesystem::path(p->m_filename)); + p->m_size = long(size); + + return true; +} + +void SimpleFile::close() +{ + if (p->m_descriptor != nullptr) { + std::fclose(p->m_descriptor); + p->m_descriptor = nullptr; + } +} + +bool SimpleFile::exists() const +{ + return std::filesystem::exists(std::filesystem::path(p->m_filename)); +} + +bool SimpleFile::exists(const char *filename) +{ + return std::filesystem::exists(std::filesystem::path(filename)); +} diff --git a/sources/shiboken6/tests/libsample/simplefile.h b/sources/shiboken6/tests/libsample/simplefile.h new file mode 100644 index 000000000..e4612c944 --- /dev/null +++ b/sources/shiboken6/tests/libsample/simplefile.h @@ -0,0 +1,34 @@ +// 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 SIMPLEFILE_H +#define SIMPLEFILE_H + +#include "libsamplemacros.h" + +#include <memory> + +class SimpleFilePrivate; + +class LIBSAMPLE_API SimpleFile +{ +public: + LIBMINIMAL_DISABLE_COPY(SimpleFile) + LIBMINIMAL_DEFAULT_MOVE(SimpleFile) + + explicit SimpleFile(const char *filename); + ~SimpleFile(); + + const char *filename(); + long size() const; + bool open(); + void close(); + + bool exists() const; + static bool exists(const char *filename); + +private: + std::unique_ptr<SimpleFilePrivate> p; +}; + +#endif // SIMPLEFILE_H diff --git a/sources/shiboken6/tests/libsample/size.cpp b/sources/shiboken6/tests/libsample/size.cpp new file mode 100644 index 000000000..0291d6e86 --- /dev/null +++ b/sources/shiboken6/tests/libsample/size.cpp @@ -0,0 +1,11 @@ +// 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 "size.h" + +#include <iostream> + +void Size::show() const +{ + std::cout << "(width: " << m_width << ", height: " << m_height << ")"; +} diff --git a/sources/shiboken6/tests/libsample/size.h b/sources/shiboken6/tests/libsample/size.h new file mode 100644 index 000000000..2d194e96b --- /dev/null +++ b/sources/shiboken6/tests/libsample/size.h @@ -0,0 +1,185 @@ +// 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 SIZE_H +#define SIZE_H + +#include "libsamplemacros.h" + +class LIBSAMPLE_API Size +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(Size) + + explicit Size(double width = 0.0, double height = 0.0) noexcept : + m_width(width), m_height(height) {} + ~Size() = default; + + inline double width() const { return m_width; } + inline void setWidth(double width) { m_width = width; } + inline double height() const { return m_height; } + inline void setHeight(double height) { m_height = height; } + + inline double calculateArea() const { return m_width * m_height; } + + // Comparison Operators + inline bool operator<(const Size &other) + { + return calculateArea() < other.calculateArea(); + } + + inline bool operator>(const Size &other) + { + // On some x86 hardware and compiler combinations, floating point + // comparisons may fail due to a hardware bug. One workaround is to + // simplify comparison expressions by putting partial results in + // variables. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=323#c109 + // for details. + double a = calculateArea(); + double b = other.calculateArea(); + return a > b; + } + + inline bool operator<=(const Size &other) + { + // See comments for operator>() + double a = calculateArea(); + double b = other.calculateArea(); + return a <= b; + } + + inline bool operator>=(const Size &other) + { + return calculateArea() >= other.calculateArea(); + } + + inline bool operator<(double area) { return calculateArea() < area; } + inline bool operator>(double area) { return calculateArea() > area; } + inline bool operator<=(double area) { return calculateArea() <= area; } + inline bool operator>=(double area) { return calculateArea() >= area; } + + // Arithmetic Operators + inline Size &operator+=(const Size &s) + { + m_width += s.m_width; + m_height += s.m_height; + return *this; + } + + inline Size &operator-=(const Size &s) + { + m_width -= s.m_width; + m_height -= s.m_height; + return *this; + } + + inline Size &operator*=(double mult) + { + m_width *= mult; + m_height *= mult; + return *this; + } + + inline Size &operator/=(double div) + { + m_width /= div; + m_height /= div; + return *this; + } + + // TODO: add ++size, size++, --size, size-- + + // External operators + friend inline bool operator==(const Size&, const Size&); + friend inline bool operator!=(const Size&, const Size&); + friend inline Size operator+(const Size&, const Size&); + friend inline Size operator-(const Size&, const Size&); + friend inline Size operator*(const Size&, double); + friend inline Size operator*(double, const Size&); + friend inline Size operator/(const Size&, double); + + friend inline bool operator<(double, const Size&); + friend inline bool operator>(double, const Size&); + friend inline bool operator<=(double, const Size&); + friend inline bool operator>=(double, const Size&); + + void show() const; + +private: + double m_width; + double m_height; +}; + +// Comparison Operators +inline bool operator!=(const Size &s1, const Size &s2) +{ + return s1.m_width != s2.m_width || s1.m_height != s2.m_height; +} + +inline bool operator==(const Size &s1, const Size &s2) +{ + return s1.m_width == s2.m_width && s1.m_height == s2.m_height; +} + +inline bool operator<(double area, const Size &s) +{ + return area < s.calculateArea(); +} + +inline bool operator>(double area, const Size &s) +{ + return area > s.calculateArea(); +} + +inline bool operator<=(double area, const Size &s) +{ + return area <= s.calculateArea(); +} + +inline bool operator>=(double area, const Size &s) +{ + return area >= s.calculateArea(); +} + +// Arithmetic Operators +inline Size operator+(const Size &s1, const Size &s2) +{ + return Size(s1.m_width + s2.m_width, s1.m_height + s2.m_height); +} + +inline Size operator-(const Size &s1, const Size &s2) +{ + return Size(s1.m_width - s2.m_width, s1.m_height - s2.m_height); +} + +inline Size operator*(const Size &s, double mult) +{ + return Size(s.m_width * mult, s.m_height * mult); +} + +inline Size operator*(double mult, const Size &s) +{ + return Size(s.m_width * mult, s.m_height * mult); +} + +inline Size operator/(const Size &s, double div) +{ + return Size(s.m_width / div, s.m_height / div); +} + +using real = double; +using ushort = unsigned short; + +class LIBSAMPLE_API SizeF +{ +public: + explicit SizeF(real width, real height) : m_width(width), m_height(height) {} + real width() const { return m_width; } + real height() const { return m_height; } + static inline ushort passTypedefOfUnsignedShort(ushort value) { return value; } +private: + real m_width; + real m_height; +}; + +#endif // SIZE_H diff --git a/sources/shiboken6/tests/libsample/snakecasetest.cpp b/sources/shiboken6/tests/libsample/snakecasetest.cpp new file mode 100644 index 000000000..8240308b4 --- /dev/null +++ b/sources/shiboken6/tests/libsample/snakecasetest.cpp @@ -0,0 +1,44 @@ +// 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 "snakecasetest.h" + +int SnakeCaseGlobalFunction() +{ + return 42; +} + +SnakeCaseTest::SnakeCaseTest() = default; +SnakeCaseTest::~SnakeCaseTest() = default; + +int SnakeCaseTest::testFunction1() const +{ + return 42; +} + +int SnakeCaseTest::testFunctionDisabled() const +{ + return 42; +} + +int SnakeCaseTest::testFunctionBoth() const +{ + return 42; +} + +int SnakeCaseTest::callVirtualFunc() const +{ + return virtualFunc(); +} + +int SnakeCaseTest::virtualFunc() const +{ + return 42; +} + +SnakeCaseDerivedTest::SnakeCaseDerivedTest() = default; + +int SnakeCaseDerivedTest::virtualFunc() const +{ + return 43; +} diff --git a/sources/shiboken6/tests/libsample/snakecasetest.h b/sources/shiboken6/tests/libsample/snakecasetest.h new file mode 100644 index 000000000..757dd23b2 --- /dev/null +++ b/sources/shiboken6/tests/libsample/snakecasetest.h @@ -0,0 +1,40 @@ +// 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 SNAKECASETEST_H +#define SNAKECASETEST_H + +#include "libsamplemacros.h" + +LIBSAMPLE_API int SnakeCaseGlobalFunction(); + +class LIBSAMPLE_API SnakeCaseTest +{ +public: + SnakeCaseTest(); + virtual ~SnakeCaseTest(); + + int testFunction1() const; + int testFunctionDisabled() const; + int testFunctionBoth() const; + + int callVirtualFunc() const; + + int testField = 42; + int testFieldDisabled = 42; + int testFieldBoth = 42; + +protected: + virtual int virtualFunc() const; +}; + +class LIBSAMPLE_API SnakeCaseDerivedTest : public SnakeCaseTest +{ +public: + SnakeCaseDerivedTest(); + +protected: + int virtualFunc() const override; +}; + +#endif // SNAKECASETEST_H diff --git a/sources/shiboken6/tests/libsample/sometime.cpp b/sources/shiboken6/tests/libsample/sometime.cpp new file mode 100644 index 000000000..ad9a0d81c --- /dev/null +++ b/sources/shiboken6/tests/libsample/sometime.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 "sometime.h" + +#include <cstdio> + +void Time::setTime() +{ + m_hour = 0; + m_minute = 0; + m_second = 0; + m_msec = 0; + m_is_null = true; +} + +void Time::setTime(int h, int m, int s, int ms) +{ + m_hour = h; + m_minute = m; + m_second = s; + m_msec = ms; + m_is_null = false; +} + +Time::NumArgs Time::somethingCompletelyDifferent() +{ + return ZeroArgs; +} + +Time::NumArgs Time::somethingCompletelyDifferent(int, int, ImplicitConv ic, ObjectType *type) +{ + if (type) + return FourArgs; + if (ic.ctorEnum() == ImplicitConv::CtorThree && ic.objId() == -1) + return TwoArgs; + return ThreeArgs; +} + +Str Time::toString() const +{ + if (m_is_null) + return Str(); + char buffer[13]; + std::snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d.%03d", + m_hour, m_minute, m_second, m_msec); + return Str(buffer); +} + +bool Time::operator==(const Time &other) const +{ + return m_hour == other.m_hour + && m_minute == other.m_minute + && m_second == other.m_second + && m_msec == other.m_msec + && m_is_null == other.m_is_null; +} + +bool Time::operator!=(const Time &other) const +{ + return !operator==(other); +} + +Time::operator Str() const +{ + return Time::toString(); +} diff --git a/sources/shiboken6/tests/libsample/sometime.h b/sources/shiboken6/tests/libsample/sometime.h new file mode 100644 index 000000000..575d4b136 --- /dev/null +++ b/sources/shiboken6/tests/libsample/sometime.h @@ -0,0 +1,66 @@ +// 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 SOMETIME_H +#define SOMETIME_H + +#include "libsamplemacros.h" +#include "str.h" +#include "implicitconv.h" +#include "objecttype.h" + +class LIBSAMPLE_API Time +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(Time) + + enum NumArgs { + ZeroArgs, + TwoArgs, + ThreeArgs, + FourArgs + }; + + Time() noexcept = default; + explicit Time(int h, int m, int s = 0, int ms = 0) noexcept: + m_hour(h), m_minute(m), m_second(s), m_msec(ms), m_is_null(false) + {} + + ~Time() = default; + + inline bool isNull() const { return m_is_null; } + + inline int hour() const { return m_hour; } + inline int minute() const { return m_minute; } + inline int second() const { return m_second; } + inline int msec() const { return m_msec; } + + void setTime(); + void setTime(int h, int m, int s = 0, int ms = 0); + + // This one is completely different from the other methods in this class, + // it was added to give the overload decisor a really hard time with + // an value-type with implicit conversion and a default argument, and also + // an object-type, just because I feel like it. + NumArgs somethingCompletelyDifferent(); + NumArgs somethingCompletelyDifferent(int h, int m, + ImplicitConv ic = ImplicitConv::CtorThree, + ObjectType *type = nullptr); + + Str toString() const; + bool operator==(const Time &other) const; + bool operator!=(const Time &other) const; + + // This cast operator must become an implicit conversion of Str. + operator Str() const; + +private: + int m_hour = 0; + int m_minute = 0; + int m_second = 0; + int m_msec = 0; + + bool m_is_null = true; +}; + +#endif // SOMETIME_H diff --git a/sources/shiboken6/tests/libsample/stdcomplex.cpp b/sources/shiboken6/tests/libsample/stdcomplex.cpp new file mode 100644 index 000000000..847174387 --- /dev/null +++ b/sources/shiboken6/tests/libsample/stdcomplex.cpp @@ -0,0 +1,32 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "stdcomplex.h" + +#include <iostream> + +StdComplex::StdComplex() noexcept = default; + +StdComplex::StdComplex(double re, double img) noexcept : m_impl(re, img) +{ +} + +StdComplex::operator int() const +{ + return std::lround(abs_value()); +} + +StdComplex::StdComplex(const Impl &impl) noexcept : m_impl(impl) +{ +} + +StdComplex StdComplex::pow(const StdComplex &exp) const +{ + return StdComplex(std::pow(m_impl, exp.m_impl)); +} + +std::ostream &operator<<(std::ostream &str, const StdComplex &c) +{ + str << "Complex(" << c.real() << ", " << c.imag() << ')'; + return str; +} diff --git a/sources/shiboken6/tests/libsample/stdcomplex.h b/sources/shiboken6/tests/libsample/stdcomplex.h new file mode 100644 index 000000000..b39b80612 --- /dev/null +++ b/sources/shiboken6/tests/libsample/stdcomplex.h @@ -0,0 +1,55 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef STDCOMPLEX_H +#define STDCOMPLEX_H + +#include "libsamplemacros.h" + +#include <complex> +#include <iosfwd> + +// A complex number based on std::complex for exercising esoteric number +// protocols (Py_nb_). For standard number protocols, see Point. + +class LIBSAMPLE_API StdComplex +{ + using Impl = std::complex<double>; + +public: + StdComplex() noexcept; + explicit StdComplex(double re, double img) noexcept; + + double real() const { return m_impl.real(); } + double imag() const { return m_impl.imag(); } + + double abs_value() const { return std::abs(m_impl); } // abs() is reserved Python word + + StdComplex pow(const StdComplex &exp) const; + + operator double() const { return abs_value(); } + operator int() const; + + friend inline bool operator==(const StdComplex &c1, const StdComplex &c2) noexcept + { return c1.m_impl == c2.m_impl; } + friend inline bool operator!=(const StdComplex &c1, const StdComplex &c2) noexcept + { return c1.m_impl != c2.m_impl; } + + friend inline StdComplex operator+(const StdComplex &c1, const StdComplex &c2) noexcept + { return StdComplex(c1.m_impl + c2.m_impl); } + friend inline StdComplex operator-(const StdComplex &c1, const StdComplex &c2) noexcept + { return StdComplex(c1.m_impl - c2.m_impl); } + friend inline StdComplex operator*(const StdComplex &c1, const StdComplex &c2) noexcept + { return StdComplex(c1.m_impl * c2.m_impl); } + friend inline StdComplex operator/(const StdComplex &c1, const StdComplex &c2) noexcept + { return StdComplex(c1.m_impl / c2.m_impl); } + +private: + explicit StdComplex(const Impl &impl) noexcept; + + Impl m_impl; +}; + +std::ostream &operator<<(std::ostream &str, const StdComplex &c); + +#endif // STDCOMPLEX_H diff --git a/sources/shiboken6/tests/libsample/str.cpp b/sources/shiboken6/tests/libsample/str.cpp new file mode 100644 index 000000000..742c0bb01 --- /dev/null +++ b/sources/shiboken6/tests/libsample/str.cpp @@ -0,0 +1,137 @@ +// 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 "str.h" + +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <sstream> + +Str::Str(char c) +{ + char str[2] = { c, 0 }; + init(str); +} + +Str::Str(const char *cstr) +{ + init(cstr); +} + +void Str::init(const char *cstr) +{ + if (cstr) + m_str = cstr; +} + +Str Str::arg(const Str &s) const +{ + size_t idx = m_str.find_first_of("%VAR"); + if (idx == std::string::npos) + return *this; + + std::string result = m_str; + result.replace(idx, 4, s.m_str); + return result.c_str(); +} + +Str &Str::append(const Str &s) +{ + m_str += s.m_str; + return *this; +} + +Str &Str::prepend(const Str &s) +{ + m_str = s.m_str + m_str; + return *this; +} + +const char *Str::cstring() const +{ + return m_str.c_str(); +} + +int Str::toInt(bool *ok, int base) const +{ + int result = 0; + std::istringstream conv(m_str); + switch (base) { + case 8: + conv >> std::oct >> result; + break; + case 10: + conv >> std::dec >> result; + break; + case 16: + conv >> std::hex >> result; + break; + } + const bool my_ok = std::istringstream::eofbit & conv.rdstate(); + if (!my_ok) + result = 0; + if (ok) + *ok = my_ok; + return result; +} + +void Str::show() const +{ + std::printf("%s", cstring()); +} + +char Str::get_char(int pos) const +{ + return m_str[pos]; +} + +bool Str::set_char(int pos, char ch) +{ + m_str[pos] = ch; + return true; +} + +Str Str::operator+(int number) const +{ + std::ostringstream in; + in << m_str << number; + return in.str().c_str(); +} + +bool Str::operator==(const Str &other) const +{ + return m_str == other.m_str; +} + +Str operator+(int number, const Str &str) +{ + std::ostringstream in; + in << number << str.m_str; + return in.str().c_str(); +} + +bool Str::operator<(const Str &other) const +{ + return m_str < other.m_str; +} + +unsigned int strHash(const Str &str) +{ + unsigned int result = 0; + for (char c : str.m_str) + result = 5U * result + unsigned(c); + return result; +} + +void changePStr(PStr *pstr, const char *suffix) +{ + pstr->append(suffix); +} + +void duplicatePStr(PStr *pstr) +{ + if (!pstr) + return; + pstr->append(*pstr); +} diff --git a/sources/shiboken6/tests/libsample/str.h b/sources/shiboken6/tests/libsample/str.h new file mode 100644 index 000000000..6b3386cef --- /dev/null +++ b/sources/shiboken6/tests/libsample/str.h @@ -0,0 +1,52 @@ +// 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 STR_H +#define STR_H + +#include "libsamplemacros.h" + +#include <string> + +class LIBSAMPLE_API Str +{ +public: + Str(char c); + Str(const char *cstr = ""); + + Str arg(const Str &s) const; + + Str &append(const Str &s); + Str &prepend(const Str &s); + + const char *cstring() const; + char get_char(int pos) const; + bool set_char(int pos, char ch); + + int toInt(bool *ok = nullptr, int base = 10) const; + + void show() const; + + inline int size() const { return int(m_str.size()); } + + // nonsense operator just to test reverse operators + Str operator+(int number) const; + bool operator==(const Str &other) const; + bool operator<(const Str &other) const; + +private: + void init(const char *cstr); + std::string m_str; + + friend LIBSAMPLE_API Str operator+(int number, const Str &str); + friend LIBSAMPLE_API unsigned int strHash(const Str &str); +}; + +LIBSAMPLE_API Str operator+(int number, const Str &str); +LIBSAMPLE_API unsigned int strHash(const Str &str); + +using PStr = Str; +LIBSAMPLE_API void changePStr(PStr *pstr, const char *suffix); +LIBSAMPLE_API void duplicatePStr(PStr *pstr = nullptr); + +#endif // STR_H diff --git a/sources/shiboken6/tests/libsample/strlist.cpp b/sources/shiboken6/tests/libsample/strlist.cpp new file mode 100644 index 000000000..5840a0516 --- /dev/null +++ b/sources/shiboken6/tests/libsample/strlist.cpp @@ -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 + +#include "strlist.h" + +#include <algorithm> + +bool StrList::operator==(const std::list<Str> &other) const +{ + return size() == other.size() + && std::equal(begin(), end(), other.begin()); +} + +Str StrList::join(const Str &sep) const +{ + Str result; + const auto i1 = begin(); + const auto i2 = end(); + for (auto it = i1; i1 != i2; ++it) { + if (it != i1) + result.append(sep); + result.append(*it); + } + return result; +} diff --git a/sources/shiboken6/tests/libsample/strlist.h b/sources/shiboken6/tests/libsample/strlist.h new file mode 100644 index 000000000..01865a5b4 --- /dev/null +++ b/sources/shiboken6/tests/libsample/strlist.h @@ -0,0 +1,49 @@ +// 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 STRLIST_H +#define STRLIST_H + +#include "libsamplemacros.h" +#include "str.h" + +#include <list> + +class LIBSAMPLE_API StrList : public std::list<Str> +{ +public: + enum CtorEnum { + NoParamsCtor, + StrCtor, + CopyCtor, + ListOfStrCtor + }; + + inline StrList() = default; + inline StrList(const std::list<Str> &lst) : + std::list<Str>(lst), m_ctorUsed(ListOfStrCtor) {} + inline explicit StrList(const Str &str) : + m_ctorUsed(StrCtor) { push_back(str); } + inline StrList(const StrList &lst) : + std::list<Str>(lst), m_ctorUsed(CopyCtor) {} + + StrList(StrList &&) = default; + StrList &operator=(const StrList &) = default; + StrList &operator=(StrList &&) = default; + ~StrList() = default; + + inline void append(const Str &str) { push_back(str); } + Str join(const Str &sep) const; + + bool operator==(const std::list<Str> &other) const; + inline bool operator!=(const std::list<Str> &other) const { return !(*this == other); } + + CtorEnum constructorUsed() const { return m_ctorUsed; } + +private: + CtorEnum m_ctorUsed = NoParamsCtor; +}; + +using PStrList = StrList; + +#endif // STRLIST_H diff --git a/sources/shiboken6/tests/libsample/templateptr.cpp b/sources/shiboken6/tests/libsample/templateptr.cpp new file mode 100644 index 000000000..a73f78417 --- /dev/null +++ b/sources/shiboken6/tests/libsample/templateptr.cpp @@ -0,0 +1,8 @@ +// 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 "templateptr.h" + +void TemplatePtr::dummy(std::list<std::pair<BlackBox *, BlackBox *> > &) +{ +} diff --git a/sources/shiboken6/tests/libsample/templateptr.h b/sources/shiboken6/tests/libsample/templateptr.h new file mode 100644 index 000000000..bf230c363 --- /dev/null +++ b/sources/shiboken6/tests/libsample/templateptr.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 TEMPLATEPTR_H +#define TEMPLATEPTR_H + +#include "libsamplemacros.h" +#include "blackbox.h" + +#include <utility> +#include <list> + +class LIBSAMPLE_API TemplatePtr +{ +public: + void dummy(std::list<std::pair<BlackBox *, BlackBox *> > &items); +}; + +#endif // TEMPLATEPTR_H diff --git a/sources/shiboken6/tests/libsample/transform.cpp b/sources/shiboken6/tests/libsample/transform.cpp new file mode 100644 index 000000000..5ccf5d1ed --- /dev/null +++ b/sources/shiboken6/tests/libsample/transform.cpp @@ -0,0 +1,28 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2013 Kitware, Inc. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "transform.h" + +#include <cmath> + +Point applyHomogeneousTransform(const Point &in, + double m11, double m12, double m13, + double m21, double m22, double m23, + double m31, double m32, double m33, + bool *okay) +{ + double x = m11 * in.x() + m12 * in.y() + m13; + double y = m21 * in.x() + m22 * in.y() + m23; + double w = m31 * in.x() + m32 * in.y() + m33; + + if (std::isfinite(w) && fabs(w) > 1e-10) { + if (okay) + *okay = true; + return {x / w, y / w}; + } + + if (okay) + *okay = false; + return {}; +} diff --git a/sources/shiboken6/tests/libsample/transform.h b/sources/shiboken6/tests/libsample/transform.h new file mode 100644 index 000000000..34ebf40d3 --- /dev/null +++ b/sources/shiboken6/tests/libsample/transform.h @@ -0,0 +1,18 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// Copyright (C) 2013 Kitware, Inc. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef TRANSFORM_H +#define TRANSFORM_H + +#include "point.h" + +#include "libsamplemacros.h" + +LIBSAMPLE_API Point applyHomogeneousTransform(const Point &in, + double m11, double m12, double m13, + double m21, double m22, double m23, + double m31, double m32, double m33, + bool *okay); + +#endif // TRANSFORM_H diff --git a/sources/shiboken6/tests/libsample/typesystypedef.cpp b/sources/shiboken6/tests/libsample/typesystypedef.cpp new file mode 100644 index 000000000..d9c9a92fc --- /dev/null +++ b/sources/shiboken6/tests/libsample/typesystypedef.cpp @@ -0,0 +1,12 @@ +// 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 "typesystypedef.h" + +ValueWithUnitUser::ValueWithUnitUser() = default; + +ValueWithUnit<double, LengthUnit::Millimeter> + ValueWithUnitUser::doubleInchToMillimeter(ValueWithUnit<double, LengthUnit::Inch> v) +{ + return ValueWithUnit<double, LengthUnit::Millimeter>(v.value() * 254); +} diff --git a/sources/shiboken6/tests/libsample/typesystypedef.h b/sources/shiboken6/tests/libsample/typesystypedef.h new file mode 100644 index 000000000..be42fbefe --- /dev/null +++ b/sources/shiboken6/tests/libsample/typesystypedef.h @@ -0,0 +1,32 @@ +// 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 TYPESYSTYPEDEF_H +#define TYPESYSTYPEDEF_H + +#include "libsamplemacros.h" + +enum class LengthUnit { Millimeter, Inch }; + +template <class T, LengthUnit Unit> +class ValueWithUnit +{ + public: + explicit ValueWithUnit(T value = {}) : m_value(value) {} + + T value() const { return m_value; } + void setValue(const T &value) { m_value = value; } + +private: + T m_value; +}; + +class LIBSAMPLE_API ValueWithUnitUser +{ +public: + ValueWithUnitUser(); + + static ValueWithUnit<double, LengthUnit::Millimeter> doubleInchToMillimeter(ValueWithUnit<double, LengthUnit::Inch>); +}; + +#endif // TYPESYSTYPEDEF_H diff --git a/sources/shiboken6/tests/libsample/valueandvirtual.h b/sources/shiboken6/tests/libsample/valueandvirtual.h new file mode 100644 index 000000000..799e11e40 --- /dev/null +++ b/sources/shiboken6/tests/libsample/valueandvirtual.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 VALUEANDVIRTUAL_H +#define VALUEANDVIRTUAL_H + +#include "libsamplemacros.h" + +class ValueAndVirtual +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(ValueAndVirtual) + + explicit ValueAndVirtual(int id) noexcept : m_id(id) {} + virtual ~ValueAndVirtual() = default; + + bool operator()(int id, int id2) { return id == id2; } + + inline int id() const { return m_id; } + +private: + int m_id; +}; + +#endif // VALUEANDVIRTUAL_H diff --git a/sources/shiboken6/tests/libsample/virtualmethods.cpp b/sources/shiboken6/tests/libsample/virtualmethods.cpp new file mode 100644 index 000000000..515564664 --- /dev/null +++ b/sources/shiboken6/tests/libsample/virtualmethods.cpp @@ -0,0 +1,66 @@ +// 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 "virtualmethods.h" + +int VirtualDtor::dtor_called = 0; + +double VirtualMethods::virtualMethod0(Point pt, int val, Complex cpx, bool b) +{ + return (pt.x() * pt.y() * val) + cpx.imag() + ((int) b); +} + +bool VirtualMethods::createStr(const char *text, Str *&ret) +{ + if (!text) { + ret = nullptr; + return false; + } + + ret = new Str(text); + return true; +} + +void VirtualMethods::getMargins(int *left, int *top, int *right, int *bottom) const +{ + *left = m_left; + *top = m_top; + *right = m_right; + *bottom = m_bottom; +} + +int VirtualMethods::recursionOnModifiedVirtual(Str) const +{ + return 0; +} + +const Str & VirtualMethods::returnConstRef() const +{ + static const Str result; + return result; +} + +int VirtualMethods::stringViewLength(std::string_view in) const +{ + return int(in.size()); +} + +double VirtualDaughter2::virtualMethod0(Point pt, int val, Complex cpx, bool b) +{ + return 42 + VirtualMethods::virtualMethod0(pt, val, cpx, b); +} + +int VirtualDaughter2::sum0(int a0, int a1, int a2) +{ + return 42 + VirtualMethods::sum0(a0, a1, a2); +} + +double VirtualFinalDaughter::virtualMethod0(Point pt, int val, Complex cpx, bool b) +{ + return 42 + VirtualMethods::virtualMethod0(pt, val, cpx, b); +} + +int VirtualFinalDaughter::sum0(int a0, int a1, int a2) +{ + return 42 + VirtualMethods::sum0(a0, a1, a2); +} diff --git a/sources/shiboken6/tests/libsample/virtualmethods.h b/sources/shiboken6/tests/libsample/virtualmethods.h new file mode 100644 index 000000000..b7172ad0d --- /dev/null +++ b/sources/shiboken6/tests/libsample/virtualmethods.h @@ -0,0 +1,145 @@ +// 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 VIRTUALMETHODS_H +#define VIRTUALMETHODS_H + +#include "point.h" +#include "complex.h" +#include "str.h" + +#include "libsamplemacros.h" +#include "strlist.h" + +#include <string_view> +#include <string> + +class LIBSAMPLE_API VirtualMethods +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(VirtualMethods) + + explicit VirtualMethods(Str name = "VirtualMethods") : m_name(name) {} + virtual ~VirtualMethods() = default; + + virtual double virtualMethod0(Point pt, int val, Complex cpx, bool b); + double callVirtualMethod0(Point pt, int val, Complex cpx, bool b) + { + return virtualMethod0(pt, val, cpx, b); + } + + // Binding modification: rename. + virtual int sum0(int a0, int a1, int a2) { return a0 + a1 + a2; } + int callSum0(int a0, int a1, int a2) { return sum0(a0, a1, a2); } + + // Binding modification: set default value for the last argument. + virtual int sum1(int a0, int a1, int a2) { return a0 + a1 + a2; } + int callSum1(int a0, int a1, int a2) { return sum1(a0, a1, a2); } + + // Binding modification: remove the last argument and set a default value for it. + virtual int sum2(int a0, int a1, int a2) { return a0 + a1 + a2; } + int callSum2(int a0, int a1, int a2) { return sum2(a0, a1, a2); } + + // Binding modification: remove the second argument. + virtual int sum3(int a0, int a1, int a2) { return a0 + a1 + a2; } + int callSum3(int a0, int a1, int a2) { return sum3(a0, a1, a2); } + + // Binding modification: remove the second argument and set its default + // value, then inject code on the binding reimplementation of the virtual + // (with a native inject-code) to sum the value of the removed + // argument to the first argument before the method is called. + virtual int sum4(int a0, int a1, int a2) { return a0 + a1 + a2; } + int callSum4(int a0, int a1, int a2) { return sum4(a0, a1, a2); } + + // Binding modification: prepend a string to the results of a Python override. + virtual Str name() { return m_name; } + Str callName() { return name(); } + + // Binding modification: code injection that calls the Python override by itself. + virtual void callMe() {} + void callCallMe() { callMe(); } + + // Passing reference to pointers. + virtual bool createStr(const char *text, Str *&ret); + bool callCreateStr(const char *text, Str *&ret) { return createStr(text, ret); } + + // Return a non-binded method + std::list<Str> callStrListToStdList(const StrList &strList) + { return strListToStdList(strList); } + virtual std::list<Str> strListToStdList(const StrList &strList ) + { return strList; } + + void setMargins(int left, int top, int right, int bottom) + { + m_left = left; + m_top = top; + m_right = right; + m_bottom = bottom; + } + virtual void getMargins(int *left, int *top, int *right, int *bottom) const; + void callGetMargins(int *left, int *top, int *right, int *bottom) const + { + getMargins(left, top, right, bottom); + } + + virtual int recursionOnModifiedVirtual(Str arg) const; + int callRecursionOnModifiedVirtual(Str arg) const { return recursionOnModifiedVirtual(arg); } + + virtual const Str &returnConstRef() const; + + virtual int stringViewLength(std::string_view in) const; + +protected: + // PYSIDE-1388: Protected hack with final classes (see VirtualFinalDaughter). + void protectedMethod() {} + +private: + Str m_name; + int m_left = 0; + int m_top = 0; + int m_right = 0; + int m_bottom = 0; +}; + +class LIBSAMPLE_API VirtualDaughter : public VirtualMethods +{ +public: + VirtualDaughter() : VirtualMethods() {} + VirtualDaughter(Str name) : VirtualMethods(name) {} +}; + +class LIBSAMPLE_API VirtualDaughter2 : public VirtualMethods +{ +public: + VirtualDaughter2() : VirtualMethods("VirtualDaughter2") {} + + double virtualMethod0(Point pt, int val, Complex cpx, bool b) override; + int sum0(int a0, int a1, int a2) final; +}; + +class LIBSAMPLE_API VirtualFinalDaughter final : public VirtualMethods +{ +public: + VirtualFinalDaughter() : VirtualMethods("VirtualFinalDaughter") {} + + double virtualMethod0(Point pt, int val, Complex cpx, bool b) override; + int sum0(int a0, int a1, int a2) override; +}; + +class LIBSAMPLE_API VirtualDtor +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(VirtualDtor) + + VirtualDtor() noexcept = default; + virtual ~VirtualDtor() { dtor_called++; } + + static VirtualDtor *create() { return new VirtualDtor(); } + static int dtorCalled() { return dtor_called; } + static void resetDtorCounter() { dtor_called = 0; } + +private: + static int dtor_called; +}; + +#endif // VIRTUALMETHODS_H diff --git a/sources/shiboken6/tests/libsample/voidholder.h b/sources/shiboken6/tests/libsample/voidholder.h new file mode 100644 index 000000000..3f0f4d973 --- /dev/null +++ b/sources/shiboken6/tests/libsample/voidholder.h @@ -0,0 +1,32 @@ +// 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 VOIDHOLDER_H +#define VOIDHOLDER_H + +#include "libsamplemacros.h" + +class VoidHolder +{ +public: + LIBMINIMAL_DEFAULT_COPY_MOVE(VoidHolder) + + explicit VoidHolder(void *ptr = nullptr) noexcept : m_ptr(ptr) {} + ~VoidHolder() = default; + + inline void *voidPointer() { return m_ptr; } + inline static void *gimmeMeSomeVoidPointer() + { + static void *pointerToSomething = new VoidHolder(); + return pointerToSomething; + } + void *takeVoidPointer(void *item) + { + return item; + } + +private: + void *m_ptr; +}; + +#endif // VOIDHOLDER_H diff --git a/sources/shiboken6/tests/libsmart/CMakeLists.txt b/sources/shiboken6/tests/libsmart/CMakeLists.txt new file mode 100644 index 000000000..95f0cffd6 --- /dev/null +++ b/sources/shiboken6/tests/libsmart/CMakeLists.txt @@ -0,0 +1,23 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +project(libsmart) + +set(libsmart_SRC +libsmartmacros.h +smart.cpp smart.h +smart_integer.h +smart_obj.h +smart_registry.h +smart_sharedptr.h +smart_test.h +stdoptionaltestbench.cpp stdoptionaltestbench.h +stdsharedptrtestbench.cpp stdsharedptrtestbench.h +stduniqueptrtestbench.cpp stduniqueptrtestbench.h +) + +add_library(libsmart SHARED ${libsmart_SRC}) +target_include_directories(libsmart PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_compile_definitions(libsmart PRIVATE LIBSMART_BUILD) +set_property(TARGET libsmart PROPERTY PREFIX "") + diff --git a/sources/shiboken6/tests/libsmart/libsmartmacros.h b/sources/shiboken6/tests/libsmart/libsmartmacros.h new file mode 100644 index 000000000..c1f229b6c --- /dev/null +++ b/sources/shiboken6/tests/libsmart/libsmartmacros.h @@ -0,0 +1,18 @@ +// 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 LIB_SMART_MACROS_H +#define LIB_SMART_MACROS_H + +#include "../libminimal/libminimalmacros.h" + +#define LIB_SMART_EXPORT LIBMINIMAL_EXPORT +#define LIB_SMART_IMPORT LIBMINIMAL_IMPORT + +#ifdef LIBSMART_BUILD +# define LIB_SMART_API LIB_SMART_EXPORT +#else +# define LIB_SMART_API LIB_SMART_IMPORT +#endif + +#endif // LIB_SMART_MACROS_H diff --git a/sources/shiboken6/tests/libsmart/smart.cpp b/sources/shiboken6/tests/libsmart/smart.cpp new file mode 100644 index 000000000..2273040f9 --- /dev/null +++ b/sources/shiboken6/tests/libsmart/smart.cpp @@ -0,0 +1,272 @@ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "smart.h" + +#include <algorithm> +#include <iostream> + +static inline bool verbose() +{ + return Registry::getInstance()->verbose(); +} + +void SharedPtrBase::logDefaultConstructor(const char *instantiation, const void *t) +{ + if (verbose()) + std::cout << "SharedPtr<" << instantiation << "> default constructor " << t << '\n'; +} + +void SharedPtrBase::logConstructor(const char *instantiation, const void *t, + const void *pointee) +{ + if (verbose()) { + std::cout << "SharedPtr<" << instantiation << "> constructor " + << t << " with pointer " << pointee << '\n'; + } +} + +void SharedPtrBase::logCopyConstructor(const char *instantiation, const void *t, + const void *refData) +{ + if (verbose()) { + std::cout << "SharedPtr<" << instantiation << ">) copy constructor " + << t << " with pointer " << refData << '\n'; + } +} + +void SharedPtrBase::logAssignment(const char *instantiation, const void *t, const void *refData) +{ + if (verbose()) { + std::cout << "SharedPtr<" << instantiation << ">::operator= " << t + << " with pointer " << refData << "\n"; + } +} + +void SharedPtrBase::logDestructor(const char *instantiation, const void *t, + int remainingRefCount) +{ + if (verbose()) { + std::cout << "~SharedPtr<" << instantiation << "> " << t << ", remaining refcount " + << remainingRefCount << '\n'; + } +} + +Obj::Obj() : m_integer(123), m_internalInteger(new Integer) +{ + Registry::getInstance()->add(this); + if (verbose()) + std::cout << "Obj constructor " << this << '\n'; +} + +Obj::~Obj() +{ + Registry::getInstance()->remove(this); + delete m_internalInteger; + if (verbose()) + std::cout << "~Obj " << this << '\n'; +} + + +void Obj::printObj() { + if (verbose()) { + std::cout << "Obj::printObj(): integer value: " << m_integer + << " internal integer value: " << m_internalInteger->value() << '\n'; + } +} + + +SharedPtr<Obj> Obj::createSharedPtrObj() +{ + SharedPtr<Obj> o(new Obj); + return o; +} + +std::vector<SharedPtr<Obj> > Obj::createSharedPtrObjList(int size) +{ + std::vector<SharedPtr<Obj> > r; + for (int i=0; i < size; i++) + r.push_back(createSharedPtrObj()); + return r; +} + + +SharedPtr<Integer> Obj::createSharedPtrInteger() +{ + SharedPtr<Integer> o(new Integer); + return o; +} + +SharedPtr<Smart::Integer2> Obj::createSharedPtrInteger2() +{ + SharedPtr<Smart::Integer2> o(new Smart::Integer2); + return o; +} + +int Obj::takeSharedPtrToObj(SharedPtr<Obj> pObj) +{ + pObj->printObj(); + return pObj->m_integer; +} + +int Obj::takeSharedPtrToInteger(SharedPtr<Integer> pInt) +{ + if (pInt.isNull()) { + std::cout << "SharedPtr<Integer>(nullptr) passed!\n"; + return -1; + } + pInt->printInteger(); + return pInt->value(); +} + +int Obj::takeSharedPtrToIntegerByConstRef(const SharedPtr<Integer> &pInt) +{ + if (pInt.isNull()) { + std::cout << "SharedPtr<Integer>(nullptr) passed!\n"; + return -1; + } + pInt->printInteger(); + return pInt->value(); +} + +SharedPtr<Integer> Obj::createSharedPtrInteger(int value) +{ + auto *i = new Integer; + i->setValue(value); + return SharedPtr<Integer>(i); +} + +SharedPtr<Integer> Obj::createNullSharedPtrInteger() +{ + return {}; +} + +SharedPtr<const Integer> Obj::createSharedPtrConstInteger() +{ + SharedPtr<const Integer> co(new Integer); + return co; +} + +int Obj::takeSharedPtrToConstInteger(SharedPtr<const Integer> pInt) +{ + return pInt->m_int; +} + +Integer Obj::takeInteger(Integer val) +{ + return val; +} + +Integer::Integer() : m_int(456) +{ + Registry::getInstance()->add(this); + if (verbose()) + std::cout << "Integer constructor " << this << '\n'; +} + +Integer::Integer(const Integer &other) +{ + Registry::getInstance()->add(this); + if (verbose()) + std::cout << "Integer copy constructor " << this << '\n'; + m_int = other.m_int; +} + +Integer &Integer::operator=(const Integer &other) +{ + Registry::getInstance()->add(this); + if (verbose()) + std::cout << "Integer operator= " << this << '\n'; + m_int = other.m_int; + return *this; +} + +Integer::~Integer() +{ + Registry::getInstance()->remove(this); + if (verbose()) + std::cout << "~Integer " << this << " (" << m_int << ")\n"; +} + +int Integer::value() const +{ + return m_int; +} + +void Integer::setValue(int v) +{ + m_int = v; + if (verbose()) + std::cout << "Integer::setValue(" << v << ") " << this << '\n'; +} + +int Integer::compare(const Integer &rhs) const +{ + if (m_int < rhs.m_int) + return -1; + return m_int > rhs.m_int ? 1 : 0; +} + +void Integer::printInteger() const +{ + if (verbose()) + std::cout << "Integer value for object " << this << " is " << m_int << '\n'; +} + +Registry *Registry::getInstance() +{ + static Registry registry; + return ®istry; +} + +Registry::Registry() = default; + +Registry::~Registry() = default; + +void Registry::add(Obj *p) +{ + m_objects.push_back(p); +} + +void Registry::add(Integer *p) +{ + m_integers.push_back(p); +} + +void Registry::remove(Obj *p) +{ + m_objects.erase(std::remove(m_objects.begin(), m_objects.end(), p), m_objects.end()); +} + +void Registry::remove(Integer *p) +{ + m_integers.erase(std::remove(m_integers.begin(), m_integers.end(), p), m_integers.end()); +} + +int Registry::countObjects() const +{ + return static_cast<int>(m_objects.size()); +} + +int Registry::countIntegers() const +{ + return static_cast<int>(m_integers.size()); +} + +bool Registry::verbose() const +{ + return m_verbose; +} + +void Registry::setVerbose(bool flag) +{ + m_verbose = flag; +} + +Smart::Integer2::Integer2() + : Integer () +{ +} + +Smart::Integer2::Integer2(const Smart::Integer2 &) = default; +Smart::Integer2 &Smart::Integer2::operator=(const Integer2 &) = default; diff --git a/sources/shiboken6/tests/libsmart/smart.h b/sources/shiboken6/tests/libsmart/smart.h new file mode 100644 index 000000000..1f610b302 --- /dev/null +++ b/sources/shiboken6/tests/libsmart/smart.h @@ -0,0 +1,16 @@ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef SMART_H +#define SMART_H + +#include "smart_sharedptr.h" +#include "smart_integer.h" +#include "smart_obj.h" +#include "smart_registry.h" +#include "smart_test.h" +#include "stdsharedptrtestbench.h" +#include "stdoptionaltestbench.h" +#include "stduniqueptrtestbench.h" + +#endif // SMART_H diff --git a/sources/shiboken6/tests/libsmart/smart_integer.h b/sources/shiboken6/tests/libsmart/smart_integer.h new file mode 100644 index 000000000..42a441a00 --- /dev/null +++ b/sources/shiboken6/tests/libsmart/smart_integer.h @@ -0,0 +1,69 @@ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef SMART_INTEGER_H +#define SMART_INTEGER_H + +#include "libsmartmacros.h" + +class LIB_SMART_API Integer { +public: + Integer(); + Integer(const Integer &other); + Integer &operator=(const Integer &other); + Integer(Integer &&other) noexcept = default; + Integer &operator=(Integer &&other) noexcept = default; + ~Integer(); + void printInteger() const; + + int value() const; + void setValue(int v); + + int compare(const Integer &rhs) const; + + int m_int; // public for testing member field access. +}; + +inline bool operator==(const Integer &lhs, const Integer &rhs) +{ + return lhs.compare(rhs) == 0; +} + +inline bool operator!=(const Integer &lhs, const Integer &rhs) +{ + return lhs.compare(rhs) != 0; +} + +inline bool operator<(const Integer &lhs, const Integer &rhs) +{ + return lhs.compare(rhs) < 0; +} + +inline bool operator<=(const Integer &lhs, const Integer &rhs) +{ + return lhs.compare(rhs) <= 0; +} + +inline bool operator>(const Integer &lhs, const Integer &rhs) +{ + return lhs.compare(rhs) > 0; +} + +inline bool operator>=(const Integer &lhs, const Integer &rhs) +{ + return lhs.compare(rhs) >= 0; +} + +namespace Smart { +class LIB_SMART_API Integer2 : public Integer { +public: + Integer2(); + Integer2(const Integer2 &); + Integer2 &operator=(const Integer2 &); + Integer2(Integer2 &&other) = delete; + Integer2 &operator=(Integer2 &&other) = delete; + ~Integer2() = default; +}; +} // namespace Smart + +#endif // SMART_INTEGER_H diff --git a/sources/shiboken6/tests/libsmart/smart_obj.h b/sources/shiboken6/tests/libsmart/smart_obj.h new file mode 100644 index 000000000..9f4f8425d --- /dev/null +++ b/sources/shiboken6/tests/libsmart/smart_obj.h @@ -0,0 +1,45 @@ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef SMART_OBJ_H +#define SMART_OBJ_H + +#include "libsmartmacros.h" +#include "smart_sharedptr.h" + +#include <vector> + +class Integer; +class Obj; +namespace Smart { class Integer2; } + +// Couldn't name it Object because it caused some namespace clashes. +class LIB_SMART_API Obj { +public: + Obj(); + Obj(const Obj &other) = delete; + Obj &operator=(const Obj &other) = delete; + Obj(Obj &&other) = delete; + Obj &operator=(Obj &&other) = delete; + virtual ~Obj(); + + void printObj(); + Integer takeInteger(Integer val); + static SharedPtr<Obj> createSharedPtrObj(); + std::vector<SharedPtr<Obj> > createSharedPtrObjList(int size); + virtual SharedPtr<Integer> createSharedPtrInteger(); // virtual for PYSIDE-1188 + SharedPtr<const Integer> createSharedPtrConstInteger(); + int takeSharedPtrToConstInteger(SharedPtr<const Integer> pInt); + SharedPtr<Smart::Integer2> createSharedPtrInteger2(); + int takeSharedPtrToObj(SharedPtr<Obj> pObj); + int takeSharedPtrToInteger(SharedPtr<Integer> pInt); + int takeSharedPtrToIntegerByConstRef(const SharedPtr<Integer> &pInt); + + static SharedPtr<Integer> createSharedPtrInteger(int value); + static SharedPtr<Integer> createNullSharedPtrInteger(); + + int m_integer; // public for testing member field access. + Integer *m_internalInteger; +}; + +#endif // SMART_OBJ_H diff --git a/sources/shiboken6/tests/libsmart/smart_registry.h b/sources/shiboken6/tests/libsmart/smart_registry.h new file mode 100644 index 000000000..abf7edc84 --- /dev/null +++ b/sources/shiboken6/tests/libsmart/smart_registry.h @@ -0,0 +1,43 @@ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef SMART_REGISTRY_H +#define SMART_REGISTRY_H + +#include <vector> + +#include "libsmartmacros.h" + +class Obj; +class Integer; + +// Used to track which C++ objects are alive. +class LIB_SMART_API Registry { +public: + static Registry *getInstance(); + ~Registry(); + + Registry(const Registry &) = delete; + Registry &operator=(const Registry &) = delete; + Registry(Registry &&) = delete; + Registry &operator=(Registry &&) = delete; + + void add(Obj *p); + void add(Integer *p); + void remove(Obj *p); + void remove(Integer *p); + int countObjects() const; + int countIntegers() const; + bool verbose() const; + void setVerbose(bool flag); + +protected: + Registry(); + +private: + std::vector<Obj *> m_objects; + std::vector<Integer *> m_integers; + bool m_verbose = false; +}; + +#endif // SMART_REGISTRY_H diff --git a/sources/shiboken6/tests/libsmart/smart_sharedptr.h b/sources/shiboken6/tests/libsmart/smart_sharedptr.h new file mode 100644 index 000000000..dc665810a --- /dev/null +++ b/sources/shiboken6/tests/libsmart/smart_sharedptr.h @@ -0,0 +1,94 @@ +// Copyright (C) 2019 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef SMART_SHARED_PTR_H +#define SMART_SHARED_PTR_H + +#include <memory> + +#include "libsmartmacros.h" + +struct SharedPtrBase +{ + LIB_SMART_API static void logDefaultConstructor(const char *instantiation, const void *t); + LIB_SMART_API static void logConstructor(const char *instantiation, const void *t, const void *pointee); + LIB_SMART_API static void logCopyConstructor(const char *instantiation, const void *t, const void *refData); + LIB_SMART_API static void logAssignment(const char *instantiation, const void *t, const void *refData); + LIB_SMART_API static void logDestructor(const char *instantiation, const void *t, int remainingRefCount); +}; + +template <class T> +class SharedPtr : public SharedPtrBase { +public: + LIBMINIMAL_DEFAULT_MOVE(SharedPtr) + + SharedPtr() { logDefaultConstructor(typeid(T).name(), this); } + + SharedPtr(T *v) : mPtr(v) + { + logConstructor(typeid(T).name(), this, v); + } + + SharedPtr(const SharedPtr<T> &other) : mPtr(other.mPtr) + { + logCopyConstructor(typeid(T).name(), this, data()); + } + + template<class X> + SharedPtr(const SharedPtr<X> &other) : mPtr(other.mPtr) + { + logCopyConstructor(typeid(T).name(), this, data()); + } + + SharedPtr &operator=(const SharedPtr &other) + { + if (this != &other) + mPtr = other.mPtr; + return *this; + } + + T *data() const + { + return mPtr.get(); + } + + int useCount() const + { + return mPtr.use_count(); + } + + void dummyMethod1() + { + } + + bool isNull() const + { + return mPtr.get() == nullptr; + } + + T& operator*() const + { + // Crashes if smart pointer is empty (just like std::shared_ptr). + return *mPtr; + } + + T *operator->() const + { + return mPtr.get(); + } + + bool operator!() const + { + return !mPtr; + } + + ~SharedPtr() + { + if (mPtr.use_count() >= 1) + logDestructor(typeid(T).name(), this, mPtr.use_count() - 1); + } + + std::shared_ptr<T> mPtr; +}; + +#endif // SMART_SHARED_PTR_H diff --git a/sources/shiboken6/tests/libsmart/smart_test.h b/sources/shiboken6/tests/libsmart/smart_test.h new file mode 100644 index 000000000..89d8cbc7c --- /dev/null +++ b/sources/shiboken6/tests/libsmart/smart_test.h @@ -0,0 +1,13 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef SMART_TEST_H +#define SMART_TEST_H + +namespace Test { + +enum DummyEnum { Dummy1, Dummy2 }; + +} + +#endif // SMART_TEST_H diff --git a/sources/shiboken6/tests/libsmart/stdoptionaltestbench.cpp b/sources/shiboken6/tests/libsmart/stdoptionaltestbench.cpp new file mode 100644 index 000000000..69100720c --- /dev/null +++ b/sources/shiboken6/tests/libsmart/stdoptionaltestbench.cpp @@ -0,0 +1,58 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "stdoptionaltestbench.h" + +#include <iostream> + +std::ostream &operator<<(std::ostream &str, const Integer &i) +{ + str << i.value(); + return str; +} + +template <class T> +std::ostream &operator<<(std::ostream &str, const std::optional<T> &o) +{ + if (o.has_value()) + str << o.value(); + else + str << "nullopt"; + return str; +} + +StdOptionalTestBench::StdOptionalTestBench() = default; + +std::optional<int> StdOptionalTestBench::optionalInt() const +{ + return m_optionalInt; +} + +void StdOptionalTestBench::setOptionalInt(const std::optional<int> &i) +{ + std::cout << __FUNCTION__ << ' ' << i << '\n'; + m_optionalInt = i; +} + +void StdOptionalTestBench::setOptionalIntValue(int i) +{ + std::cout << __FUNCTION__ << ' ' << i << '\n'; + m_optionalInt.emplace(i); +} + +std::optional<Integer> StdOptionalTestBench::optionalInteger() const +{ + return m_optionalInteger; +} + +void StdOptionalTestBench::setOptionalInteger(const std::optional<Integer> &s) +{ + std::cout << __FUNCTION__ << ' ' << s << '\n'; + m_optionalInteger = s; +} + +void StdOptionalTestBench::setOptionalIntegerValue(Integer &s) +{ + std::cout << __FUNCTION__ << ' ' << s << '\n'; + m_optionalInteger.emplace(s); +} diff --git a/sources/shiboken6/tests/libsmart/stdoptionaltestbench.h b/sources/shiboken6/tests/libsmart/stdoptionaltestbench.h new file mode 100644 index 000000000..baa709821 --- /dev/null +++ b/sources/shiboken6/tests/libsmart/stdoptionaltestbench.h @@ -0,0 +1,30 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef OPTIONALTEST_H +#define OPTIONALTEST_H + +#include "libsmartmacros.h" +#include "smart_integer.h" + +#include <optional> + +class LIB_SMART_API StdOptionalTestBench +{ +public: + StdOptionalTestBench(); + + std::optional<int> optionalInt() const; + void setOptionalInt(const std::optional<int> &i); + void setOptionalIntValue(int i); + + std::optional<Integer> optionalInteger() const; + void setOptionalInteger(const std::optional<Integer> &s); + void setOptionalIntegerValue(Integer &s); + +private: + std::optional<int> m_optionalInt; + std::optional<Integer> m_optionalInteger; +}; + +#endif // OPTIONALTEST_H diff --git a/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.cpp b/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.cpp new file mode 100644 index 000000000..472f807f2 --- /dev/null +++ b/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.cpp @@ -0,0 +1,106 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "stdsharedptrtestbench.h" +#include "smart_integer.h" + +#include <iostream> + +StdSharedPtrTestBench::StdSharedPtrTestBench() = default; +StdSharedPtrTestBench::~StdSharedPtrTestBench() = default; + +std::shared_ptr<Integer> StdSharedPtrTestBench::createInteger(int v) +{ + auto result = std::make_shared<Integer>(); + result->setValue(v); + return result; +} + +std::shared_ptr<Integer> StdSharedPtrTestBench::createNullInteger() +{ + return {}; +} + +void StdSharedPtrTestBench::printInteger(const std::shared_ptr<Integer> &p) +{ + std::cerr << __FUNCTION__ << ' '; + if (p.get()) + std::cerr << p->value(); + else + std::cerr << "nullptr"; + std::cerr << '\n'; +} + +std::shared_ptr<int> StdSharedPtrTestBench::createInt(int v) +{ + return std::make_shared<int>(v); +} + +std::shared_ptr<int> StdSharedPtrTestBench::createNullInt() +{ + return {}; +} + +void StdSharedPtrTestBench::printInt(const std::shared_ptr<int> &p) +{ + std::cerr << __FUNCTION__ << ' '; + if (p.get()) + std::cerr << *p; + else + std::cerr << "nullptr"; + std::cerr << '\n'; +} + +std::shared_ptr<double> StdSharedPtrTestBench::createDouble(double v) +{ + return std::make_shared<double>(v); +} + +std::shared_ptr<double> StdSharedPtrTestBench::createNullDouble() +{ + return {}; +} + +void StdSharedPtrTestBench::printDouble(const std::shared_ptr<double> &p) +{ + std::cerr << __FUNCTION__ << ' '; + if (p.get()) + std::cerr << *p; + else + std::cerr << "nullptr"; + std::cerr << '\n'; +} + +std::shared_ptr<std::string> StdSharedPtrTestBench::createString(const char *text) +{ + return std::make_shared<std::string>(text); +} + +std::shared_ptr<std::string> StdSharedPtrTestBench::createNullString() +{ + return {}; +} + +void StdSharedPtrTestBench::printString(const std::shared_ptr<std::string> &p) +{ + std::cerr << __FUNCTION__ << ' '; + if (p.get()) + std::cerr << '"' << *p << '"'; + else + std::cerr << "nullptr"; + std::cerr << '\n'; +} + +StdSharedPtrVirtualMethodTester::StdSharedPtrVirtualMethodTester() = default; +StdSharedPtrVirtualMethodTester::~StdSharedPtrVirtualMethodTester() = default; + +std::shared_ptr<Integer> StdSharedPtrVirtualMethodTester::callModifyInteger(const std::shared_ptr<Integer> &p) +{ + return doModifyInteger(p); +} + +std::shared_ptr<Integer> StdSharedPtrVirtualMethodTester::doModifyInteger(std::shared_ptr<Integer> p) +{ + p->setValue(p->value() + 1); + return p; +} diff --git a/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.h b/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.h new file mode 100644 index 000000000..9d4c207b5 --- /dev/null +++ b/sources/shiboken6/tests/libsmart/stdsharedptrtestbench.h @@ -0,0 +1,49 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef STDSHAREDPTRTESTBENCH_H +#define STDSHAREDPTRTESTBENCH_H + +#include "libsmartmacros.h" + +#include <memory> +#include <string> + +class Integer; + +class LIB_SMART_API StdSharedPtrTestBench +{ +public: + StdSharedPtrTestBench(); + ~StdSharedPtrTestBench(); + + static std::shared_ptr<Integer> createInteger(int v = 42); + static std::shared_ptr<Integer> createNullInteger(); + static void printInteger(const std::shared_ptr<Integer> &); + + static std::shared_ptr<int> createInt(int v = 42); + static std::shared_ptr<int> createNullInt(); + static void printInt(const std::shared_ptr<int> &); + + static std::shared_ptr<double> createDouble(double v = 42); + static std::shared_ptr<double> createNullDouble(); + static void printDouble(const std::shared_ptr<double> &); + + static std::shared_ptr<std::string> createString(const char *text); + static std::shared_ptr<std::string> createNullString(); + static void printString(const std::shared_ptr<std::string> &); +}; + +class LIB_SMART_API StdSharedPtrVirtualMethodTester +{ +public: + StdSharedPtrVirtualMethodTester(); + virtual ~StdSharedPtrVirtualMethodTester(); + + std::shared_ptr<Integer> callModifyInteger(const std::shared_ptr<Integer> &p); + +protected: + virtual std::shared_ptr<Integer> doModifyInteger(std::shared_ptr<Integer> p); +}; + +#endif // STDSHAREDPTRTESTBENCH_H diff --git a/sources/shiboken6/tests/libsmart/stduniqueptrtestbench.cpp b/sources/shiboken6/tests/libsmart/stduniqueptrtestbench.cpp new file mode 100644 index 000000000..df4b566fa --- /dev/null +++ b/sources/shiboken6/tests/libsmart/stduniqueptrtestbench.cpp @@ -0,0 +1,133 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "stduniqueptrtestbench.h" +#include "smart_integer.h" + +#include <iostream> + +std::ostream &operator<<(std::ostream &str, const std::unique_ptr<Integer> &p) +{ + str << "unique_ptr<Integer>("; + if (p.get()) + str << p->value(); + else + str << "nullptr"; + str << ')'; + return str; +} + +std::ostream &operator<<(std::ostream &str, const std::unique_ptr<Smart::Integer2> &p) +{ + str << "unique_ptr<Integer>("; + if (p.get()) + str << p->value(); + else + str << "nullptr"; + str << ')'; + return str; +} + +std::ostream &operator<<(std::ostream &str, const std::unique_ptr<int> &p) +{ + str << "unique_ptr<int>("; + if (p.get()) + str << *p; + else + str << "nullptr"; + str << ')'; + return str; +} + +StdUniquePtrTestBench::StdUniquePtrTestBench() = default; +StdUniquePtrTestBench::~StdUniquePtrTestBench() = default; + +std::unique_ptr<Integer> StdUniquePtrTestBench::createInteger(int v) +{ + auto result = std::make_unique<Integer>(); + result->setValue(v); + return result; +} + +std::unique_ptr<Integer> StdUniquePtrTestBench::createNullInteger() +{ + return {}; +} + +void StdUniquePtrTestBench::printInteger(const std::unique_ptr<Integer> &p) +{ + std::cerr << __FUNCTION__ << ' ' << p << '\n'; +} + +void StdUniquePtrTestBench::takeInteger(std::unique_ptr<Integer> p) +{ + std::cerr << __FUNCTION__ << ' ' << p << '\n'; +} + +std::unique_ptr<int> StdUniquePtrTestBench::createInt(int v) +{ + return std::make_unique<int>(v); +} + +std::unique_ptr<int> StdUniquePtrTestBench::createNullInt() +{ + return {}; +} + +void StdUniquePtrTestBench::printInt(const std::unique_ptr<int> &p) +{ + std::cerr << __FUNCTION__ << ' ' << p << '\n'; +} + +void StdUniquePtrTestBench::takeInt(std::unique_ptr<int> p) +{ + std::cerr << __FUNCTION__ << ' ' << p << '\n'; +} + +StdUniquePtrVirtualMethodTester::StdUniquePtrVirtualMethodTester() = default; + +StdUniquePtrVirtualMethodTester::~StdUniquePtrVirtualMethodTester() = default; + +bool StdUniquePtrVirtualMethodTester::testModifyIntegerByRef(int value, int expectedValue) +{ + auto p = std::make_unique<Integer>(); + p->setValue(value); + const int actualValue = doModifyIntegerByRef(p); + return p.get() != nullptr && actualValue == expectedValue; +} + +bool StdUniquePtrVirtualMethodTester::testModifyIntegerValue(int value, int expectedValue) +{ + auto p = std::make_unique<Integer>(); + p->setValue(value); + const int actualValue = doModifyIntegerByValue(std::move(p)); + return p.get() == nullptr && actualValue == expectedValue; +} + +bool StdUniquePtrVirtualMethodTester::testCreateInteger(int value, int expectedValue) +{ + auto p = doCreateInteger(value); + return p.get() != nullptr && p->value() == expectedValue; +} + +std::unique_ptr<Integer> StdUniquePtrVirtualMethodTester::doCreateInteger(int v) +{ + auto result = std::make_unique<Integer>(); + result->setValue(v); + return result; +} + +int StdUniquePtrVirtualMethodTester::doModifyIntegerByRef(const std::unique_ptr<Integer> &p) +{ + return p->value() + 1; +} + +int StdUniquePtrVirtualMethodTester::doModifyIntegerByValue(std::unique_ptr<Integer> p) +{ + return p->value() + 1; +} + +void StdUniquePtrTestBench::printInteger2(const std::unique_ptr<Smart::Integer2> &p) +{ + std::cerr << __FUNCTION__ << ' ' << p << '\n'; +} diff --git a/sources/shiboken6/tests/libsmart/stduniqueptrtestbench.h b/sources/shiboken6/tests/libsmart/stduniqueptrtestbench.h new file mode 100644 index 000000000..868c6d08c --- /dev/null +++ b/sources/shiboken6/tests/libsmart/stduniqueptrtestbench.h @@ -0,0 +1,50 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#ifndef STDUNIQUEPTRTESTBENCH_H +#define STDUNIQUEPTRTESTBENCH_H + +#include "libsmartmacros.h" + +#include <memory> + +class Integer; +namespace Smart { +class Integer2; +} + +class LIB_SMART_API StdUniquePtrTestBench +{ +public: + StdUniquePtrTestBench(); + ~StdUniquePtrTestBench(); + + static std::unique_ptr<Integer> createInteger(int v = 42); + static std::unique_ptr<Integer> createNullInteger(); + static void printInteger2(const std::unique_ptr<Smart::Integer2> &p); + static void printInteger(const std::unique_ptr<Integer> &p); + static void takeInteger(std::unique_ptr<Integer> p); // Call with std::move() + + static std::unique_ptr<int> createInt(int v = 42); + static std::unique_ptr<int> createNullInt(); + static void printInt(const std::unique_ptr<int> &p); + static void takeInt(std::unique_ptr<int> p); // Call with std::move() +}; + +class LIB_SMART_API StdUniquePtrVirtualMethodTester +{ +public: + StdUniquePtrVirtualMethodTester(); + virtual ~StdUniquePtrVirtualMethodTester(); + + bool testModifyIntegerByRef(int value, int expectedValue); + bool testModifyIntegerValue(int value, int expectedValue); + bool testCreateInteger(int value, int expectedValue); + +protected: + virtual std::unique_ptr<Integer> doCreateInteger(int v); + virtual int doModifyIntegerByRef(const std::unique_ptr<Integer> &p); + virtual int doModifyIntegerByValue(std::unique_ptr<Integer> p); +}; + +#endif // STDUNIQUEPTRTESTBENCH_H diff --git a/sources/shiboken6/tests/minimalbinding/CMakeLists.txt b/sources/shiboken6/tests/minimalbinding/CMakeLists.txt new file mode 100644 index 000000000..7f132bd34 --- /dev/null +++ b/sources/shiboken6/tests/minimalbinding/CMakeLists.txt @@ -0,0 +1,47 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +project(minimal) + +set(minimal_TYPESYSTEM +${CMAKE_CURRENT_SOURCE_DIR}/typesystem_minimal.xml +) + +set(minimal_SRC +${CMAKE_CURRENT_BINARY_DIR}/minimal/minimal_module_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/minimal/containeruser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/minimal/obj_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/minimal/val_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/minimal/listuser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/minimal/spanuser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/minimal/minbooluser_wrapper.cpp +) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/minimal-binding.txt.in" + "${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt" @ONLY) + +shiboken_get_tool_shell_wrapper(shiboken tool_wrapper) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" + BYPRODUCTS ${minimal_SRC} + COMMAND + ${tool_wrapper} + $<TARGET_FILE:Shiboken6::shiboken6> + --project-file=${CMAKE_CURRENT_BINARY_DIR}/minimal-binding.txt + ${GENERATOR_EXTRA_FLAGS} + DEPENDS ${minimal_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h Shiboken6::shiboken6 + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Running generator for 'minimal' test binding..." +) + +add_library(minimal MODULE ${minimal_SRC}) +target_include_directories(minimal PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(minimal PUBLIC libminimal libshiboken) +set_property(TARGET minimal PROPERTY PREFIX "") +set_property(TARGET minimal PROPERTY OUTPUT_NAME "minimal${PYTHON_EXTENSION_SUFFIX}") +if(WIN32) + set_property(TARGET minimal PROPERTY SUFFIX ".pyd") +endif() + +create_generator_target(minimal) diff --git a/sources/shiboken6/tests/minimalbinding/brace_pattern_test.py b/sources/shiboken6/tests/minimalbinding/brace_pattern_test.py new file mode 100644 index 000000000..946a869db --- /dev/null +++ b/sources/shiboken6/tests/minimalbinding/brace_pattern_test.py @@ -0,0 +1,87 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +import os +import re +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from shiboken6 import Shiboken # noqa: F401 + +from shibokensupport.signature.lib.tool import build_brace_pattern + +""" +This test tests the brace pattern from signature.lib.tool +against a slower reference implementation. +The pattern is crucial, because it is used heavily in signature.parser . +""" + + +def check(s): + """A slow reference parser for braces and strings""" + open, close = "[{(<", "]})>" + escape, quote = "\\", '"' + instring = blind = False + stack = [] + for c in s: + if instring: + if blind: + blind = False + elif c == escape: + blind = True + elif c == quote: + instring = False + stack.pop() + continue + if c in open: + stack.append(c) + elif c in close: + pos = close.index(c) + if len(stack) > 0 and open[pos] == stack[len(stack) - 1]: + stack.pop() + else: + return False + elif c == escape: + return False + elif c == quote: + instring = True + stack.append(c) + return len(stack) == 0 + + +class TestBracePattern(unittest.TestCase): + tests = [ + (r'{[]{()}}', True), + (r'[{}{})(]', False), + (r'[{}{} ")(" ]', True), + (r'[{}{} ")(\" ]', False), + (r'[{}{} ")(\" ]"]', True), + (r'a < b ( c [ d { "} \"\"}" } ] ) >', True), + (r'a < b ( c [ d { } ] ) >', True), + (r'a < b ( c [ d { "huh" } ] ) >', True), + (r'a < b ( c [ d { "huh\" \" \\\"" } ] ) >', True), + ] + + def test_checkfunc(self): + for test, result in self.tests: + if result: + self.assertTrue(check(test)) + else: + self.assertFalse(check(test)) + + def test_the_brace_pattern(self): + func = re.compile(build_brace_pattern(5, ",") + "$", re.VERBOSE).match + for test, result in self.tests: + if result: + self.assertTrue(func(test)) + else: + self.assertFalse(func(test)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/minimalbinding/containeruser_test.py b/sources/shiboken6/tests/minimalbinding/containeruser_test.py new file mode 100644 index 000000000..25d683957 --- /dev/null +++ b/sources/shiboken6/tests/minimalbinding/containeruser_test.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from minimal import ContainerUser + + +class ContainerTest(unittest.TestCase): + """Simple test for converting std::vector and using an opaque container. + For advanced tests, see ListUser.""" + def testVectorConversion(self): + v = ContainerUser.createIntVector(4) + self.assertEqual(ContainerUser.sumIntVector(v), 6) + + def testVectorOpaqueContainer(self): + cu = ContainerUser() + oc = cu.intVector() + self.assertEqual(oc[0], 1) + oc[0] = 42 + self.assertEqual(cu.intVector()[0], 42) + + def testArrayConversion(self): + v = ContainerUser.createIntArray() + self.assertEqual(ContainerUser.sumIntArray(v), 6) + + def testArrayOpaqueContainer(self): + cu = ContainerUser() + oc = cu.intArray() + self.assertEqual(oc[0], 1) + oc[0] = 42 + self.assertEqual(cu.intArray()[0], 42) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/minimalbinding/global.h b/sources/shiboken6/tests/minimalbinding/global.h new file mode 100644 index 000000000..fc5c59a26 --- /dev/null +++ b/sources/shiboken6/tests/minimalbinding/global.h @@ -0,0 +1,10 @@ +// 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 "obj.h" +#include "containeruser.h" +#include "val.h" +#include "minbool.h" +#include "listuser.h" +#include "spanuser.h" +#include "typedef.h" diff --git a/sources/shiboken6/tests/minimalbinding/listuser_test.py b/sources/shiboken6/tests/minimalbinding/listuser_test.py new file mode 100644 index 000000000..b30bb653a --- /dev/null +++ b/sources/shiboken6/tests/minimalbinding/listuser_test.py @@ -0,0 +1,376 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +from functools import reduce +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from minimal import ListUser, Val, Obj, StdIntList + + +class ExtListUser(ListUser): + def __init__(self): + super().__init__() + self._stdIntList = StdIntList() + self._stdIntList.append(1) + self._stdIntList.append(2) + + def createIntList(self, num): + return list(range(0, num * 2, 2)) + + def sumIntList(self, intList): + return sum(intList) * 2 + + def createMinBoolList(self, mb1, mb2): + return [not mb1, not mb2] + + def oredMinBoolList(self, minBoolList): + return not reduce(lambda a, b: a | b, minBoolList) + + def createValList(self, num): + return [Val(i) for i in range(0, num * 2, 2)] + + def sumValList(self, valList): + return sum([val.valId() for val in valList]) * 2 + + def createObjList(self, o1, o2): + o1.setObjId(o1.objId() * 2) + o2.setObjId(o2.objId() * 2) + return [o1, o2] + + def sumObjList(self, objList): + return sum([obj.objId() for obj in objList]) * 2 + + def createListOfIntLists(self, num): + return [self.createIntList(num)] * 4 + + def sumListOfIntLists(self, intListList): + return sum([sum(line) for line in intListList]) * 2 + + def returnIntListByPtr(self): + return self._stdIntList + + +class IntListConversionTest(unittest.TestCase): + + def testCreateIntList(self): + num = 4 + lu = ListUser() + lst = lu.createIntList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), int) + self.assertEqual(lst, list(range(num))) + lst = lu.callCreateIntList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), int) + self.assertEqual(lst, list(range(num))) + + def testCreateIntListFromExtendedClass(self): + lu = ExtListUser() + num = 4 + lst = lu.createIntList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), int) + self.assertEqual(lst, list(range(0, num * 2, 2))) + lst = lu.callCreateIntList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), int) + self.assertEqual(lst, list(range(0, num * 2, 2))) + + def testSumIntList(self): + lu = ListUser() + lst = range(4) + expected = sum(lst) + self.assertEqual(lu.sumIntList(lst), expected) + self.assertEqual(lu.callSumIntList(lst), expected) + self.assertEqual(lu.sumIntListDefaultParam(lst), expected) + self.assertEqual(lu.sumIntListDefaultParamConstRef(lst), expected) + # PYSIDE-2454: Check container default parameters (1,2,3) + self.assertEqual(lu.sumIntListDefaultParam(), 6) + self.assertEqual(lu.sumIntListDefaultParamConstRef(), 6) + + def testSumIntListFromExtendedClass(self): + lu = ExtListUser() + lst = range(4) + self.assertEqual(lu.sumIntList(lst), sum(lst) * 2) + self.assertEqual(lu.callSumIntList(lst), sum(lst) * 2) + + +class MinBoolListConversionTest(unittest.TestCase): + + def testCreateMinBoolList(self): + lu = ListUser() + lst = lu.createMinBoolList(True, False) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), bool) + self.assertEqual(lst, [True, False]) + + lst = lu.callCreateMinBoolList(False, True) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), bool) + self.assertEqual(lst, [False, True]) + + def testCreateMinBoolListFromExtendedClass(self): + lu = ExtListUser() + lst = lu.createMinBoolList(True, False) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), bool) + self.assertEqual(lst, [False, True]) + + lst = lu.callCreateMinBoolList(False, True) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), bool) + self.assertEqual(lst, [True, False]) + + def testOredMinBoolList(self): + lu = ListUser() + lst = [False, False, True] + self.assertTrue(lu.oredMinBoolList(lst)) + self.assertTrue(lu.callOredMinBoolList(lst)) + lst = [False, False, False] + self.assertFalse(lu.oredMinBoolList(lst)) + self.assertFalse(lu.callOredMinBoolList(lst)) + + def testOredMinBoolListFromExtendedClass(self): + lu = ExtListUser() + lst = [False, False, True] + self.assertFalse(lu.oredMinBoolList(lst)) + self.assertFalse(lu.callOredMinBoolList(lst)) + lst = [False, False, False] + self.assertTrue(lu.oredMinBoolList(lst)) + self.assertTrue(lu.callOredMinBoolList(lst)) + + +class ValListConversionTest(unittest.TestCase): + + def testCreateValList(self): + num = 4 + lu = ListUser() + lst = lu.createValList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), Val) + self.assertEqual([val.valId() for val in lst], list(range(num))) + lst = lu.callCreateValList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), Val) + self.assertEqual([val.valId() for val in lst], list(range(num))) + + def testCreateValListFromExtendedClass(self): + lu = ExtListUser() + num = 4 + lst = lu.createValList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), Val) + self.assertEqual([val.valId() for val in lst], list(range(0, num * 2, 2))) + lst = lu.callCreateValList(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), Val) + self.assertEqual([val.valId() for val in lst], list(range(0, num * 2, 2))) + + def testSumValList(self): + lu = ListUser() + lst = [Val(i) for i in range(4)] + self.assertEqual(lu.sumValList(lst), sum([val.valId() for val in lst])) + self.assertEqual(lu.callSumValList(lst), sum([val.valId() for val in lst])) + + def testSumValListFromExtendedClass(self): + lu = ExtListUser() + lst = [Val(i) for i in range(4)] + self.assertEqual(lu.sumValList(lst), sum([val.valId() for val in lst]) * 2) + self.assertEqual(lu.callSumValList(lst), sum([val.valId() for val in lst]) * 2) + + +class ObjListConversionTest(unittest.TestCase): + + def testCreateObjList(self): + o1 = Obj(1) + o2 = Obj(2) + lu = ListUser() + lst = lu.createObjList(o1, o2) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), Obj) + self.assertEqual(lst, [o1, o2]) + self.assertEqual([obj.objId() for obj in lst], [1, 2]) + + lst = lu.callCreateObjList(o1, o2) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), Obj) + self.assertEqual(lst, [o1, o2]) + self.assertEqual([obj.objId() for obj in lst], [1, 2]) + + def testCreateObjListFromExtendedClass(self): + o1 = Obj(1) + o2 = Obj(2) + lu = ExtListUser() + lst = lu.createObjList(o1, o2) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), Obj) + self.assertEqual(lst, [o1, o2]) + self.assertEqual([obj.objId() for obj in lst], [2, 4]) + + lst = lu.callCreateObjList(o1, o2) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), 2) + for i in lst: + self.assertEqual(type(i), Obj) + self.assertEqual(lst, [o1, o2]) + self.assertEqual([obj.objId() for obj in lst], [4, 8]) + + def testSumObjList(self): + lu = ListUser() + lst = [Obj(i) for i in list(range(4))] + self.assertEqual(lu.sumObjList(lst), sum([obj.objId() for obj in lst])) + self.assertEqual(lu.callSumObjList(lst), sum([obj.objId() for obj in lst])) + + def testSumObjListFromExtendedClass(self): + lu = ExtListUser() + lst = [Obj(i) for i in list(range(4))] + self.assertEqual(lu.sumObjList(lst), sum([obj.objId() for obj in lst]) * 2) + self.assertEqual(lu.callSumObjList(lst), sum([obj.objId() for obj in lst]) * 2) + + +class ListOfIntListConversionTest(unittest.TestCase): + + def testCreateListOfIntLists(self): + num = 4 + lu = ListUser() + lst = lu.createListOfIntLists(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), list) + self.assertEqual(i, list(range(num))) + for j in i: + self.assertEqual(type(j), int) + self.assertEqual(lst, [list(range(num))] * 4) + + def testCreateListOfIntListsFromExtendedClass(self): + num = 4 + lu = ExtListUser() + lst = lu.createListOfIntLists(num) + self.assertEqual(type(lst), list) + self.assertEqual(len(lst), num) + for i in lst: + self.assertEqual(type(i), list) + self.assertEqual(i, list(range(0, num * 2, 2))) + for j in i: + self.assertEqual(type(j), int) + self.assertEqual(lst, [list(range(0, num * 2, 2))] * 4) + + def testSumListIntLists(self): + lu = ListUser() + lst = [range(4)] * 4 + self.assertEqual(lu.sumListOfIntLists(lst), sum([sum(line) for line in [range(4)] * 4])) + self.assertEqual(lu.callSumListOfIntLists(lst), sum([sum(line) for line in [range(4)] * 4])) + + def testSumListOfIntListsFromExtendedClass(self): + lu = ExtListUser() + lst = [range(4)] * 4 + self.assertEqual(lu.sumListOfIntLists(lst), + sum([sum(line) for line in [range(4)] * 4]) * 2) + self.assertEqual(lu.callSumListOfIntLists(lst), + sum([sum(line) for line in [range(4)] * 4]) * 2) + + def testOpaqueContainer(self): + lu = ListUser() + + # Set via Python + python_list = [1, 2] + lu.setStdIntList(python_list) + self.assertEqual(len(lu.m_stdIntList), 2) + self.assertEqual(lu.m_stdIntList[0], 1) + self.assertEqual(lu.m_stdIntList[1], 2) + + # Set via C++ + cpp_list = StdIntList() + cpp_list.append(3) + cpp_list.append(4) + lu.setStdIntList(cpp_list) + self.assertEqual(len(lu.m_stdIntList), 2) + self.assertEqual(lu.m_stdIntList[0], 3) + self.assertEqual(lu.m_stdIntList[1], 4) + + # Access field directly via reference + lu.m_stdIntList.append(5) + self.assertEqual(len(lu.m_stdIntList), 3) + self.assertEqual(lu.m_stdIntList[2], 5) + + # Access list via getter + il = lu.getIntList() + il.append(6) + self.assertEqual(len(lu.m_stdIntList), 4) + self.assertEqual(lu.m_stdIntList[3], 6) + + # Access a const list via getter and verify that it cannot be modified + const_l = lu.getConstIntList() + self.assertEqual(len(const_l), 4) + self.assertRaises(TypeError, const_l.append, 6) + + def testListByPtrOpaque(self): + """Test a function taking C++ list by pointer for which an opaque + container exists.""" + lu = ListUser() + python_list = [1, 2] + self.assertEqual(lu.modifyIntListPtr(python_list), 2) + + # Pass an opaque container and verify whether it is modified by C++ + cpp_list = StdIntList() + cpp_list.append(1) + cpp_list.append(2) + self.assertEqual(lu.modifyIntListPtr(cpp_list), 2) + self.assertEqual(len(cpp_list), 3) + + def testListByPtr(self): + """Test a function taking C++ list by pointer for which no opaque + container exists.""" + lu = ListUser() + python_list = [1.1, 22.2] + self.assertEqual(lu.modifyDoubleListPtr(python_list), 2) + + def testReturnListByPtr(self): + """Test that a virtual function returning a list by pointer can be + reimplemented by a Python function returning an opaque container.""" + lu = ExtListUser() + size = lu.callReturnIntListByPtr() # Call virtual from C++ + self.assertEqual(size, 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/minimalbinding/minbool_test.py b/sources/shiboken6/tests/minimalbinding/minbool_test.py new file mode 100644 index 000000000..d9ce0eac0 --- /dev/null +++ b/sources/shiboken6/tests/minimalbinding/minbool_test.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from minimal import MinBoolUser + + +class DerivedMinBoolUser (MinBoolUser): + def returnMyselfVirtual(self): + return MinBoolUser() + + +class MinBoolTest(unittest.TestCase): + + def testMinBoolUser(self): + mbuTrue = MinBoolUser() + mbuFalse = MinBoolUser() + mbuTrue.setMinBool(True) + self.assertFalse(mbuFalse.minBool()) + self.assertTrue(mbuTrue.minBool()) + self.assertFalse(mbuTrue.callInvertedMinBool()) + + self.assertTrue(mbuTrue.minBool()) + self.assertFalse(mbuFalse.minBool()) + self.assertTrue(mbuTrue.minBool() != mbuFalse.minBool()) + + self.assertFalse(mbuFalse.minBool()) + self.assertFalse(mbuFalse.minBool()) + self.assertTrue(mbuTrue.minBool() != mbuFalse.minBool()) + + def testVirtuals(self): + dmbu = DerivedMinBoolUser() + self.assertEqual(dmbu.invertedMinBool(), True) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/minimalbinding/minimal-binding.txt.in b/sources/shiboken6/tests/minimalbinding/minimal-binding.txt.in new file mode 100644 index 000000000..101567070 --- /dev/null +++ b/sources/shiboken6/tests/minimalbinding/minimal-binding.txt.in @@ -0,0 +1,16 @@ +[generator-project] + +generator-set = shiboken + +header-file = @CMAKE_CURRENT_SOURCE_DIR@/global.h +typesystem-file = @minimal_TYPESYSTEM@ + +output-directory = @CMAKE_CURRENT_BINARY_DIR@ + +include-path = @libminimal_SOURCE_DIR@ + +typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@ + +enable-parent-ctor-heuristic +use-isnull-as-nb_nonzero +lean-headers diff --git a/sources/shiboken6/tests/minimalbinding/minimalbinding.pyproject b/sources/shiboken6/tests/minimalbinding/minimalbinding.pyproject new file mode 100644 index 000000000..ab19dc443 --- /dev/null +++ b/sources/shiboken6/tests/minimalbinding/minimalbinding.pyproject @@ -0,0 +1,10 @@ +{ + "files": ["brace_pattern_test.py", + "containeruser_test.py", + "listuser_test.py", + "minbool_test.py", + "obj_test.py", + "typedef_test.py", + "val_test.py", + "typesystem_minimal.xml"] +} diff --git a/sources/shiboken6/tests/minimalbinding/obj_test.py b/sources/shiboken6/tests/minimalbinding/obj_test.py new file mode 100644 index 000000000..e873845de --- /dev/null +++ b/sources/shiboken6/tests/minimalbinding/obj_test.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from minimal import Obj + + +class ExtObj(Obj): + def __init__(self, objId): + Obj.__init__(self, objId) + self.virtual_method_called = False + + def virtualMethod(self, val): + self.virtual_method_called = True + return not Obj.virtualMethod(self, val) + + def passObjectType(self, obj): + obj.setObjId(obj.objId() + 1) + return obj + + def passObjectTypeReference(self, obj): + obj.setObjId(obj.objId() + 1) + return obj + + +class ObjTest(unittest.TestCase): + + def testNormalMethod(self): + objId = 123 + obj = Obj(objId) + self.assertEqual(obj.objId(), objId) + + def testNormalMethodFromExtendedClass(self): + objId = 123 + obj = ExtObj(objId) + self.assertEqual(obj.objId(), objId) + + def testVirtualMethod(self): + obj = Obj(0) + even_number = 8 + self.assertEqual(obj.virtualMethod(even_number), obj.callVirtualMethod(even_number)) + + def testVirtualMethodFromExtendedClass(self): + obj = ExtObj(0) + even_number = 8 + self.assertEqual(obj.virtualMethod(even_number), obj.callVirtualMethod(even_number)) + self.assertTrue(obj.virtual_method_called) + + def testPassObjectType(self): + obj = Obj(0) + self.assertEqual(obj, obj.passObjectType(obj)) + self.assertEqual(obj, obj.callPassObjectType(obj)) + + def testPassObjectTypeNone(self): + obj = Obj(0) + self.assertEqual(None, obj.passObjectType(None)) + self.assertEqual(None, obj.callPassObjectType(None)) + + def testPassObjectTypeReference(self): + obj = Obj(0) + self.assertEqual(obj, obj.passObjectTypeReference(obj)) + self.assertEqual(obj, obj.callPassObjectTypeReference(obj)) + + def testPassObjectTypeFromExtendedClass(self): + obj = ExtObj(0) + self.assertEqual(obj.objId(), 0) + sameObj = obj.passObjectType(obj) + self.assertEqual(obj, sameObj) + self.assertEqual(sameObj.objId(), 1) + sameObj = obj.callPassObjectType(obj) + self.assertEqual(obj, sameObj) + self.assertEqual(sameObj.objId(), 2) + + def testPassObjectTypeReferenceFromExtendedClass(self): + obj = ExtObj(0) + self.assertEqual(obj.objId(), 0) + sameObj = obj.passObjectTypeReference(obj) + self.assertEqual(obj, sameObj) + self.assertEqual(sameObj.objId(), 1) + sameObj = obj.callPassObjectTypeReference(obj) + self.assertEqual(obj, sameObj) + self.assertEqual(sameObj.objId(), 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/minimalbinding/spanuser_test.py b/sources/shiboken6/tests/minimalbinding/spanuser_test.py new file mode 100644 index 000000000..6db6aa616 --- /dev/null +++ b/sources/shiboken6/tests/minimalbinding/spanuser_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from minimal import SpanUser + + +class IntSpanTest(unittest.TestCase): + + def testCreateIntSpan(self): + if not SpanUser.enabled(): + return + expected = [1, 2, 3] + self.assertEqual(SpanUser.getIntSpan3(), expected) + self.assertEqual(SpanUser.getIntSpan(), expected) + self.assertEqual(SpanUser.getConstIntSpan3(), expected) + + self.assertEqual(SpanUser.sumIntSpan3(expected), 6) + self.assertEqual(SpanUser.sumIntSpan(expected), 6) + self.assertEqual(SpanUser.sumConstIntSpan3(expected), 6) + + def testSpanOpaqueContainer(self): + if not SpanUser.enabled(): + return + oc = SpanUser.getIntSpan3_OpaqueContainer() # 1,2,3 + oc[1] = 10 + oc = SpanUser.getIntSpan3_OpaqueContainer() + # note: This converts to std::vector + self.assertEqual(SpanUser.sumIntSpan3(oc), 14) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/minimalbinding/typedef_test.py b/sources/shiboken6/tests/minimalbinding/typedef_test.py new file mode 100644 index 000000000..c2fc8fc12 --- /dev/null +++ b/sources/shiboken6/tests/minimalbinding/typedef_test.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from minimal import (arrayFunc, arrayFuncInt, arrayFuncIntReturn, + arrayFuncIntReturnTypedef, arrayFuncIntTypedef, + arrayFuncReturn, arrayFuncReturnTypedef, arrayFuncTypedef) + +try: + import numpy as np +except ImportError as e: + print(e) + np = None + + +class TypedefTest(unittest.TestCase): + + def setUp(self): + self.the_size = 8 + + def test_arrayFuncInt(self): + none = () + full = range(self.the_size) + self.assertTrue(arrayFuncInt(none), "None is empty, arrayFuncInt should return true") + self.assertFalse(arrayFuncInt(full), "Full is NOT empty, arrayFuncInt should return false") + + self.assertTrue(arrayFuncInt(np.array(none)), + "None is empty, arrayFuncInt should return true") + self.assertFalse(arrayFuncInt(np.array(full)), + "Full is NOT empty, arrayFuncInt should return false") + + def test_arrayFuncIntTypedef(self): + none = () + full = (1, 2, 3) + self.assertTrue(arrayFuncIntTypedef(none), + "None is empty, arrayFuncIntTypedef should return true") + self.assertFalse(arrayFuncIntTypedef(full), + "Full is NOT empty, arrayFuncIntTypedef should return false") + + self.assertTrue(arrayFuncIntTypedef(np.array(none)), + "None is empty, arrayFuncIntTypedef should return true") + self.assertFalse(arrayFuncIntTypedef(np.array(full)), + "Full is NOT empty, arrayFuncIntTypedef should return false") + + def test_arrayFuncIntReturn(self): + none = arrayFuncIntReturn(0) + full = arrayFuncIntReturn(self.the_size) + self.assertTrue((len(none) == 0), "none should be empty") + self.assertTrue((len(full) == self.the_size), + f"full should have {self.the_size} elements") + + def test_arrayFuncIntReturnTypedef(self): + none = arrayFuncIntReturnTypedef(0) + full = arrayFuncIntReturnTypedef(self.the_size) + self.assertTrue((len(none) == 0), "none should be empty") + self.assertTrue((len(full) == self.the_size), + f"full should have {self.the_size} elements") + + def test_arrayFunc(self): + none = () + full = range(self.the_size) + self.assertTrue(arrayFunc(none), "None is empty, arrayFunc should return true") + self.assertFalse(arrayFunc(full), "Full is NOT empty, arrayFunc should return false") + + self.assertTrue(arrayFunc(np.array(none)), "None is empty, arrayFunc should return true") + self.assertFalse(arrayFunc(np.array(full)), + "Full is NOT empty, arrayFunc should return false") + + def test_arrayFuncTypedef(self): + none = () + full = (1, 2, 3) + self.assertTrue(arrayFuncTypedef(none), + "None is empty, arrayFuncTypedef should return true") + self.assertFalse(arrayFuncTypedef(full), + "Full is NOT empty, arrayFuncTypedef should return false") + + self.assertTrue(arrayFuncTypedef(np.array(none)), + "None is empty, arrayFuncTypedef should return true") + self.assertFalse(arrayFuncTypedef(np.array(full)), + "Full is NOT empty, arrayFuncTypedef should return false") + + def test_arrayFuncReturn(self): + none = arrayFuncReturn(0) + full = arrayFuncReturn(self.the_size) + self.assertTrue((len(none) == 0), "none should be empty") + self.assertTrue((len(full) == self.the_size), + f"full should have {self.the_size} elements") + + def test_arrayFuncReturnTypedef(self): + none = arrayFuncReturnTypedef(0) + full = arrayFuncReturnTypedef(self.the_size) + self.assertTrue((len(none) == 0), "none should be empty") + self.assertTrue((len(full) == self.the_size), + f"full should have {self.the_size} elements") + + +if __name__ == '__main__': + if np is not None: + unittest.main() diff --git a/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml b/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml new file mode 100644 index 000000000..e18bf8686 --- /dev/null +++ b/sources/shiboken6/tests/minimalbinding/typesystem_minimal.xml @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="UTF-8"?> +<typesystem package="minimal"> + + <primitive-type name="MinBool" target-lang-api-name="PyBool" default-constructor="MinBool(false)"> + <include file-name="minbool.h" location="global"/> + <conversion-rule> + <native-to-target> + return PyBool_FromLong(%in.value()); + </native-to-target> + <target-to-native> + <add-conversion type="PyBool" check="PyBool_Check(%in)"> + %out = %OUTTYPE(%in == Py_True); + </add-conversion> + </target-to-native> + </conversion-rule> + </primitive-type> + + <opaque-container name="std::list" opaque-containers="int:StdIntList"/> + + <opaque-container name="std::vector" opaque-containers="int:StdIntVector"/> + + <opaque-container name="std::array" opaque-containers="int,3:StdIntArray"/> + + <?if c++20?> <!-- FIXME PYSIDE 7: Remove "if" --> + <opaque-container name="std::span" opaque-containers="int,3:StdIntSpan3"/> + <?endif?> + + <object-type name="Obj"/> + <value-type name="Val"> + <enum-type name="ValEnum"/> + </value-type> + <value-type name="ListUser"> + <modify-field name="m_stdIntList" opaque-container="yes"/> + <modify-function signature="getIntList()"> + <modify-argument index="return"> + <replace-type modified-type="StdIntList"/> + </modify-argument> + </modify-function> + <modify-function signature="getConstIntList()const"> + <modify-argument index="return"> + <replace-type modified-type="StdIntList"/> + </modify-argument> + </modify-function> + </value-type> + + <value-type name="SpanUser"> + <?if c++20?> <!-- FIXME PYSIDE 7: Remove "if" --> + <modify-function signature="getIntSpan3_OpaqueContainer()"> + <modify-argument index="return"> + <replace-type modified-type="StdIntSpan3"/> + </modify-argument> + </modify-function> + <?endif?> + </value-type> + + <value-type name="MinBoolUser"/> + + <value-type name="ContainerUser"> + <modify-function signature="intVector()"> + <modify-argument index="return"> + <replace-type modified-type="StdIntVector"/> + </modify-argument> + </modify-function> + <modify-function signature="intArray()"> + <modify-argument index="return"> + <replace-type modified-type="StdIntArray"/> + </modify-argument> + </modify-function> + </value-type> + + <!-- Test wrapping of a typedef --> + <function signature="arrayFuncInt(std::vector<int>)" /> + <!-- Note manual expansion of the typedef --> + <function signature="arrayFuncIntTypedef(std::vector<int>)" /> + + <function signature="arrayFuncIntReturn(int)" /> + <function signature="arrayFuncIntReturnTypedef(int)" /> + + <!-- Test wrapping of a typedef of a typedef --> + <function signature="arrayFunc(std::vector<int>)" /> + <!-- Note manual expansion of the typedef --> + <function signature="arrayFuncTypedef(std::vector<int>)" /> + + <function signature="arrayFuncReturn(int)" /> + <function signature="arrayFuncReturnTypedef(int)" /> +</typesystem> diff --git a/sources/shiboken6/tests/minimalbinding/val_test.py b/sources/shiboken6/tests/minimalbinding/val_test.py new file mode 100644 index 000000000..b8225a247 --- /dev/null +++ b/sources/shiboken6/tests/minimalbinding/val_test.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from minimal import Val + + +class ExtVal(Val): + def __init__(self, valId): + Val.__init__(self, valId) + + def passValueType(self, val): + return ExtVal(val.valId() + 1) + + def passValueTypePointer(self, val): + val.setValId(val.valId() + 1) + return val + + def passValueTypeReference(self, val): + val.setValId(val.valId() + 1) + return val + + +class ValTest(unittest.TestCase): + + def testNormalMethod(self): + valId = 123 + val = Val(valId) + self.assertEqual(val.valId(), valId) + + def testPassValueType(self): + val = Val(123) + val1 = val.passValueType(val) + self.assertNotEqual(val, val1) + self.assertEqual(val1.valId(), 123) + val2 = val.callPassValueType(val) + self.assertNotEqual(val, val2) + self.assertEqual(val2.valId(), 123) + + def testPassValueTypePointer(self): + val = Val(0) + self.assertEqual(val, val.passValueTypePointer(val)) + self.assertEqual(val, val.callPassValueTypePointer(val)) + + def testPassValueTypeReference(self): + val = Val(0) + self.assertEqual(val, val.passValueTypeReference(val)) + self.assertEqual(val, val.callPassValueTypeReference(val)) + + def testPassAndReceiveEnumValue(self): + val = Val(0) + self.assertEqual(val.oneOrTheOtherEnumValue(Val.One), Val.Other) + self.assertEqual(val.oneOrTheOtherEnumValue(Val.Other), Val.One) + + def testPassValueTypeFromExtendedClass(self): + val = ExtVal(0) + val1 = val.passValueType(val) + self.assertNotEqual(val, val1) + self.assertEqual(val1.valId(), val.valId() + 1) + val2 = val.callPassValueType(val) + self.assertNotEqual(val, val2) + self.assertEqual(val2.valId(), val.valId() + 1) + + def testPassValueTypePointerFromExtendedClass(self): + val = ExtVal(0) + self.assertEqual(val.valId(), 0) + sameVal = val.passValueTypePointer(val) + self.assertEqual(val, sameVal) + self.assertEqual(sameVal.valId(), 1) + sameVal = val.callPassValueTypePointer(val) + self.assertEqual(val, sameVal) + self.assertEqual(sameVal.valId(), 2) + + def testPassValueTypeReferenceFromExtendedClass(self): + val = ExtVal(0) + self.assertEqual(val.valId(), 0) + sameVal = val.passValueTypeReference(val) + self.assertEqual(val, sameVal) + self.assertEqual(sameVal.valId(), 1) + sameVal = val.callPassValueTypeReference(val) + self.assertEqual(val, sameVal) + self.assertEqual(sameVal.valId(), 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/CMakeLists.txt b/sources/shiboken6/tests/otherbinding/CMakeLists.txt new file mode 100644 index 000000000..2172593d3 --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/CMakeLists.txt @@ -0,0 +1,58 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +project(other) + +set(other_TYPESYSTEM +${CMAKE_CURRENT_SOURCE_DIR}/typesystem_other.xml +) + +set(other_SRC +${CMAKE_CURRENT_BINARY_DIR}/other/extendsnoimplicitconversion_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/number_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/otherderived_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/othermultiplederived_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/otherobjecttype_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/othervaluewithunituser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/sharedptr_str_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/smartptrtester_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/other_module_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/valuewithunitintinch_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/other/valuewithunitintmillimeter_wrapper.cpp +) + + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/other-binding.txt.in" + "${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt" @ONLY) + +shiboken_get_tool_shell_wrapper(shiboken tool_wrapper) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" + BYPRODUCTS ${other_SRC} + COMMAND + ${tool_wrapper} + $<TARGET_FILE:Shiboken6::shiboken6> + --project-file=${CMAKE_CURRENT_BINARY_DIR}/other-binding.txt + ${GENERATOR_EXTRA_FLAGS} + DEPENDS ${other_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h Shiboken6::shiboken6 + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Running generator for 'other' test binding..." +) + +add_library(other MODULE ${other_SRC}) +target_include_directories(other PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} + ${sample_BINARY_DIR}/sample + ${smart_BINARY_DIR}/smart) +target_link_libraries(other PUBLIC libother libsample libsmart libshiboken) +set_property(TARGET other PROPERTY PREFIX "") +set_property(TARGET other PROPERTY OUTPUT_NAME "other${PYTHON_EXTENSION_SUFFIX}") + +if(WIN32) + set_property(TARGET other PROPERTY SUFFIX ".pyd") +endif() + + +add_dependencies(other sample smart) +create_generator_target(other) + diff --git a/sources/shiboken6/tests/otherbinding/collector_external_operator_test.py b/sources/shiboken6/tests/otherbinding/collector_external_operator_test.py new file mode 100644 index 000000000..2ba21653d --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/collector_external_operator_test.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for Collector shift operators defined in other modules.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Collector, ObjectType +from other import OtherObjectType + + +class CollectorOtherObjectType(unittest.TestCase): + '''Test cases for Collector << OtherObjectType''' + + def testLShiftWithExpectedType(self): + '''Collector << ObjectType # libsample << operator''' + collector = Collector() + obj = ObjectType() + collector << obj + self.assertEqual(collector.items()[0], obj.identifier()) + + def testOtherReversal(self): + '''Collector << OtherObjectType # libother << operator''' + collector = Collector() + obj = OtherObjectType() + collector << obj + self.assertEqual(collector.items()[0], obj.identifier() * 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/conversion_operator_for_class_without_implicit_conversions_test.py b/sources/shiboken6/tests/otherbinding/conversion_operator_for_class_without_implicit_conversions_test.py new file mode 100644 index 000000000..bd00b5892 --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/conversion_operator_for_class_without_implicit_conversions_test.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests calling NoImplicitConversion using a ExtendsNoImplicitConversion parameter, + being that the latter defines a new conversion operator for the former, and this one + has no implicit conversions.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import NoImplicitConversion +from other import ExtendsNoImplicitConversion + + +class ConversionOperatorForClassWithoutImplicitConversionsTest(unittest.TestCase): + '''Tests calling NoImplicitConversion constructor using a + ExtendsNoImplicitConversion parameter.''' + + def testNoImplicitConversion(self): + '''Basic test to see if the NoImplicitConversion is Ok.''' + obj = NoImplicitConversion(123) + # NoImplicitConversion.receivesNoImplicitConversionByValue(NoImplicitConversion) + self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByValue(obj)) + # NoImplicitConversion.receivesNoImplicitConversionByPointer(NoImplicitConversion*) + self.assertEqual(obj.objId(), + NoImplicitConversion.receivesNoImplicitConversionByPointer(obj)) + # NoImplicitConversion.receivesNoImplicitConversionByReference(NoImplicitConversion&) + self.assertEqual(obj.objId(), + NoImplicitConversion.receivesNoImplicitConversionByReference(obj)) + + def testPassingExtendsNoImplicitConversionAsNoImplicitConversionByValue(self): + '''Gives an ExtendsNoImplicitConversion object to a function expecting a + NoImplicitConversion, passing by value.''' + obj = ExtendsNoImplicitConversion(123) + self.assertEqual(obj.objId(), NoImplicitConversion.receivesNoImplicitConversionByValue(obj)) + + def testPassingExtendsNoImplicitConversionAsNoImplicitConversionByReference(self): + '''Gives an ExtendsNoImplicitConversion object to a function expecting a + NoImplicitConversion, passing by reference.''' + obj = ExtendsNoImplicitConversion(123) + self.assertEqual(obj.objId(), + NoImplicitConversion.receivesNoImplicitConversionByReference(obj)) + + def testPassingExtendsNoImplicitConversionAsNoImplicitConversionByPointer(self): + '''Gives an ExtendsNoImplicitConversion object to a function expecting + a NoImplicitConversion, passing by pointer. This should not be + accepted, since pointers should not be converted.''' + obj = ExtendsNoImplicitConversion(123) + self.assertRaises(TypeError, + NoImplicitConversion.receivesNoImplicitConversionByPointer, obj) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/extended_multiply_operator_test.py b/sources/shiboken6/tests/otherbinding/extended_multiply_operator_test.py new file mode 100644 index 000000000..abbef6231 --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/extended_multiply_operator_test.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for libsample's Point multiply operator defined in libother module.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Point +from other import Number + + +class PointOperationsWithNumber(unittest.TestCase): + '''Test cases for libsample's Point multiply operator defined in libother module.''' + + def testPointTimesInt(self): + '''sample.Point * int''' + pt1 = Point(2, 7) + num = 3 + pt2 = Point(pt1.x() * num, pt1.y() * num) + self.assertEqual(pt1 * num, pt2) + + def testIntTimesPoint(self): + '''int * sample.Point''' + pt1 = Point(2, 7) + num = 3 + pt2 = Point(pt1.x() * num, pt1.y() * num) + self.assertEqual(num * pt1, pt2) + + def testPointTimesNumber(self): + '''sample.Point * other.Number''' + pt = Point(2, 7) + num = Number(11) + self.assertEqual(pt * num.value(), pt * 11) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/global.h b/sources/shiboken6/tests/otherbinding/global.h new file mode 100644 index 000000000..af796734a --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/global.h @@ -0,0 +1,11 @@ +// 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 "../samplebinding/global.h" +#include "extendsnoimplicitconversion.h" +#include "number.h" +#include "otherderived.h" +#include "otherobjecttype.h" +#include "othermultiplederived.h" +#include "othertypesystypedef.h" +#include "smartptrtester.h" diff --git a/sources/shiboken6/tests/otherbinding/module_reload_test.py b/sources/shiboken6/tests/otherbinding/module_reload_test.py new file mode 100644 index 000000000..bde2f5236 --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/module_reload_test.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +from importlib import reload +import os +import shutil +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + + +orig_path = Path(__file__).parent +workdir = Path.cwd() +src = orig_path / 'test_module_template.py' +dst = workdir / 'test_module.py' +shutil.copyfile(src, dst) +sys.path.append(os.fspath(workdir)) + + +class TestModuleReloading(unittest.TestCase): + + def testModuleReloading(self): + '''Test module reloading with on-the-fly modifications.''' + import test_module + for i in range(3): + oldObject = test_module.obj + self.assertTrue(oldObject is test_module.obj) + reload(test_module) + self.assertFalse(oldObject is test_module.obj) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/new_ctor_operator_test.py b/sources/shiboken6/tests/otherbinding/new_ctor_operator_test.py new file mode 100644 index 000000000..d6c356436 --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/new_ctor_operator_test.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests calling Str constructor using a Number parameter, being that number defines + a cast operator to Str.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Str +from other import Number + + +class NewCtorOperatorTest(unittest.TestCase): + '''Tests calling Str constructor using a Number parameter, being that number + defines a cast operator to Str.''' + + def testNumber(self): + '''Basic test to see if the Number class is Ok.''' + value = 123 + num = Number(value) + self.assertEqual(num.value(), value) + + def testStrCtorWithNumberArgument(self): + '''Try to build a Str from 'sample' module with a Number argument from 'other' module.''' + value = 123 + num = Number(value) + string = Str(num) # noqa: F841 + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/objtypehashes_test.py b/sources/shiboken6/tests/otherbinding/objtypehashes_test.py new file mode 100644 index 000000000..d2cd7de5b --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/objtypehashes_test.py @@ -0,0 +1,34 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import HandleHolder +from shiboken6 import Shiboken + + +class TestHashFuncs (unittest.TestCase): + + def testIt(self): + obj1 = HandleHolder() + obj2 = HandleHolder() + + hash1 = hash(obj1) + hash2 = hash(obj2) + self.assertNotEqual(hash1, hash2) + + # Now invalidate the object and test its hash. It shouldn't segfault. + Shiboken.invalidate(obj1) + + hash1_2 = hash(obj1) + self.assertEqual(hash1_2, hash1) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/other-binding.txt.in b/sources/shiboken6/tests/otherbinding/other-binding.txt.in new file mode 100644 index 000000000..d85f6030a --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/other-binding.txt.in @@ -0,0 +1,20 @@ +[generator-project] + +generator-set = shiboken + +header-file = @CMAKE_CURRENT_SOURCE_DIR@/global.h +typesystem-file = @other_TYPESYSTEM@ + +output-directory = @CMAKE_CURRENT_BINARY_DIR@ + +include-path = @libother_SOURCE_DIR@ +include-path = @libsmart_SOURCE_DIR@ +include-path = @libsample_SOURCE_DIR@ +include-path = @libsample_SOURCE_DIR@/.. + +typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@ +typesystem-path = @sample_SOURCE_DIR@ +typesystem-path = @smart_SOURCE_DIR@ + +enable-parent-ctor-heuristic +lean-headers diff --git a/sources/shiboken6/tests/otherbinding/otherbinding.pyproject b/sources/shiboken6/tests/otherbinding/otherbinding.pyproject new file mode 100644 index 000000000..d1bbee11e --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/otherbinding.pyproject @@ -0,0 +1,17 @@ +{ + "files": ["collector_external_operator_test.py", + "conversion_operator_for_class_without_implicit_conversions_test.py", + "extended_multiply_operator_test.py", + "module_reload_test.py", + "new_ctor_operator_test.py", + "objtypehashes_test.py", + "otherderived_test.py", + "othertypesystypedef_test.py", + "signature_test.py", + "smartptr_test.py", + "test_module_template.py", + "typediscovery_test.py", + "usersprimitivefromothermodule_test.py", + "wrongctor_test.py", + "typesystem_other.xml"] +} diff --git a/sources/shiboken6/tests/otherbinding/otherderived_test.py b/sources/shiboken6/tests/otherbinding/otherderived_test.py new file mode 100644 index 000000000..459f474f1 --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/otherderived_test.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for OtherDerived class''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Abstract, Derived +from other import OtherDerived, Number + + +class Multiple(Derived, Number): + def __init__(self): + Derived.__init__(self, 42) + Number.__init__(self, 42) + + def testCall(self): + return True + + +class OtherDeviant(OtherDerived): + def __init__(self): + OtherDerived.__init__(self) + self.pure_virtual_called = False + self.unpure_virtual_called = False + + def pureVirtual(self): + self.pure_virtual_called = True + + def unpureVirtual(self): + self.unpure_virtual_called = True + + def className(self): + return 'OtherDeviant' + + +class MultipleTest(unittest.TestCase): + '''Test case for Multiple derived class''' + + def testConstructor(self): + o = Multiple() + self.assertTrue(isinstance(o, Multiple)) + self.assertTrue(isinstance(o, Number)) + self.assertTrue(isinstance(o, Derived)) + del o + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + def testMethodCall(self): + o = Multiple() + self.assertTrue(o.id_(), 42) + self.assertTrue(o.value(), 42) + self.assertTrue(o.testCall()) + + +class OtherDerivedTest(unittest.TestCase): + '''Test case for OtherDerived class''' + + def testParentClassMethodsAvailability(self): + '''Test if OtherDerived class really inherits its methods from parent.''' + inherited_methods = set(['callPureVirtual', 'callUnpureVirtual', + 'id_', 'pureVirtual', 'unpureVirtual']) + self.assertTrue(inherited_methods.issubset(dir(OtherDerived))) + + def testReimplementedPureVirtualMethodCall(self): + '''Test if a Python override of a implemented pure virtual method is + correctly called from C++.''' + d = OtherDeviant() + d.callPureVirtual() + self.assertTrue(d.pure_virtual_called) + + def testReimplementedVirtualMethodCall(self): + '''Test if a Python override of a reimplemented virtual method is + correctly called from C++.''' + d = OtherDeviant() + d.callUnpureVirtual() + self.assertTrue(d.unpure_virtual_called) + + def testVirtualMethodCallString(self): + '''Test virtual method call returning string.''' + d = OtherDerived() + self.assertEqual(d.className(), 'OtherDerived') + self.assertEqual(d.getClassName(), 'OtherDerived') + + def testReimplementedVirtualMethodCallReturningString(self): + '''Test if a Python override of a reimplemented virtual method is + correctly called from C++.''' + d = OtherDeviant() + self.assertEqual(d.className(), 'OtherDeviant') + self.assertEqual(d.getClassName(), 'OtherDeviant') + + def testCallToMethodWithAbstractArgument(self): + '''Call to method that expects an Abstract argument.''' + objId = 123 + d = OtherDerived(objId) + self.assertEqual(Abstract.getObjectId(d), objId) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/othertypesystypedef_test.py b/sources/shiboken6/tests/otherbinding/othertypesystypedef_test.py new file mode 100644 index 000000000..198c71693 --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/othertypesystypedef_test.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test case for a class that holds a void pointer.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from other import (OtherValueWithUnitUser, ValueWithUnitIntMillimeter) +from sample import (ValueWithUnitDoubleMillimeter) + + +class OtherTypeSysTypeDefTest(unittest.TestCase): + '''Test case type system typedefs across modules.''' + + def test(self): + # Exercise existing typedefs from "sample" + mm_value = ValueWithUnitDoubleMillimeter(2540) + inch_value = OtherValueWithUnitUser.doubleMillimeterToInch(mm_value) + self.assertEqual(int(inch_value.value()), 10) + # Exercise typedefs in "other" + mm_value = ValueWithUnitIntMillimeter(2540) + inch_value = OtherValueWithUnitUser.intMillimeterToInch(mm_value) + self.assertEqual(inch_value.value(), 10) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/signature_test.py b/sources/shiboken6/tests/otherbinding/signature_test.py new file mode 100644 index 000000000..8db3e566b --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/signature_test.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for functions signature''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from other import OtherObjectType +from shiboken_test_helper import objectFullname + +from shibokensupport.signature import get_signature + + +class SignatureTest(unittest.TestCase): + + # Check if the argument of + # 'OtherObjectType::enumAsInt(SampleNamespace::SomeClass::PublicScopedEnum value)' + # has the correct representation + def testNamespaceFromOtherModule(self): + argType = get_signature(OtherObjectType.enumAsInt).parameters["value"].annotation + self.assertEqual(objectFullname(argType), + "sample.SampleNamespace.SomeClass.PublicScopedEnum") + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/smartptr_test.py b/sources/shiboken6/tests/otherbinding/smartptr_test.py new file mode 100644 index 000000000..fd5c7fa09 --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/smartptr_test.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for the SmartPtrTester class''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from other import SmartPtrTester + + +class SmartPtrTest(unittest.TestCase): + '''Test case for the SmartPtrTester class''' + + def test(self): + tester = SmartPtrTester() + + integerPtr = tester.createSharedPtrInteger(42) + self.assertEqual(tester.valueOfSharedPtrInteger(integerPtr), 42) + + strPtr = tester.createSharedPtrStr('hello') + self.assertEqual(tester.valueOfSharedPtrStr(strPtr), 'hello') + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/star_import_test.py b/sources/shiboken6/tests/otherbinding/star_import_test.py new file mode 100644 index 000000000..4b5f1d270 --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/star_import_test.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +"""PYSIDE-2404: Test whether star imports work as they require special handling + by the lazy initialization.""" + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +SHIBOKEN_NAME = "shiboken6.Shiboken" +MINIMAL_NAME = "minimal" +OTHER_NAME = "other" + +shiboken_loaded = 1 if sys.modules.get(SHIBOKEN_NAME) else 0 +minimal_loaded = 1 if sys.modules.get(MINIMAL_NAME) else 0 +other_loaded = 1 if sys.modules.get(OTHER_NAME) else 0 + +from minimal import * # noqa: F403 + +shiboken_loaded += 2 if sys.modules.get(SHIBOKEN_NAME) else 0 +minimal_loaded += 2 if sys.modules.get(MINIMAL_NAME) else 0 +other_loaded += 2 if sys.modules.get(OTHER_NAME) else 0 + +from other import Number # noqa: F403 +from other import * # noqa: F403 + +shiboken_loaded += 4 if sys.modules.get(SHIBOKEN_NAME) else 0 +minimal_loaded += 4 if sys.modules.get(MINIMAL_NAME) else 0 +other_loaded = +4 if sys.modules.get(OTHER_NAME) else 0 + +import shiboken6.Shiboken # noqa: F401 F403 + +shiboken_loaded += 8 if sys.modules.get(SHIBOKEN_NAME) else 0 + + +class ValTest(unittest.TestCase): + + def test(self): + val_id = 123 + val = Val(val_id) # noqa: F405 + self.assertEqual(val.valId(), val_id) + + +class Simple(Number): + + def __init__(self): + Number.__init__(self, 42) + + +class OtherTest(unittest.TestCase): + + def testConstructor(self): + o = Simple() + self.assertTrue(isinstance(o, Number)) + + +class StarImportTest(unittest.TestCase): + """ + This test is meant for Lazy Init. + We explicitly choose modules which are able to lazy load. + + The ValTest: + ------------ + We load something with `import *`. + There is no module from our known ones imported. + This means we need stack introspection to find out that this was + a star import and we must disable lazyness. + + The OtherTest: + -------------- + We load something normally that should be lazy. + After that, we follow with a star import. + Now the stack introspection does not work, because the loading is + cached. The first import did a lazy load. The following star import + needs to undo the lazyness. But now we have a redirected import. + + All tests simply check if the objects are real and not just names. + The <module>_loaded tests prevend upcoming internal dependencies. + + To make sure that Shiboken is really not involved, it is checked + and really imported afterwards (ensuring nothing is misspelled). + """ + + def testStar(self): + self.assertEqual(other_loaded, 4) + self.assertEqual(minimal_loaded, 6) + self.assertEqual(shiboken_loaded, 14) + # Interesting effect: Did not expect that shiboken is loaded at all. + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/test_module_template.py b/sources/shiboken6/tests/otherbinding/test_module_template.py new file mode 100644 index 000000000..36ab43ae3 --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/test_module_template.py @@ -0,0 +1,24 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from other import OtherObjectType +from sample import ObjectType + + +class MyObjectType(ObjectType): + pass + + +class MyOtherObjectType(OtherObjectType): + value = 10 + + +obj = MyObjectType() diff --git a/sources/shiboken6/tests/otherbinding/typediscovery_test.py b/sources/shiboken6/tests/otherbinding/typediscovery_test.py new file mode 100644 index 000000000..39dc5cf0f --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/typediscovery_test.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for type discovery''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import (Abstract, Base1, Derived, + MDerived1, SonOfMDerived1, MDerived3) +from other import OtherMultipleDerived + + +class TypeDiscoveryTest(unittest.TestCase): + + def testPureVirtualsOfImpossibleTypeDiscovery(self): + a = Derived.triggerImpossibleTypeDiscovery() + self.assertEqual(type(a), Abstract) + # call some pure virtual method + a.pureVirtual() + + def testAnotherImpossibleTypeDiscovery(self): + a = Derived.triggerAnotherImpossibleTypeDiscovery() + self.assertEqual(type(a), Derived) + + def testMultipleInheritance(self): + obj = OtherMultipleDerived.createObject("Base1") + self.assertEqual(type(obj), Base1) + # PYSIDE-868: In case of single line direct inheritance, + # a factory function will return the class wrapper + # of the derived class. + obj = OtherMultipleDerived.createObject("MDerived1") + self.assertEqual(type(obj), MDerived1) + obj = OtherMultipleDerived.createObject("SonOfMDerived1") + self.assertEqual(type(obj), SonOfMDerived1) + obj = OtherMultipleDerived.createObject("MDerived3") + self.assertEqual(type(obj), MDerived3) + # PYSIDE-868: OtherMultipleDerived inherits + # OtherBase, Base1. In this case, a factory + # function will return the base class wrapper. + obj = OtherMultipleDerived.createObject("OtherMultipleDerived") + self.assertEqual(type(obj), Base1) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/typesystem_other.xml b/sources/shiboken6/tests/otherbinding/typesystem_other.xml new file mode 100644 index 000000000..ade1c8bad --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/typesystem_other.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="UTF-8"?> +<typesystem package="other"> + <load-typesystem name="typesystem_sample.xml" generate="no" /> + <load-typesystem name="typesystem_smart.xml" generate="no" /> + + <object-type name="OtherObjectType" /> + <object-type name="OtherDerived" /> + <object-type name="OtherMultipleDerived" /> + + <value-type name="ExtendsNoImplicitConversion" /> + <value-type name="Number" /> + + <smart-pointer-type name="SharedPtr" type="shared" getter="data" ref-count-method="useCount" + instantiations="Str"/> + <value-type name="SmartPtrTester"/> + + <typedef-type name="ValueWithUnitIntInch" source="ValueWithUnit<int,LengthUnit::Inch>"/> + <typedef-type name="ValueWithUnitIntMillimeter" source="ValueWithUnit<int,LengthUnit::Millimeter>"/> + <value-type name="OtherValueWithUnitUser"/> +</typesystem> diff --git a/sources/shiboken6/tests/otherbinding/usersprimitivefromothermodule_test.py b/sources/shiboken6/tests/otherbinding/usersprimitivefromothermodule_test.py new file mode 100644 index 000000000..15a988326 --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/usersprimitivefromothermodule_test.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests user defined primitive type from a required module.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from other import Number + + +class UserDefinedPrimitiveTypeFromRequiredModuleTest(unittest.TestCase): + + def testUsersPrimitiveFromRequiredModuleAsArgument(self): + '''static Number Number::fromComplex(Complex)''' + cpx = complex(3.0, 1.2) + number = Number.fromComplex(cpx) + self.assertEqual(number.value(), int(cpx.real)) + + def testUsersPrimitiveFromRequiredModuleAsReturnValue(self): + '''Complex Number::toComplex()''' + number = Number(12) + cpx = number.toComplex() + self.assertEqual(number.value(), int(cpx.real)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/otherbinding/wrongctor_test.py b/sources/shiboken6/tests/otherbinding/wrongctor_test.py new file mode 100644 index 000000000..b9251b428 --- /dev/null +++ b/sources/shiboken6/tests/otherbinding/wrongctor_test.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import Abstract, ObjectType +from other import OtherDerived + + +class Foo(OtherDerived): + def __init__(self): + Abstract.__init__(self, 2) # this should raise an exception + + +class Foo2(ObjectType, OtherDerived): + def __init__(self): + ObjectType.__init__(self) + Abstract.__init__(self, 2) # this should raise an exception + + +class WrongCtorTest(unittest.TestCase): + def testIt(self): + self.assertRaises(TypeError, Foo) + self.assertRaises(TypeError, Foo2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/qtxmltosphinx/CMakeLists.txt b/sources/shiboken6/tests/qtxmltosphinx/CMakeLists.txt new file mode 100644 index 000000000..11b22f038 --- /dev/null +++ b/sources/shiboken6/tests/qtxmltosphinx/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.18) + +# Standalone-buildable + +project(qtxmltosphinx) + +set(CMAKE_AUTOMOC ON) + +find_package(Qt6 COMPONENTS Core) + +set(generator_src_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../generator) +set(api_extractor_src_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../ApiExtractor) + +set(qtxmltosphinx_SRC + ${generator_src_dir}/qtdoc/qtxmltosphinx.cpp + ${api_extractor_src_dir}/codesniphelpers.cpp + ${api_extractor_src_dir}/textstream.cpp + main.cpp) + +add_executable(qtxmltosphinx ${qtxmltosphinx_SRC}) + +target_include_directories(qtxmltosphinx PRIVATE + ${CMAKE_CURRENT_BINARY_DIR} + ${api_extractor_src_dir} + ${generator_src_dir} + ${generator_src_dir}/shiboken + ${generator_src_dir}/qtdoc) + +target_link_libraries(qtxmltosphinx PRIVATE Qt::Core) diff --git a/sources/shiboken6/tests/qtxmltosphinx/main.cpp b/sources/shiboken6/tests/qtxmltosphinx/main.cpp new file mode 100644 index 000000000..5b0624376 --- /dev/null +++ b/sources/shiboken6/tests/qtxmltosphinx/main.cpp @@ -0,0 +1,115 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "qtxmltosphinxinterface.h" +#include "qtxmltosphinx.h" + +#include <QtCore/QCommandLineParser> +#include <QtCore/QCoreApplication> +#include <QtCore/QDebug> +#include <QtCore/QFile> +#include <QtCore/QLoggingCategory> + +#include <exception> +#include <iostream> + +using namespace Qt::StringLiterals; + +static const char help[] = R"(QtXmlToSphinx WebXML to rst converter + +A manual test for converting WebXML files to rst files for checking +formatting. +)"; + +Q_LOGGING_CATEGORY(lcQtXmlToSphinx, "qt.xmltosphinx"); + +static std::ostream &operator<<(std::ostream &str, const QString &s) +{ + str << s.toUtf8().constData(); + return str; +} + +class QtXmlToSphinxDocGenerator : public QtXmlToSphinxDocGeneratorInterface +{ +public: + QtXmlToSphinxDocGenerator() = default; + + QString expandFunction(const QString &) const override; + QString expandClass(const QString &, const QString &) const override; + QString resolveContextForMethod(const QString &, + const QString &) const override; + const QLoggingCategory &loggingCategory() const override; + QtXmlToSphinxLink resolveLink(const QtXmlToSphinxLink &link) const override; + Image resolveImage(const QString &href, const QString &) const; +}; + +// QtXmlToSphinxDocGeneratorInterface +QString QtXmlToSphinxDocGenerator::expandFunction(const QString &) const +{ + return {}; +} + +QString QtXmlToSphinxDocGenerator::expandClass(const QString &, const QString &) const +{ + return {}; +} + +QString QtXmlToSphinxDocGenerator::resolveContextForMethod(const QString &, const QString &) const +{ + return {}; +} + +const QLoggingCategory &QtXmlToSphinxDocGenerator::loggingCategory() const +{ + return lcQtXmlToSphinx(); +} + +QtXmlToSphinxLink + QtXmlToSphinxDocGenerator::resolveLink(const QtXmlToSphinxLink &link) const +{ + return link; +} + +QtXmlToSphinxDocGeneratorInterface::Image + QtXmlToSphinxDocGenerator::resolveImage(const QString &href, const QString &) const +{ + return {href, href}; +} + +static bool run(const QString &fileName) +{ + QtXmlToSphinxDocGenerator generator; + QtXmlToSphinxParameters parameters; + + QFile file(fileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + std::cerr << "Cannot open " << fileName << ": " << file.errorString() << '\n'; + return false; + } + const QString xml = QString::fromUtf8(file.readAll()); + file.close(); + std::cout << QtXmlToSphinx(&generator, parameters, xml).result(); + return true; +} + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + + QCommandLineParser commandLineParser; + commandLineParser.setApplicationDescription(QString::fromLatin1(help)); + commandLineParser.addHelpOption(); + commandLineParser.addPositionalArgument(u"[file]"_s, u"WebXML file to process."_s); + commandLineParser.process(QCoreApplication::arguments()); + if (commandLineParser.positionalArguments().isEmpty()) + commandLineParser.showHelp(0); // quits + + int exitCode = 1; + try { + if (run(commandLineParser.positionalArguments().constFirst())) + exitCode = 0; + } catch (const std::exception &e) { + std::cerr << "An exception occurred: " << e.what() << '\n'; + } + return exitCode; +} diff --git a/sources/shiboken6/tests/qtxmltosphinxtest/CMakeLists.txt b/sources/shiboken6/tests/qtxmltosphinxtest/CMakeLists.txt new file mode 100644 index 000000000..25074e716 --- /dev/null +++ b/sources/shiboken6/tests/qtxmltosphinxtest/CMakeLists.txt @@ -0,0 +1,38 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.18) + +project(qtxmltosphinxtest) + +set(CMAKE_AUTOMOC ON) + +find_package(Qt6 COMPONENTS Core) +find_package(Qt6 COMPONENTS Test) + +set(generator_src_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../generator) +set(api_extractor_src_dir ${CMAKE_CURRENT_SOURCE_DIR}/../../ApiExtractor) + +set(qtxmltosphinxtest_SRC + ${generator_src_dir}/qtdoc/qtxmltosphinx.cpp + ${api_extractor_src_dir}/codesniphelpers.cpp + ${api_extractor_src_dir}/textstream.cpp + qtxmltosphinxtest.cpp + qtxmltosphinxtest.h) + +include_directories(${CMAKE_CURRENT_BINARY_DIR} + ${api_extractor_src_dir} + ${generator_src_dir} + ${generator_src_dir}/shiboken + ${generator_src_dir}/qtdoc) + +add_executable(qtxmltosphinxtest ${qtxmltosphinxtest_SRC}) + +target_link_libraries(qtxmltosphinxtest PRIVATE + Qt::Core + Qt::Test) + +add_test("qtxmltosphinx" qtxmltosphinxtest) +if (INSTALL_TESTS) + install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/qtxmltosphinxtest DESTINATION ${TEST_INSTALL_DIR}) +endif() diff --git a/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.cpp b/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.cpp new file mode 100644 index 000000000..3ba77196f --- /dev/null +++ b/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.cpp @@ -0,0 +1,517 @@ +// 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 "qtxmltosphinxtest.h" +#include "qtxmltosphinx.h" +#include <QtTest/QTest> + +#include <QtCore/QBuffer> +#include <QtCore/QDebug> +#include <QtCore/QLoggingCategory> + +using namespace Qt::StringLiterals; + +Q_LOGGING_CATEGORY(lcQtXmlToSphinxTest, "qt.sphinxtabletest"); + +// QtXmlToSphinxDocGeneratorInterface +QString QtXmlToSphinxTest::expandFunction(const QString &) const +{ + return {}; +} + +QString QtXmlToSphinxTest::expandClass(const QString &, const QString &) const +{ + return {}; +} + +QString QtXmlToSphinxTest::resolveContextForMethod(const QString &, const QString &) const +{ + return {}; +} + +const QLoggingCategory &QtXmlToSphinxTest::loggingCategory() const +{ + return lcQtXmlToSphinxTest(); +} + +QtXmlToSphinxLink QtXmlToSphinxTest::resolveLink(const QtXmlToSphinxLink &link) const +{ + return link; +} + +QtXmlToSphinxDocGeneratorInterface::Image + QtXmlToSphinxTest::resolveImage(const QString &href, const QString &) const +{ + return {href, href}; +} + +QString QtXmlToSphinxTest::transformXml(const QString &xml) const +{ + return QtXmlToSphinx(this, m_parameters, xml).result(); +} + +void QtXmlToSphinxTest::testTable_data() +{ + QTest::addColumn<QString>("xml"); + QTest::addColumn<QString>("expected"); + + QTest::newRow("emptyString") << QString() << QString(); + + // testSimpleTable + const char *xml = R"(<table> + <header> + <item> + <para>Header 1</para> + </item> + <item> + <para>Header 2</para> + </item> + </header> + <row> + <item> + <para>1 1</para> + </item> + <item> + <para>1 2</para> + </item> + </row> + <row> + <item> + <para>2 1</para> + </item> + <item> + <para>2 2</para> + </item> + </row> +</table>)"; + + const char *expected = R"( + +--------+--------+ + |Header 1|Header 2| + +========+========+ + |1 1 |1 2 | + +--------+--------+ + |2 1 |2 2 | + +--------+--------+ + +)"; + + QTest::newRow("testSimpleTable") + << QString::fromLatin1(xml) << QString::fromLatin1(expected); + + // testRowSpan + xml = R"(<table> + <header> + <item> + <para>Header 1</para> + </item> + <item> + <para>Header 2</para> + </item> + </header> + <row> + <item colspan="2"> + <para>I'm a big text!</para> + </item> + </row> + <row> + <item> + <para>2 1</para> + </item> + <item> + <para>2 2</para> + </item> + </row> +</table>)"; + + expected = R"( + +---------------+--------+ + |Header 1 |Header 2| + +===============+========+ + |I'm a big text! | + +---------------+--------+ + |2 1 |2 2 | + +---------------+--------+ + +)"; + + QTest::newRow("testColSpan") + << QString::fromLatin1(xml) << QString::fromLatin1(expected); + + // testRowSpan + xml = R"(<table> + <header> + <item> + <para>Header 1</para> + </item> + <item> + <para>Header 2</para> + </item> + </header> + <row> + <item rowspan="2"> + <para>1.1</para> + </item> + <item> + <para>1.2</para> + </item> + </row> + <row> + <item> + <para>2 2</para> + </item> + </row> +</table>)"; + + expected = R"( + +--------+--------+ + |Header 1|Header 2| + +========+========+ + |1.1 |1.2 | + + +--------+ + | |2 2 | + +--------+--------+ + +)"; + + QTest::newRow("testRowSpan") + << QString::fromLatin1(xml) << QString::fromLatin1(expected); + + // testComplexTable + xml = R"(<table> + <header> + <item> + <para>Header 1</para> + </item> + <item> + <para>Header 2</para> + </item> + <item> + <para>Header 3</para> + </item> + </header> + <row> + <item rowspan="2"> + <para>1.1</para> + </item> + <item colspan="2"> + <para>1.2</para> + </item> + </row> + <row> + <item> + <para>2 2</para> + </item> + <item> + <para>2 3</para> + </item> + </row> +</table>)"; + + expected = R"( + +--------+--------+--------+ + |Header 1|Header 2|Header 3| + +========+========+========+ + |1.1 |1.2 | + + +--------+--------+ + | |2 2 |2 3 | + +--------+--------+--------+ + +)"; + + QTest::newRow("testComplexTable") + << QString::fromLatin1(xml) << QString::fromLatin1(expected); + + // testRowSpan2 + xml = R"(<table> + <header> + <item><para>h1</para></item> + <item><para>h2</para></item> + <item><para>h3</para></item> + <item><para>h4</para></item> + </header> + <row> + <item rowspan="6"><para>A</para></item> + <item rowspan="6"><para>B</para></item> + <item><para>C</para></item> + <item><para>D</para></item> + </row> + <row> + <item><para>E</para></item> + <item><para>F</para></item> + </row> + <row> + <item><para>E</para></item> + <item><para>F</para></item> + </row> + <row> + <item><para>E</para></item> + <item><para>F</para></item> + </row> + <row> + <item><para>E</para></item> + <item><para>F</para></item> + </row> + <row> + <item><para>E</para></item> + <item><para>F</para></item> + </row> +</table>)"; + + expected = R"( + +--+--+--+--+ + |h1|h2|h3|h4| + +==+==+==+==+ + |A |B |C |D | + + + +--+--+ + | | |E |F | + + + +--+--+ + | | |E |F | + + + +--+--+ + | | |E |F | + + + +--+--+ + | | |E |F | + + + +--+--+ + | | |E |F | + +--+--+--+--+ + +)"; + + QTest::newRow("testRowSpan2") + << QString::fromLatin1(xml) << QString::fromLatin1(expected); + + // testNestedList + xml = R"(<table> + <row> + <item> + <list type="bullet"> + <item> + <para>I11</para> + </item> + <item> + <para>I21</para> + </item> + </list> + </item> + <item> + <list type="bullet"> + <item> + <para>I12</para> + </item> + <item> + <para>I22</para> + </item> + </list> + </item> + </row> +</table>)"; + + expected = R"( + +---------+---------+ + | * I11| * I12| + | * I21| * I22| + +---------+---------+ + +)"; + + QTest::newRow("testNestedList") + << QString::fromLatin1(xml) << QString::fromLatin1(expected); + + // testBrokenTable + xml = R"(<table> + <header> + <item> + <para>Header 1</para> + </item> + <item> + <para>Header 2</para> + </item> + </header> + <row> + <item> + <para>1.1</para> + </item> + <item> + <para>1.2</para> + </item> + </row> + <row> + <item colspan="2"> + <para>2 2</para> + </item> + <item> + <para>2 3</para> + </item> + <item> + <para>2 4</para> + </item> + <item> + <para>2 5</para> + </item> + </row> + <row> + <item> + <para>3 1</para> + </item> + <item> + <para>3 2</para> + </item> + <item> + <para>3 3</para> + </item> + </row> +</table>)"; + + expected = R"( + +--------+------------+ + |Header 1|Header 2 | + +========+============+ + |1.1 |1.2 | + +--------+------------+ + |2 2 2 3 2 4 2 5| + +--------+------------+ + |3 1 |3 2 3 3 | + +--------+------------+ + +)"; + + QTest::newRow("testBrokenTable") + << QString::fromLatin1(xml) << QString::fromLatin1(expected); +} + +void QtXmlToSphinxTest::testTable() +{ + QFETCH(QString, xml); + QFETCH(QString, expected); + + const QString actual = transformXml(xml); + + QEXPECT_FAIL("testBrokenTable", "testBrokenTable fails", Continue); + QCOMPARE(actual, expected); +} + +using TablePtr = std::shared_ptr<QtXmlToSphinx::Table>; + +Q_DECLARE_METATYPE(TablePtr); + +void QtXmlToSphinxTest::testTableFormatting_data() +{ + using TableCell = QtXmlToSphinx::TableCell; + + QTest::addColumn<TablePtr>("table"); + QTest::addColumn<QString>("expected"); + + TablePtr table(new QtXmlToSphinx::Table); + table->appendRow({TableCell("item11"), TableCell("item12")}); + table->appendRow({TableCell(""), TableCell("item22")}); + table->normalize(); + + const char *expected = R"(+------+------+ +|item11|item12| ++------+------+ +| |item22| ++------+------+ + +)"; + + QTest::newRow("normal") << table << QString::fromLatin1(expected); + + table.reset(new QtXmlToSphinx::Table); + table->appendRow({TableCell("item11"), TableCell("item12\nline2")}); + table->appendRow({TableCell(""), TableCell("item22\nline2\nline3")}); + table->normalize(); + + expected = R"(+------+------+ +|item11|item12| +| |line2 | ++------+------+ +| |item22| +| |line2 | +| |line3 | ++------+------+ + +)"; + + QTest::newRow("multi-line") << table << QString::fromLatin1(expected); +} + +void QtXmlToSphinxTest::testTableFormatting() +{ + QFETCH(TablePtr, table); + QFETCH(QString, expected); + + StringStream str; + table->format(str); + const QString actual = str.toString(); + + QCOMPARE(actual, expected); +} + +void QtXmlToSphinxTest::testTableFormattingIoDevice_data() +{ + testTableFormatting_data(); +} + +void QtXmlToSphinxTest::testTableFormattingIoDevice() +{ + QFETCH(TablePtr, table); + QFETCH(QString, expected); + + QByteArray byteArray; + { + TextStream str(&byteArray); + table->format(str); + } + const QString actual = QString::fromUtf8(byteArray); + + QCOMPARE(actual, expected); +} + +void QtXmlToSphinxTest::testSnippetExtraction_data() +{ + QTest::addColumn<QByteArray>("file"); + QTest::addColumn<QLatin1StringView>("id"); + QTest::addColumn<QString>("expected"); + + const char *fileCpp = R"(bla +// ![snip1] +snip1_line1 +// ![snip1] // ![snip2] +snip2_line1 +snip2_line2 +// ![snip2] // ![snip3] +)"; + + constexpr auto id = "snip2"_L1; + const QString expected = uR"(snip2_line1 +snip2_line2 +)"_s; + + const char *filePython = R"(bla +# ![snip1] +snip1_line1 +# ![snip1] # ![snip2] +snip2_line1 +snip2_line2 +# ![snip2] # ![snip3] +)"; + + QTest::newRow("c++") << QByteArray(fileCpp) << id << expected; + QTest::newRow("Python") << QByteArray(filePython) << id << expected; +} + +void QtXmlToSphinxTest::testSnippetExtraction() +{ + QFETCH(QByteArray, file); + QFETCH(QLatin1StringView, id); + QFETCH(QString, expected); + + QBuffer buffer(&file); + QVERIFY(buffer.open(QIODevice::ReadOnly)); + QString errorMessage; + QString actual = QtXmlToSphinx::readSnippet(buffer, id, &errorMessage); + QVERIFY2(errorMessage.isEmpty(), qPrintable(errorMessage)); + QCOMPARE(actual, expected); +} + +QTEST_APPLESS_MAIN( QtXmlToSphinxTest) diff --git a/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.h b/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.h new file mode 100644 index 000000000..5108ef452 --- /dev/null +++ b/sources/shiboken6/tests/qtxmltosphinxtest/qtxmltosphinxtest.h @@ -0,0 +1,40 @@ +// 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 QTXMLTOSPHINXTEST_H +#define QTXMLTOSPHINXTEST_H + +#include "qtxmltosphinxinterface.h" + +#include <QtCore/QObject> + +class QtXmlToSphinxTest : public QObject, public QtXmlToSphinxDocGeneratorInterface +{ + Q_OBJECT +public: + // QtXmlToSphinxDocGeneratorInterface + QString expandFunction(const QString &) const override; + QString expandClass(const QString &, const QString &) const override; + QString resolveContextForMethod(const QString &, + const QString &) const override; + const QLoggingCategory &loggingCategory() const override; + QtXmlToSphinxLink resolveLink(const QtXmlToSphinxLink &link) const override; + Image resolveImage(const QString &href, const QString &context) const override; + +private slots: + void testTable_data(); + void testTable(); + void testTableFormatting_data(); + void testTableFormatting(); + void testTableFormattingIoDevice_data(); + void testTableFormattingIoDevice(); + void testSnippetExtraction_data(); + void testSnippetExtraction(); + +private: + QString transformXml(const QString &xml) const; + + QtXmlToSphinxParameters m_parameters; +}; + +#endif // QTXMLTOSPHINXTEST_H diff --git a/sources/shiboken6/tests/samplebinding/CMakeLists.txt b/sources/shiboken6/tests/samplebinding/CMakeLists.txt new file mode 100644 index 000000000..fc812feb8 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/CMakeLists.txt @@ -0,0 +1,176 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +project(sample) + +set(sample_TYPESYSTEM +${CMAKE_CURRENT_SOURCE_DIR}/typesystem_sample.xml +) + +set(sample_SRC +${CMAKE_CURRENT_BINARY_DIR}/sample/abstractmodifications_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/abstract_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/arraymodifytest_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base1_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base2_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base3_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base4_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base5_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/base6_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/blackbox_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/brush_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/bytearray_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/bucket_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/classwithfunctionpointer_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/collector_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/comparisontester_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/color_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/ctorconvrule_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/customoverloadsequence_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/cvlistuser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/cvvaluetype_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sbkdate_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/deleteddefaultctor_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/derived_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/derivedusingct_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/derived_someinnerclass_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/echo_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/event_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/expression_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/exceptiontest_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/friendofonlycopy_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/handleholder_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/implicitconv_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/implicitbase_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/implicittarget_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/intarray2_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/intarray3_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/intlist_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sortedoverload_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/intwrapper_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/injectcode_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/listuser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mapuser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived1_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived2_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived3_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived4_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/mderived5_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/modelindex_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/modifications_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/modifiedconstructor_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/noimplicitconversion_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/nondefaultctor_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objectmodel_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttype_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypebyvalue_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypeholder_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypederived_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypelayout_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypeptrlist_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objecttypeoperators_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objectview_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/objtypereference_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/oddbooluser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/onlycopy_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/otherbase_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/overload_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/overload2_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pairuser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pen_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/persistentmodelindex_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/photon_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/photon_base_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/photon_valueidentity_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/photon_valueduplicator_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/point_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointerholder_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointf_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/pointvaluelist_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/polygon_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/primitivestructpointerholder_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/privatector_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/privatedtor_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectedenumclass_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectednonpolymorphic_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectedpolymorphic_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectedpolymorphicdaughter_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectedpolymorphicgranddaughter_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectedproperty_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/protectedvirtualdestructor_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/rect_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/rectf_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/reference_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/referentmodelindex_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/toberenamedvalue_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/removednamespace1_objectoninvisiblenamespace_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/renameduser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sample_module_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sample_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sample_sample_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_ctparam_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_inlinenamespace_classwithininlinenamespace_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someinnerclass_okthisisrecursiveenough_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someinnerclass_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_someotherinnerclass_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_someclass_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/samplenamespace_derivedfromnamespace_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/stdcomplex_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/simplefile_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/size_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sizef_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/snakecasetest_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/snakecasederivedtest_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/sonofmderived1_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/spaceshipcomparisontester_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/str_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/strlist_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/time_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/templateptr_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/unremovednamespace_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/valuewithunitdoubleinch_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/valuewithunitdoublemillimeter_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/valuewithunituser_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/virtualdaughter_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/virtualdaughter2_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/virtualfinaldaughter_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/virtualdtor_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/virtualmethods_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/voidholder_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/valueandvirtual_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/filter_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/data_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/intersection_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/sample/union_wrapper.cpp +) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/sample-binding.txt.in" + "${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt" @ONLY) + +shiboken_get_tool_shell_wrapper(shiboken tool_wrapper) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" + BYPRODUCTS ${sample_SRC} + COMMAND + ${tool_wrapper} + $<TARGET_FILE:Shiboken6::shiboken6> + --project-file=${CMAKE_CURRENT_BINARY_DIR}/sample-binding.txt + ${GENERATOR_EXTRA_FLAGS} + DEPENDS ${sample_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h Shiboken6::shiboken6 + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Running generator for 'sample' test binding..." +) + +add_library(sample MODULE ${sample_SRC}) +target_include_directories(sample PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(sample PUBLIC libsample libshiboken) +set_property(TARGET sample PROPERTY PREFIX "") +set_property(TARGET sample PROPERTY OUTPUT_NAME "sample${PYTHON_EXTENSION_SUFFIX}") + +if(WIN32) + set_property(TARGET sample PROPERTY SUFFIX ".pyd") +endif() + +create_generator_target(sample) diff --git a/sources/shiboken6/tests/samplebinding/__del___test.py b/sources/shiboken6/tests/samplebinding/__del___test.py new file mode 100644 index 000000000..456886614 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/__del___test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +import sample + +delCalled = False + + +class MyObject(sample.ObjectType): + def __del__(self): + global delCalled + delCalled = True + + +class TestDel(unittest.TestCase): + def testIt(self): + a = MyObject() + del a + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertTrue(delCalled) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/abstract_test.py b/sources/shiboken6/tests/samplebinding/abstract_test.py new file mode 100644 index 000000000..89e87be1d --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/abstract_test.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for Abstract class''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Abstract + + +class Incomplete(Abstract): + def __init__(self): + Abstract.__init__(self) + + +class Concrete(Abstract): + def __init__(self): + Abstract.__init__(self) + self.pure_virtual_called = False + self.unpure_virtual_called = False + + def pureVirtual(self): + self.pure_virtual_called = True + + def pureVirtualReturningVoidPtr(self): + return 42 + + def unpureVirtual(self): + self.unpure_virtual_called = True + + def virtualGettingAEnum(self, enum): + self.virtual_getting_enum = True + + +class AbstractTest(unittest.TestCase): + '''Test case for Abstract class''' + + def testAbstractPureVirtualMethodAvailability(self): + '''Test if Abstract class pure virtual method was properly wrapped.''' + self.assertTrue('pureVirtual' in dir(Abstract)) + + def testAbstractInstanciation(self): + '''Test if instanciation of an abstract class raises the correct exception.''' + self.assertRaises(NotImplementedError, Abstract) + + def testUnimplementedPureVirtualMethodCall(self): + '''Test if calling a pure virtual method raises the correct exception.''' + i = Incomplete() + self.assertRaises(NotImplementedError, i.pureVirtual) + + def testPureVirtualReturningVoidPtrReturnValue(self): + '''Test if a pure virtual method returning void ptr can be properly reimplemented''' + # Note that the semantics of reimplementing the pure virtual method in + # Python and calling it from C++ is undefined until it's decided how to + # cast the Python data types to void pointers + c = Concrete() + self.assertEqual(c.pureVirtualReturningVoidPtr(), 42) + + def testReimplementedVirtualMethodCall(self): + '''Test if a Python override of a virtual method is correctly called from C++.''' + c = Concrete() + c.callUnpureVirtual() + self.assertTrue(c.unpure_virtual_called) + + def testImplementedPureVirtualMethodCall(self): + '''Test if a Python override of a pure virtual method is correctly called from C++.''' + c = Concrete() + c.callPureVirtual() + self.assertTrue(c.pure_virtual_called) + + def testEnumParameterOnVirtualMethodCall(self): + '''testEnumParameterOnVirtualMethodCall''' + c = Concrete() + c.callVirtualGettingEnum(Abstract.Short) + self.assertTrue(c.virtual_getting_enum) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/addedfunction_test.py b/sources/shiboken6/tests/samplebinding/addedfunction_test.py new file mode 100644 index 000000000..0b5680143 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/addedfunction_test.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for added functions.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import SampleNamespace, ObjectType, Point + + +class TestAddedFunctionsWithSimilarTypes(unittest.TestCase): + '''Adds new signatures very similar to already existing ones.''' + + def testValueTypeReferenceAndValue(self): + '''In C++ we have "function(const ValueType&, double)", + in Python we add "function(ValueType)".''' + point = Point(10, 20) + multiplier = 4.0 + control = (point.x() + point.y()) * multiplier + self.assertEqual(SampleNamespace.passReferenceToValueType(point, multiplier), control) + control = point.x() + point.y() + self.assertEqual(SampleNamespace.passReferenceToValueType(point), control) + + def testObjectTypeReferenceAndPointer(self): + '''In C++ we have "function(const ObjectType&, int)", + in Python we add "function(ValueType)".''' + obj = ObjectType() + obj.setObjectName('sbrubbles') + multiplier = 3.0 + control = len(obj.objectName()) * multiplier + self.assertEqual(SampleNamespace.passReferenceToObjectType(obj, multiplier), control) + control = len(obj.objectName()) + self.assertEqual(SampleNamespace.passReferenceToObjectType(obj), control) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/addedfunction_with_container_args_test.py b/sources/shiboken6/tests/samplebinding/addedfunction_with_container_args_test.py new file mode 100644 index 000000000..2a739033b --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/addedfunction_with_container_args_test.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for added functions with nested and multi-argument container types.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import sum2d, sumproduct + + +class TestAddedFunctionsWithContainerArgs(unittest.TestCase): + '''Tests added functions with nested and multi-argument container types.''' + + def testNestedContainerType(self): + '''Test added function with single-argument containers.''' + values = [[1, 2], [3, 4, 5], [6]] + self.assertEqual(sum2d(values), 21) + + def testMultiArgContainerType(self): + '''Test added function with a two-argument container.''' + values = [(1, 2), (3, 4), (5, 6)] + self.assertEqual(sumproduct(values), 44) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/argumentmodifications_test.py b/sources/shiboken6/tests/samplebinding/argumentmodifications_test.py new file mode 100644 index 000000000..b0ca56a6d --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/argumentmodifications_test.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for method arguments modifications performed as described on typesystem.''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Modifications, Point + + +class ArgumentModificationsTest(unittest.TestCase): + '''Test cases for method arguments modifications performed as described on typesystem.''' + + def setUp(self): + self.mods = Modifications() + + def tearDown(self): + del self.mods + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + def testArgRemoval0(self): + '''Tests argument removal modifications on Modifications.argRemoval0.''' + # void [-> PyObject*] argRemoval0(int, bool, int = 123 [removed, new val = 321], int = 456) + # code-injection: returns tuple with received parameters plus removed ones + a0, a1, a2 = 1, True, 2 + self.assertEqual(self.mods.argRemoval0(a0, a1), (a0, a1, 321, 456)) + self.assertEqual(self.mods.argRemoval0(a0, a1, a2), (a0, a1, 321, a2)) + # the other wasn't modified + # void argRemoval0(int, bool, int, bool) + self.assertEqual(self.mods.argRemoval0(0, False, 0, False), None) + + def testArgRemoval1(self): + '''Tests argument removal modifications on Modifications.argRemoval1.''' + # void [-> PyObject*] argRemoval1(int, bool, Point = Point(1, 2) [removed], + # Point = Point(3, 4) [removed], int = 333) + # code-injection: returns tuple with received parameters plus removed ones + a0, a1, a2 = 1, True, 2 + self.assertEqual(self.mods.argRemoval1(a0, a1), (a0, a1, Point(1, 2), Point(3, 4), 333)) + self.assertEqual(self.mods.argRemoval1(a0, a1, a2), (a0, a1, Point(1, 2), Point(3, 4), a2)) + # the other wasn't modified + # void argRemoval1(int, bool, int, bool) + self.assertEqual(self.mods.argRemoval1(0, False, 0, False), None) + + def testArgRemoval2(self): + '''Tests argument removal modifications on Modifications.argRemoval2.''' + # void [-> PyObject*] argRemoval2(int, bool, Point = Point(1, 2) + # [removed], Point = Point(3, 4) [removed], int = 333) + # code-injection: returns tuple with received parameters plus removed ones + a0, a1, a2 = 1, True, 2 + self.assertEqual(self.mods.argRemoval2(a0, a1), (a0, a1, Point(1, 2), Point(3, 4), 333)) + self.assertEqual(self.mods.argRemoval2(a0, a1, a2), (a0, a1, Point(1, 2), Point(3, 4), a2)) + + def testArgRemoval3(self): + '''Tests argument removal modifications on Modifications.argRemoval3.''' + # void [-> PyObject*] argRemoval3(int, Point = Point(1, 2) [removed], + # bool = true, Point = Point(3, 4) [removed], int = 333) + # code-injection: returns tuple with received parameters plus removed ones + a0, a1, a2 = 1, True, 2 + self.assertEqual(self.mods.argRemoval3(a0), (a0, Point(1, 2), True, Point(3, 4), 333)) + self.assertEqual(self.mods.argRemoval3(a0, a1), (a0, Point(1, 2), a1, Point(3, 4), 333)) + self.assertEqual(self.mods.argRemoval3(a0, a1, a2), (a0, Point(1, 2), a1, Point(3, 4), a2)) + + def testArgRemoval4(self): + '''Tests argument removal modifications on Modifications.argRemoval4.''' + # void [-> PyObject*] argRemoval4(int, Point [removed, new val = Point(6, 9)], bool, + # Point = Point(3, 4) [removed], int = 333) + # code-injection: returns tuple with received parameters plus removed ones + a0, a1, a2 = 1, True, 2 + self.assertRaises(TypeError, self.mods.argRemoval4, a0) + self.assertEqual(self.mods.argRemoval4(a0, a1), (a0, Point(6, 9), a1, Point(3, 4), 333)) + self.assertEqual(self.mods.argRemoval4(a0, a1, a2), (a0, Point(6, 9), a1, Point(3, 4), a2)) + + def testArgRemoval5(self): + '''Tests argument removal modifications on Modifications.argRemoval5.''' + # void [-> PyObject*] argRemoval5(int [removed, new val = 100], bool, + # Point = Point(1, 2) [removed], + # Point = Point(3, 4) [removed], int = 333) + # code-injection: returns tuple with received parameters plus removed ones + a0, a1, a2 = True, 2, True + self.assertEqual(self.mods.argRemoval5(a0), (100, a0, Point(1, 2), Point(3, 4), 333)) + self.assertEqual(self.mods.argRemoval5(a0, a1), (100, a0, Point(1, 2), Point(3, 4), a1)) + # void [-> PyObject*] argRemoval5(int [removed, new val = 200], bool, int, bool) + # code-injection: returns tuple with received parameters plus removed ones + self.assertEqual(self.mods.argRemoval5(a0, a1, a2), (200, a0, a1, a2)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/array_numpy_test.py b/sources/shiboken6/tests/samplebinding/array_numpy_test.py new file mode 100644 index 000000000..0d73bca1c --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/array_numpy_test.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test case for NumPy Array types.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +import sample + +hasNumPy = False + +try: + import numpy + hasNumPy = True +except ImportError: + pass + + +class ArrayTester(unittest.TestCase): + '''Test case for NumPy arrays.''' + + def testIntArray(self): + intList = numpy.array([1, 2, 3, 4], dtype='int32') + self.assertEqual(sample.sumIntArray(intList), 10) + + def testDoubleArray(self): + doubleList = numpy.array([1, 2, 3, 4], dtype='double') + self.assertEqual(sample.sumDoubleArray(doubleList), 10) + + def testIntMatrix(self): + intMatrix = numpy.array([[1, 2, 3], [4, 5, 6]], dtype='int32') + self.assertEqual(sample.sumIntMatrix(intMatrix), 21) + + def testDoubleMatrix(self): + doubleMatrix = numpy.array([[1, 2, 3], [4, 5, 6]], dtype='double') + self.assertEqual(sample.sumDoubleMatrix(doubleMatrix), 21) + + +if __name__ == '__main__' and hasNumPy: + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/array_sequence_test.py b/sources/shiboken6/tests/samplebinding/array_sequence_test.py new file mode 100644 index 000000000..ad65d58db --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/array_sequence_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test case for Array types (PySequence).''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +import sample + + +class ArrayTester(unittest.TestCase): + '''Test case for arrays.''' + + def testIntArray(self): + intList = [1, 2, 3, 4] + self.assertEqual(sample.sumIntArray(intList), 10) + + def testIntArrayModified(self): + intList = [1, 2, 3, 4] + tester = sample.ArrayModifyTest() + self.assertEqual(tester.sumIntArray(4, intList), 10) + + def testDoubleArray(self): + doubleList = [1.2, 2.3, 3.4, 4.5] + self.assertEqual(sample.sumDoubleArray(doubleList), 11.4) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/bug_554_test.py b/sources/shiboken6/tests/samplebinding/bug_554_test.py new file mode 100644 index 000000000..a7e7a7210 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/bug_554_test.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Unit test for bug#554''' + +import os +import sys +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType + + +class Bug554: + def crash(self): + class Crasher(ObjectType): + pass + + +if __name__ == '__main__': + bug = Bug554() + bug.crash() diff --git a/sources/shiboken6/tests/samplebinding/bug_704_test.py b/sources/shiboken6/tests/samplebinding/bug_704_test.py new file mode 100644 index 000000000..c470fe723 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/bug_704_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType + + +class NewStyle(object): + def name(self): + return "NewStyle" + + +def defineNewStyle(): + class MyObjectNew(ObjectType, NewStyle): + pass + + +class ObjectTypeTest(unittest.TestCase): + '''Test cases to avoid declaring Shiboken classes with multiple inheritance + from old style classes.''' + + def testObjectTypeNewStype(self): + defineNewStyle() + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/bytearray_test.py b/sources/shiboken6/tests/samplebinding/bytearray_test.py new file mode 100644 index 000000000..e51a899fa --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/bytearray_test.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import ByteArray + + +class ByteArrayBufferProtocolTest(unittest.TestCase): + '''Tests ByteArray implementation of Python buffer protocol.''' + + def testByteArrayBufferProtocol(self): + # Tests ByteArray implementation of Python buffer protocol using the Path().is_dir + # function with a unicode object or other object implementing the Python buffer protocol. + Path(str(ByteArray('/tmp'))).is_dir() + + +class ByteArrayConcatenationOperatorTest(unittest.TestCase): + '''Test cases for ByteArray concatenation with '+' operator.''' + + def testConcatByteArrayAndPythonString(self): + # Test concatenation of a ByteArray with a Python string, in this order. + ba = ByteArray('foo') + result = ba + '\x00bar' + self.assertEqual(type(result), ByteArray) + self.assertEqual(result, 'foo\x00bar') + + def testConcatPythonStringAndByteArray(self): + # Test concatenation of a Python string with a ByteArray, in this order. + concat_python_string_add_qbytearray_worked = True # noqa: F841 + ba = ByteArray('foo') + result = 'bar\x00' + ba + self.assertEqual(type(result), ByteArray) + self.assertEqual(result, 'bar\x00foo') + + +class ByteArrayOperatorEqual(unittest.TestCase): + '''TestCase for operator ByteArray == ByteArray.''' + + def testDefault(self): + # ByteArray() == ByteArray() + obj1 = ByteArray() + obj2 = ByteArray() + self.assertEqual(obj1, obj2) + + def testSimple(self): + # ByteArray(some_string) == ByteArray(some_string) + string = 'egg snakes' + self.assertEqual(ByteArray(string), ByteArray(string)) + + def testPyString(self): + # ByteArray(string) == string + string = 'my test string' + self.assertEqual(ByteArray(string), string) + + def testQString(self): + # ByteArray(string) == string + string = 'another test string' + self.assertEqual(ByteArray(string), string) + + +class ByteArrayOperatorAt(unittest.TestCase): + '''TestCase for operator ByteArray[]''' + + def testInRange(self): + # ByteArray[x] where x is a valid index. + string = 'abcdefgh' + obj = ByteArray(string) + for i in range(len(string)): + self.assertEqual(obj[i], bytes(string[i], "UTF8")) + + def testInRangeReverse(self): + # ByteArray[x] where x is a valid index (reverse order). + string = 'abcdefgh' + obj = ByteArray(string) + for i in range(len(string) - 1, 0, -1): + self.assertEqual(obj[i], bytes(string[i], "UTF8")) + + def testOutOfRange(self): + # ByteArray[x] where x is out of index. + string = '1234567' + obj = ByteArray(string) + self.assertRaises(IndexError, lambda: obj[len(string)]) + + def testNullStrings(self): + ba = ByteArray('\x00') + self.assertEqual(ba.at(0), '\x00') + self.assertEqual(ba[0], bytes('\x00', "UTF8")) + + +class ByteArrayOperatorLen(unittest.TestCase): + '''Test case for __len__ operator of ByteArray''' + + def testBasic(self): + '''ByteArray __len__''' + self.assertEqual(len(ByteArray()), 0) + self.assertEqual(len(ByteArray('')), 0) + self.assertEqual(len(ByteArray(' ')), 1) + self.assertEqual(len(ByteArray('yabadaba')), 8) + + +class ByteArrayAndPythonStr(unittest.TestCase): + '''Test case for __str__ operator of ByteArray''' + + def testStrOperator(self): + '''ByteArray __str__''' + self.assertEqual(ByteArray().__str__(), '') + self.assertEqual(ByteArray('').__str__(), '') + self.assertEqual(ByteArray('aaa').__str__(), 'aaa') + + def testPythonStrAndNull(self): + s1 = bytes('123\000321', "UTF8") + ba = ByteArray(s1) + s2 = ba.data() + self.assertEqual(s1, s2) + self.assertEqual(type(s1), type(s2)) + self.assertEqual(s1, ba) + self.assertNotEqual(type(s1), type(ba)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/child_return_test.py b/sources/shiboken6/tests/samplebinding/child_return_test.py new file mode 100644 index 000000000..f0ac70626 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/child_return_test.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''The BlackBox class has cases of ownership transference between C++ and Python.''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType + + +class ReturnOfChildTest(unittest.TestCase): + '''The BlackBox class has cases of ownership transference between C++ and Python.''' + + def testKillParentKeepingChild(self): + '''Ownership transference from Python to C++ and back again.''' + o1 = ObjectType.createWithChild() + child = o1.children()[0] + del o1 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertRaises(RuntimeError, child.objectName) + + def testKillParentKeepingChild2(self): + '''Ownership transference from Python to C++ and back again.''' + o1 = ObjectType.createWithChild() + child = o1.findChild("child") + del o1 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertRaises(RuntimeError, child.objectName) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/class_fields_test.py b/sources/shiboken6/tests/samplebinding/class_fields_test.py new file mode 100644 index 000000000..1eeb3d446 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/class_fields_test.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Simple test case for accessing the exposed C++ class fields.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Derived, Point, ObjectType + + +class TestAccessingCppFields(unittest.TestCase): + '''Simple test case for accessing the exposed C++ class fields.''' + + def testAccessingPrimitiveTypeField(self): + '''Reads and writes a primitive type (in this case an 'int') field.''' + d = Derived() + self.assertEqual(type(d.primitiveField), int) + + # attribution + old_value = d.primitiveField + new_value = 2255 + d.primitiveField = new_value + self.assertEqual(d.primitiveField, new_value) + self.assertNotEqual(d.primitiveField, old_value) + + # attribution with a convertible type + value = 1.2 + d.primitiveField = value + self.assertEqual(d.primitiveField, int(value)) + + # attribution with invalid type + self.assertRaises(TypeError, lambda: setattr(d, 'primitiveField', None)) + + def testAccessingRenamedFields(self): + '''Reads and writes a renamed field.''' + d = Derived() + self.assertEqual(type(d.renamedField), int) + old_value = d.renamedField + new_value = 2255 + d.renamedField = new_value + self.assertEqual(d.renamedField, new_value) + self.assertNotEqual(d.renamedField, old_value) + + def testAccessingReadOnlyFields(self): + '''Tests a read-only field.''' + d = Derived() + self.assertEqual(type(d.readOnlyField), int) + old_value = d.readOnlyField + try: + d.readOnlyField = 25555 + except AttributeError: + pass + self.assertEqual(d.readOnlyField, old_value) + + def testAccessingUsersPrimitiveTypeField(self): + '''Reads and writes an user's primitive type (in this case an 'Complex') field.''' + d = Derived() + self.assertEqual(type(d.userPrimitiveField), complex) + + # attribution + old_value = d.userPrimitiveField + new_value = complex(1.1, 2.2) + d.userPrimitiveField = new_value + self.assertEqual(d.userPrimitiveField, new_value) + self.assertNotEqual(d.userPrimitiveField, old_value) + + # attribution with invalid type + self.assertRaises(TypeError, lambda: setattr(d, 'userPrimitiveField', None)) + + def testAccessingValueTypeField(self): + '''Reads and writes a value type (in this case a 'Point') field.''' + d = Derived() + self.assertEqual(type(d.valueTypeField), Point) + + # attribution + old_value = d.valueTypeField # noqa: F841 + new_value = Point(-10, 537) + d.valueTypeField = new_value + self.assertEqual(d.valueTypeField, new_value) + + #object modify + d.valueTypeField.setX(10) + d.valueTypeField.setY(20) + self.assertEqual(d.valueTypeField.x(), 10) + self.assertEqual(d.valueTypeField.y(), 20) + + # attribution with invalid type + self.assertRaises(TypeError, lambda: setattr(d, 'valueTypeField', 123)) + + def testAccessingObjectTypeField(self): + '''Reads and writes a object type (in this case an 'ObjectType') field.''' + d = Derived() + + # attribution + old_value = d.objectTypeField + new_value = ObjectType() + d.objectTypeField = new_value + self.assertEqual(d.objectTypeField, new_value) + self.assertNotEqual(d.objectTypeField, old_value) + + # attribution with a convertible type + value = None + d.objectTypeField = value + self.assertEqual(d.objectTypeField, value) + + # attribution with invalid type + self.assertRaises(TypeError, lambda: setattr(d, 'objectTypeField', 123)) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testRefCountingAccessingObjectTypeField(self): + '''Accessing a object type field should respect the reference counting rules.''' + d = Derived() + + # attributing object to instance's field should increase its reference count + o1 = ObjectType() + refcount1 = sys.getrefcount(o1) + d.objectTypeField = o1 + self.assertEqual(d.objectTypeField, o1) + self.assertEqual(sys.getrefcount(d.objectTypeField), refcount1 + 1) + + # attributing a new object to instance's field should decrease the previous + # object's reference count + o2 = ObjectType() + refcount2 = sys.getrefcount(o2) + d.objectTypeField = o2 + self.assertEqual(d.objectTypeField, o2) + self.assertEqual(sys.getrefcount(o1), refcount1) + self.assertEqual(sys.getrefcount(d.objectTypeField), refcount2 + 1) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testRefCountingOfReferredObjectAfterDeletingReferrer(self): + '''Deleting the object referring to other object should decrease the + reference count of the referee.''' + d = Derived() + o = ObjectType() + refcount = sys.getrefcount(o) + d.objectTypeField = o + self.assertEqual(sys.getrefcount(o), refcount + 1) + del d + self.assertEqual(sys.getrefcount(o), refcount) + + def testStaticField(self): + self.assertEqual(Derived.staticPrimitiveField, 0) + + def testAccessingUnsignedIntBitField(self): + d = Derived() + + # attribution + old_value = d.bitField + new_value = 1 + d.bitField = new_value + self.assertEqual(d.bitField, new_value) + self.assertNotEqual(d.bitField, old_value) + + # attribution with a convertible type + value = 1.2 + d.bitField = value + self.assertEqual(d.bitField, int(value)) + + # attribution with invalid type + self.assertRaises(TypeError, lambda: setattr(d, 'bitField', None)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/collector_test.py b/sources/shiboken6/tests/samplebinding/collector_test.py new file mode 100644 index 000000000..4caebc62a --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/collector_test.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for Collector class' shift operators.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Collector, IntWrapper, ObjectType + + +class CollectorTest(unittest.TestCase): + '''Test cases for Collector class' shift operators.''' + + def testLShiftOperatorSingleUse(self): + '''Test case for using the Collector.__lshift__ operator just one time.''' + collector = Collector() + collector << 13 + self.assertEqual(collector.size(), 1) + self.assertEqual(collector.items(), [13]) + + def testLShiftOperatorMultipleUses(self): + '''Test case for using the Collector.__lshift__ operator many times in the same line.''' + collector = Collector() + collector << 2 << 3 << 5 << 7 << 11 + self.assertEqual(collector.size(), 5) + self.assertEqual(collector.items(), [2, 3, 5, 7, 11]) + + +class CollectorExternalOperator(unittest.TestCase): + '''Test cases for external operators of Collector''' + + def testLShiftExternal(self): + '''Collector external operator''' + collector = Collector() + collector << IntWrapper(5) + self.assertEqual(collector.size(), 1) + self.assertEqual(collector.items(), [5]) + + +class CollectorObjectType(unittest.TestCase): + '''Test cases for Collector ObjectType''' + + def testBasic(self): + '''Collector << ObjectType # greedy collector''' + collector = Collector() + obj = ObjectType() + collector << obj + self.assertEqual(collector.items()[0], obj.identifier()) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/complex_test.py b/sources/shiboken6/tests/samplebinding/complex_test.py new file mode 100644 index 000000000..454aff100 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/complex_test.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for Complex class''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +import sample +from sample import Point + + +class ComplexTest(unittest.TestCase): + '''Test case for conversions between C++ Complex class to Python complex class''' + + def testFunctionReturningComplexObject(self): + '''Test function returning a C++ Complex object.''' + cpx = sample.transmutePointIntoComplex(Point(5.0, 2.3)) + self.assertEqual(cpx, complex(5.0, 2.3)) + + def testFunctionReceivingComplexObjectAsArgument(self): + '''Test function returning a C++ Complex object.''' + pt = sample.transmuteComplexIntoPoint(complex(1.2, 3.4)) + # these assertions intentionally avoids to test the == operator, + # it should have its own test cases. + self.assertEqual(pt.x(), 1.2) + self.assertEqual(pt.y(), 3.4) + + def testComplexList(self): + '''Test list of C++ Complex objects conversion to a list of Python complex objects.''' + # the global function gimmeComplexList() is expected to return a list + # containing the following Complex values: [0j, 1.1+2.2j, 1.3+2.4j] + cpxlist = sample.gimmeComplexList() + self.assertEqual(cpxlist, [complex(), complex(1.1, 2.2), complex(1.3, 2.4)]) + + def testSumComplexPair(self): + '''Test sum of a tuple containing two complex objects.''' + cpx1 = complex(1.2, 3.4) + cpx2 = complex(5.6, 7.8) + self.assertEqual(sample.sumComplexPair((cpx1, cpx2)), cpx1 + cpx2) + + def testUsingTuples(self): + cpx1, cpx2 = (1.2, 3.4), (5.6, 7.8) + self.assertEqual(sample.sumComplexPair((cpx1, cpx2)), + sample.sumComplexPair((complex(*cpx1), complex(*cpx2)))) + cpx1, cpx2 = (1, 3), (5, 7) + self.assertEqual(sample.sumComplexPair((cpx1, cpx2)), + sample.sumComplexPair((complex(*cpx1), complex(*cpx2)))) + cpx1, cpx2 = (1.2, 3), (5.6, 7) + self.assertEqual(sample.sumComplexPair((cpx1, cpx2)), + sample.sumComplexPair((complex(*cpx1), complex(*cpx2)))) + cpx1, cpx2 = (1, 2, 3), (4, 5, 7) + self.assertRaises(TypeError, sample.sumComplexPair, (cpx1, cpx2)) + cpx1, cpx2 = ('1', '2'), ('4', '5') + self.assertRaises(TypeError, sample.sumComplexPair, (cpx1, cpx2)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/conversion_operator_test.py b/sources/shiboken6/tests/samplebinding/conversion_operator_test.py new file mode 100644 index 000000000..7e76245b1 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/conversion_operator_test.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for implicit conversion generated by conversion operator.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Time, StrList + + +class ConversionOperatorTest(unittest.TestCase): + '''Test cases for implicit conversion generated by conversion operator.''' + + def testConversionOperator(self): + '''Time defined an conversion operator for Str, so passing a Time object + to a method expecting a Str should work.''' + t = Time(1, 2, 3) + t_str = t.toString() + sl = StrList() + + # StrList.append expects a Str object. + sl.append(t) + + self.assertEqual(len(sl), 1) + self.assertEqual(sl[0], t_str) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/copy_test.py b/sources/shiboken6/tests/samplebinding/copy_test.py new file mode 100644 index 000000000..db539d1b9 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/copy_test.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for deep copy of objects''' + +import copy +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +try: + import cPickle as pickle +except ImportError: + import pickle + + +from sample import Point + + +class SimpleCopy(unittest.TestCase): + '''Simple copy of objects''' + + def testCopy(self): + point = Point(0.1, 2.4) + new_point = copy.copy(point) + + self.assertTrue(point is not new_point) + self.assertEqual(point, new_point) + + +class DeepCopy(unittest.TestCase): + '''Deep copy with shiboken objects''' + + def testDeepCopy(self): + '''Deep copy of value types''' + point = Point(3.1, 4.2) + new_point = copy.deepcopy([point])[0] + + self.assertTrue(point is not new_point) + self.assertEqual(point, new_point) + + +class PicklingTest(unittest.TestCase): + '''Support pickling''' + + def testSimple(self): + '''Simple pickling and unpickling''' + + point = Point(10.2, 43.5) + + data = pickle.dumps(point) + new_point = pickle.loads(data) + + self.assertEqual(point, new_point) + self.assertTrue(point is not new_point) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/ctorconvrule_test.py b/sources/shiboken6/tests/samplebinding/ctorconvrule_test.py new file mode 100644 index 000000000..5e2695d72 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/ctorconvrule_test.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for proper generation of constructor altered by conversion-rule tag.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import CtorConvRule + + +class TestCtorConvRule(unittest.TestCase): + '''Simple test case for CtorConvRule''' + + def testCtorConvRule(self): + '''Test CtorConvRule argument modification through conversion-rule tag.''' + value = 123 + obj = CtorConvRule(value) + self.assertEqual(obj.value(), value + 1) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/cyclic_test.py b/sources/shiboken6/tests/samplebinding/cyclic_test.py new file mode 100644 index 000000000..4e4ae2603 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/cyclic_test.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import ObjectType +from sample import ObjectView +from sample import ObjectModel + + +class ObjTest(unittest.TestCase): + + def test_cyclic_dependency_withParent(self): + """Create 2 objects with a cyclic dependency, so that they can + only be removed by the garbage collector, and then invoke the + garbage collector in a different thread. + """ + class CyclicChildObject(ObjectType): + def __init__(self, parent): + super(CyclicChildObject, self).__init__(parent) + self._parent = parent + + class CyclicObject(ObjectType): + def __init__(self): + super(CyclicObject, self).__init__() + CyclicChildObject(self) + + # turn off automatic garbage collection, to be able to trigger it + # at the 'right' time + gc.disable() + alive = lambda: sum(isinstance(o, CyclicObject) for o in gc.get_objects()) # noqa: E731 + + # + # first proof that the wizard is only destructed by the garbage + # collector + # + cycle = CyclicObject() + self.assertTrue(alive()) + del cycle + if not hasattr(sys, "pypy_version_info"): + # PYSIDE-535: the semantics of gc.enable/gc.disable is different for PyPy + self.assertTrue(alive()) + gc.collect() + self.assertFalse(alive()) + + def test_cyclic_dependency_withKeepRef(self): + """Create 2 objects with a cyclic dependency, so that they can + only be removed by the garbage collector, and then invoke the + garbage collector in a different thread. + """ + class CyclicChildObject(ObjectView): + def __init__(self, model): + super(CyclicChildObject, self).__init__(None) + self.setModel(model) + + class CyclicObject(ObjectModel): + def __init__(self): + super(CyclicObject, self).__init__() + self._view = CyclicChildObject(self) + + # turn off automatic garbage collection, to be able to trigger it + # at the 'right' time + gc.disable() + alive = lambda: sum(isinstance(o, CyclicObject) for o in gc.get_objects()) # noqa: E731 + + # + # first proof that the wizard is only destructed by the garbage + # collector + # + cycle = CyclicObject() + self.assertTrue(alive()) + del cycle + if not hasattr(sys, "pypy_version_info"): + # PYSIDE-535: the semantics of gc.enable/gc.disable is different for PyPy + self.assertTrue(alive()) + gc.collect() + self.assertFalse(alive()) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/date_test.py b/sources/shiboken6/tests/samplebinding/date_test.py new file mode 100644 index 000000000..2b6efcf18 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/date_test.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for python conversions types ''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from datetime import date + +from sample import SbkDate + + +class DateConversionTest(unittest.TestCase): + + def testConstructorWithDateObject(self): + pyDate = date(2010, 12, 12) + cDate = SbkDate(pyDate) + self.assertTrue(cDate.day(), pyDate.day) + self.assertTrue(cDate.month(), pyDate.month) + self.assertTrue(cDate.year(), pyDate.year) + + def testToPythonFunction(self): + cDate = SbkDate(2010, 12, 12) + pyDate = cDate.toPython() + self.assertTrue(cDate.day(), pyDate.day) + self.assertTrue(cDate.month(), pyDate.month) + self.assertTrue(cDate.year(), pyDate.year) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/decisor_test.py b/sources/shiboken6/tests/samplebinding/decisor_test.py new file mode 100644 index 000000000..0d39c5f96 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/decisor_test.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for the method overload decisor.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import SampleNamespace, Point, ObjectType, ObjectModel + + +class DecisorTest(unittest.TestCase): + '''Test cases for the method overload decisor.''' + + def testCallWithInvalidParametersSideA(self): + '''Call a method missing with the last argument missing. + This can trigger the bug #262, which means using an argument + not provided by the user.''' + pt = Point() + # This exception may move from a TypeError to a ValueError. + self.assertRaises((TypeError, ValueError), SampleNamespace.forceDecisorSideA, pt) + + def testCallWithInvalidParametersSideB(self): + '''Same as the previous test, but with an integer as first argument, + just to complicate things for the overload method decisor.''' + pt = Point() + # This exception may move from a TypeError to a ValueError. + self.assertRaises((TypeError, ValueError), SampleNamespace.forceDecisorSideB, 1, pt) + + def testDecideCallWithInheritance(self): + '''Call methods overloads that receive parent and inheritor classes' instances.''' + objecttype = ObjectType() + objectmodel = ObjectModel() + self.assertEqual(ObjectModel.receivesObjectTypeFamily(objecttype), + ObjectModel.ObjectTypeCalled) + self.assertNotEqual(ObjectModel.receivesObjectTypeFamily(objecttype), + ObjectModel.ObjectModelCalled) + self.assertEqual(ObjectModel.receivesObjectTypeFamily(objectmodel), + ObjectModel.ObjectModelCalled) + self.assertNotEqual(ObjectModel.receivesObjectTypeFamily(objectmodel), + ObjectModel.ObjectTypeCalled) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/delete_test.py b/sources/shiboken6/tests/samplebinding/delete_test.py new file mode 100644 index 000000000..57a792ae2 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/delete_test.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +import sample +from shiboken6 import Shiboken + + +class DeleteTest(unittest.TestCase): + def testNonCppWrapperClassDelete(self): + """Would segfault when shiboken.delete called on obj not created from Python.""" + obj = sample.ObjectType() + child = obj.createChild(None) + Shiboken.delete(child) + assert not Shiboken.isValid(child) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/deprecated_test.py b/sources/shiboken6/tests/samplebinding/deprecated_test.py new file mode 100644 index 000000000..c371df94f --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/deprecated_test.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest +import warnings + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType + + +class TestDeprecatedCall(unittest.TestCase): + def testCallWithError(self): + o = ObjectType() + warnings.simplefilter('error') + self.assertRaises(DeprecationWarning, o.deprecatedFunction) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/derived_test.py b/sources/shiboken6/tests/samplebinding/derived_test.py new file mode 100644 index 000000000..346f29136 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/derived_test.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for Derived class''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +import sample +from sample import Abstract, Derived, DerivedUsingCt, OverloadedFuncEnum + + +class Deviant(Derived): + def __init__(self): + Derived.__init__(self) + self.pure_virtual_called = False + self.unpure_virtual_called = False + + def pureVirtual(self): + self.pure_virtual_called = True + + def unpureVirtual(self): + self.unpure_virtual_called = True + + def className(self): + return 'Deviant' + + +class ImplementVirtualWithOutParameter(Derived): + def __init__(self, value): + super().__init__() + self._value = value + + def virtualWithOutParameter(self): + return self._value + + +class DerivedTest(unittest.TestCase): + '''Test case for Derived class''' + + def testParentClassMethodsAvailability(self): + '''Test if Derived class really inherits its methods from parent.''' + inherited_methods = set(['callPureVirtual', 'callUnpureVirtual', + 'id_', 'pureVirtual', 'unpureVirtual']) + self.assertTrue(inherited_methods.issubset(dir(Derived))) + + def testOtherOverloadedMethodCall(self): + '''Another test to check overloaded method calling, just to double check.''' + derived = Derived() + + result = derived.otherOverloaded(1, 2, True, 3.3) + self.assertEqual(type(result), Derived.OtherOverloadedFuncEnum) + self.assertEqual(result, sample.Derived.OtherOverloadedFunc_iibd) + + result = derived.otherOverloaded(1, 2.2) + self.assertEqual(type(result), Derived.OtherOverloadedFuncEnum) + self.assertEqual(result, Derived.OtherOverloadedFunc_id) + + def testOverloadedMethodCallWithDifferentNumericTypes(self): + '''Test if the correct overloaded method accepts a different numeric type as argument.''' + derived = Derived() + result = derived.overloaded(1.1, 2.2) + self.assertEqual(type(result), OverloadedFuncEnum) + + def testOverloadedMethodCallWithWrongNumberOfArguments(self): + '''Test if a call to an overloaded method with the wrong number of arguments + raises an exception.''' + derived = Derived() + self.assertRaises(TypeError, derived.otherOverloaded, 1, 2, True) + + def testReimplementedPureVirtualMethodCall(self): + '''Test if a Python override of a implemented pure virtual method is + correctly called from C++.''' + d = Deviant() + d.callPureVirtual() + self.assertTrue(d.pure_virtual_called) + + def testReimplementedVirtualMethodCall(self): + '''Test if a Python override of a reimplemented virtual method is + correctly called from C++.''' + d = Deviant() + d.callUnpureVirtual() + self.assertTrue(d.unpure_virtual_called) + + def testVirtualMethodCallString(self): + '''Test virtual method call returning string.''' + d = Derived() + self.assertEqual(d.className(), 'Derived') + self.assertEqual(d.getClassName(), 'Derived') + + def testReimplementedVirtualMethodCallReturningString(self): + '''Test if a Python override of a reimplemented virtual method is + correctly called from C++.''' + d = Deviant() + self.assertEqual(d.className(), 'Deviant') + self.assertEqual(d.getClassName(), 'Deviant') + + def testSingleArgument(self): + '''Test singleArgument call.''' + d = Derived() + self.assertTrue(d.singleArgument(False)) + self.assertTrue(not d.singleArgument(True)) + + def testMethodCallWithDefaultValue(self): + '''Test method call with default value.''' + d = Derived() + self.assertEqual(d.defaultValue(3), 3.1) + self.assertEqual(d.defaultValue(), 0.1) + + def testCallToMethodWithAbstractArgument(self): + '''Call to method that expects an Abstract argument.''' + objId = 123 + d = Derived(objId) + self.assertEqual(Abstract.getObjectId(d), objId) + + def testObjectCreationWithParentType(self): + '''Derived class creates an instance of itself in C++ and returns it as + a pointer to its ancestor Abstract.''' + obj = Derived.createObject() + self.assertEqual(type(obj), Derived) + + def testDerivedUsingCt(self): + '''Test whether a constructor of the base class declared by using works''' + obj = DerivedUsingCt(42) + self.assertEqual(obj.value(), 42) + + def testVirtualWithOutParameter(self): + d = Derived() + self.assertEqual(d.callVirtualWithOutParameter(), 42) + + d = ImplementVirtualWithOutParameter(1) + self.assertEqual(d.callVirtualWithOutParameter(), 1) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/duck_punching_test.py b/sources/shiboken6/tests/samplebinding/duck_punching_test.py new file mode 100644 index 000000000..aa21a0f7e --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/duck_punching_test.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for virtual methods.''' + +import os +import sys +import types +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import VirtualMethods, SimpleFile, Point + + +def MethodTypeCompat(func, instance): + return types.MethodType(func, instance) + + +class Duck(VirtualMethods): + def __init__(self): + VirtualMethods.__init__(self) + + +class Monkey(SimpleFile): + def __init__(self, filename): + SimpleFile.__init__(self, filename) + + +class DuckPunchingTest(unittest.TestCase): + '''Test case for duck punching (aka "monkey patching").''' + + def setUp(self): + self.multiplier = 2.0 + self.duck_method_called = False + self.call_counter = 0 + + def testMonkeyPatchOnVirtualMethod(self): + '''Injects new 'virtualMethod0' on a VirtualMethods instance and makes C++ call it.''' + vm = VirtualMethods() + pt, val, cpx, b = Point(1.1, 2.2), 4, complex(3.3, 4.4), True + + result1 = vm.virtualMethod0(pt, val, cpx, b) + result2 = vm.callVirtualMethod0(pt, val, cpx, b) + self.assertEqual(result1, result2) + self.assertEqual(result1, VirtualMethods.virtualMethod0(vm, pt, val, cpx, b)) + + def myVirtualMethod0(obj, pt, val, cpx, b): + self.duck_method_called = True + return VirtualMethods.virtualMethod0(obj, pt, val, cpx, b) * self.multiplier + vm.virtualMethod0 = MethodTypeCompat(myVirtualMethod0, vm) + + result1 = vm.callVirtualMethod0(pt, val, cpx, b) + self.assertTrue(self.duck_method_called) + + result2 = vm.virtualMethod0(pt, val, cpx, b) + self.assertEqual(result1, result2) + self.assertEqual(result1, + VirtualMethods.virtualMethod0(vm, pt, val, cpx, b) * self.multiplier) + + # This is done to decrease the refcount of the vm object + # allowing the object wrapper to be deleted before the + # BindingManager. This is useful when compiling Shiboken + # for debug, since the BindingManager destructor has an + # assert that checks if the wrapper mapper is empty. + vm.virtualMethod0 = None + + def testMonkeyPatchOnVirtualMethodWithInheritance(self): + '''Injects new 'virtualMethod0' on an object that inherits from + VirtualMethods and makes C++ call it.''' + duck = Duck() + pt, val, cpx, b = Point(1.1, 2.2), 4, complex(3.3, 4.4), True + + result1 = duck.virtualMethod0(pt, val, cpx, b) + result2 = duck.callVirtualMethod0(pt, val, cpx, b) + self.assertEqual(result1, result2) + self.assertEqual(result1, VirtualMethods.virtualMethod0(duck, pt, val, cpx, b)) + + def myVirtualMethod0(obj, pt, val, cpx, b): + self.duck_method_called = True + return VirtualMethods.virtualMethod0(obj, pt, val, cpx, b) * self.multiplier + duck.virtualMethod0 = MethodTypeCompat(myVirtualMethod0, duck) + + result1 = duck.callVirtualMethod0(pt, val, cpx, b) + self.assertTrue(self.duck_method_called) + + result2 = duck.virtualMethod0(pt, val, cpx, b) + self.assertEqual(result1, result2) + self.assertEqual(result1, + VirtualMethods.virtualMethod0(duck, pt, val, cpx, b) * self.multiplier) + + duck.virtualMethod0 = None + + def testMonkeyPatchOnMethodWithStaticAndNonStaticOverloads(self): + '''Injects new 'exists' on a SimpleFile instance and makes C++ call it.''' + simplefile = SimpleFile('foobar') + + # Static 'exists' + simplefile.exists('sbrubbles') + self.assertFalse(self.duck_method_called) + # Non-static 'exists' + simplefile.exists() + self.assertFalse(self.duck_method_called) + + def myExists(obj): + self.duck_method_called = True + return False + simplefile.exists = MethodTypeCompat(myExists, simplefile) + + # Static 'exists' was overridden by the monkey patch, which accepts 0 arguments + self.assertRaises(TypeError, simplefile.exists, 'sbrubbles') + # Monkey patched exists + simplefile.exists() + self.assertTrue(self.duck_method_called) + + simplefile.exists = None + + def testMonkeyPatchOnMethodWithStaticAndNonStaticOverloadsWithInheritance(self): + '''Injects new 'exists' on an object that inherits from SimpleFile and makes C++ call it.''' + monkey = Monkey('foobar') + + # Static 'exists' + monkey.exists('sbrubbles') + self.assertFalse(self.duck_method_called) + # Non-static 'exists' + monkey.exists() + self.assertFalse(self.duck_method_called) + + def myExists(obj): + self.duck_method_called = True + return False + monkey.exists = MethodTypeCompat(myExists, monkey) + + # Static 'exists' was overridden by the monkey patch, which accepts 0 arguments + self.assertRaises(TypeError, monkey.exists, 'sbrubbles') + # Monkey patched exists + monkey.exists() + self.assertTrue(self.duck_method_called) + + monkey.exists = None + + def testForInfiniteRecursion(self): + def myVirtualMethod0(obj, pt, val, cpx, b): + self.call_counter += 1 + return VirtualMethods.virtualMethod0(obj, pt, val, cpx, b) + vm = VirtualMethods() + vm.virtualMethod0 = MethodTypeCompat(myVirtualMethod0, vm) + pt, val, cpx, b = Point(1.1, 2.2), 4, complex(3.3, 4.4), True + vm.virtualMethod0(pt, val, cpx, b) + self.assertEqual(self.call_counter, 1) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/echo_test.py b/sources/shiboken6/tests/samplebinding/echo_test.py new file mode 100644 index 000000000..f1859260e --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/echo_test.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for <add-function> with const char* as argument''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Echo + + +class TestEcho(unittest.TestCase): + '''Simple test case for Echo.echo''' + + def testEcho(self): + '''Test function added with const char * as arg''' + x = 'Foobar' + y = Echo().echo(x) + self.assertEqual(x, y) + + def testCallOperator(self): + e = Echo() + self.assertEqual(e("Hello", 3), "Hello3") + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/enum_test.py b/sources/shiboken6/tests/samplebinding/enum_test.py new file mode 100644 index 000000000..276b8d894 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/enum_test.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for Python representation of C++ enums.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +# This is needed after the introduction of BUILD_DIR. + +import sample +from sample import SampleNamespace, ObjectType, Event + + +def createTempFile(): + import tempfile + return tempfile.SpooledTemporaryFile(mode='rw') + + +class EnumTest(unittest.TestCase): + '''Test case for Python representation of C++ enums.''' + + def testHashability(self): + self.assertEqual(hash(SampleNamespace.TwoIn), hash(SampleNamespace.TwoOut)) + self.assertNotEqual(hash(SampleNamespace.TwoIn), hash(SampleNamespace.OneIn)) + + def testEnumValuesInsideEnum(self): + '''Enum values should be accessible inside the enum as well as outside.''' + for value_name in SampleNamespace.Option.__members__: + enum_item1 = getattr(SampleNamespace.Option, value_name) + enum_item2 = getattr(SampleNamespace, value_name) + self.assertEqual(enum_item1, enum_item2) + + def testPassingIntegerOnEnumArgument(self): + '''Tries to use an integer in place of an enum argument.''' + self.assertRaises(TypeError, SampleNamespace.getNumber, 1) + + def testBuildingEnumFromIntegerValue(self): + '''Tries to build the proper enum using an integer.''' + SampleNamespace.getNumber(SampleNamespace.Option(1)) + + def testBuildingEnumWithDefaultValue(self): + '''Enum constructor with default value''' + enum = SampleNamespace.Option() + self.assertEqual(enum, SampleNamespace.None_) + + def testEnumConversionToAndFromPython(self): + '''Conversion of enum objects from Python to C++ back again.''' + enumout = SampleNamespace.enumInEnumOut(SampleNamespace.TwoIn) + self.assertTrue(enumout, SampleNamespace.TwoOut) + self.assertEqual(repr(enumout), repr(SampleNamespace.TwoOut)) + + def testEnumConstructorWithTooManyParameters(self): + '''Calling the constructor of non-extensible enum with the wrong number of parameters.''' + self.assertRaises((TypeError, ValueError), SampleNamespace.InValue, 13, 14) + + def testEnumConstructorWithNonNumberParameter(self): + '''Calling the constructor of non-extensible enum with a string.''' + self.assertRaises((TypeError, ValueError), SampleNamespace.InValue, '1') + + def testEnumItemAsDefaultValueToIntArgument(self): + '''Calls function with an enum item as default value to an int argument.''' + self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(), + SampleNamespace.ZeroIn) + self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(SampleNamespace.ZeroOut), # noqa E:501 + SampleNamespace.ZeroOut) + self.assertEqual(SampleNamespace.enumItemAsDefaultValueToIntArgument(123), 123) + + def testAnonymousGlobalEnums(self): + '''Checks availability of anonymous global enum items.''' + self.assertEqual(sample.AnonymousGlobalEnum_Value0, 0) + self.assertEqual(sample.AnonymousGlobalEnum_Value1, 1) + + def testAnonymousClassEnums(self): + '''Checks availability of anonymous class enum items.''' + self.assertEqual(SampleNamespace.AnonymousClassEnum_Value0, 0) + self.assertEqual(SampleNamespace.AnonymousClassEnum_Value1, 1) + + def testEnumClasses(self): + # C++ 11: values of enum classes need to be fully qualified to match C++ + sum = Event.EventTypeClass.Value1 + Event.EventTypeClass.Value2 + self.assertEqual(sum, 1) + + def testSetEnum(self): + event = Event(Event.ANY_EVENT) + self.assertEqual(event.eventType(), Event.ANY_EVENT) + event.setEventType(Event.BASIC_EVENT) + self.assertEqual(event.eventType(), Event.BASIC_EVENT) + event.setEventTypeByConstRef(Event.SOME_EVENT) + self.assertEqual(event.eventType(), Event.SOME_EVENT) + event.setEventTypeByConstPtr(Event.BASIC_EVENT) + self.assertEqual(event.eventType(), Event.BASIC_EVENT) + + def testEnumArgumentWithDefaultValue(self): + '''Option enumArgumentWithDefaultValue(Option opt = UnixTime);''' + self.assertEqual(SampleNamespace.enumArgumentWithDefaultValue(), SampleNamespace.UnixTime) + self.assertEqual(SampleNamespace.enumArgumentWithDefaultValue(SampleNamespace.RandomNumber), # noqa E:501 + SampleNamespace.RandomNumber) + + +class MyEvent(Event): + def __init__(self): + Event.__init__(self, Event.EventType(3)) + + +class OutOfBoundsTest(unittest.TestCase): + def testValue(self): + e = MyEvent() + self.assertEqual(repr(e.eventType()), "<EventType.ANY_EVENT: 3>") + + +class EnumOverloadTest(unittest.TestCase): + '''Test case for overloads involving enums''' + + def testWithInt(self): + '''Overload with Enums and ints with default value''' + o = ObjectType() + + self.assertEqual(o.callWithEnum('', Event.ANY_EVENT, 9), 81) + self.assertEqual(o.callWithEnum('', 9), 9) + + +class EnumOperators(unittest.TestCase): + '''Test case for operations on enums''' + + def testInequalitySameObject(self): + self.assertFalse(Event.ANY_EVENT != Event.ANY_EVENT) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/enumfromremovednamespace_test.py b/sources/shiboken6/tests/samplebinding/enumfromremovednamespace_test.py new file mode 100644 index 000000000..42ae23961 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/enumfromremovednamespace_test.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +import sample +from shiboken_test_helper import objectFullname + +from shibokensupport.signature import get_signature + + +class TestEnumFromRemovedNamespace(unittest.TestCase): + + def testNames(self): + # Test if invisible namespace does not appear on type name + self.assertEqual(objectFullname(sample.RemovedNamespace1_Enum), + "sample.RemovedNamespace1_Enum") + self.assertEqual(objectFullname(sample.ObjectOnInvisibleNamespace), + "sample.ObjectOnInvisibleNamespace") + + # Function arguments + signature = get_signature(sample.ObjectOnInvisibleNamespace.toInt) + self.assertEqual(objectFullname(signature.parameters['e'].annotation), + "sample.RemovedNamespace1_Enum") + signature = get_signature(sample.ObjectOnInvisibleNamespace.consume) + self.assertEqual(objectFullname(signature.parameters['other'].annotation), + "sample.ObjectOnInvisibleNamespace") + + def testGlobalFunctionFromRemovedNamespace(self): + self.assertEqual(sample.mathSum(1, 2), 3) + + def testEnumPromotedToUpperNamespace(self): + sample.UnremovedNamespace + sample.UnremovedNamespace.RemovedNamespace3_Enum + sample.UnremovedNamespace.RemovedNamespace3_Enum_Value0 + sample.UnremovedNamespace.RemovedNamespace3_AnonymousEnum_Value0 + + def testNestedFunctionFromRemovedNamespace(self): + self.assertEqual(sample.UnremovedNamespace.nestedMathSum(1, 2), 3) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/event_loop_call_virtual_test.py b/sources/shiboken6/tests/samplebinding/event_loop_call_virtual_test.py new file mode 100644 index 000000000..8e13d5d46 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/event_loop_call_virtual_test.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Simple event loop dispatcher test.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType, Event + + +class NoOverride(ObjectType): + + pass + + +class Override(ObjectType): + + def __init__(self): + ObjectType.__init__(self) + self.called = False + + def event(self, event): + self.called = True + return True + + +class TestEventLoop(unittest.TestCase): + + def testEventLoop(self): + '''Calling virtuals in a event loop''' + objs = [ObjectType(), NoOverride(), Override()] + + evaluated = ObjectType.processEvent(objs, + Event(Event.BASIC_EVENT)) + + self.assertEqual(evaluated, 3) + self.assertTrue(objs[2].called) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/event_loop_thread_test.py b/sources/shiboken6/tests/samplebinding/event_loop_thread_test.py new file mode 100644 index 000000000..8b854fca6 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/event_loop_thread_test.py @@ -0,0 +1,77 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +from random import random +import sys +import time +import threading +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType, Event + + +class Producer(ObjectType): + + def __init__(self): + ObjectType.__init__(self) + self.data = None + self.read = False + + def event(self, event): + self.data = random() + + while not self.read: + time.sleep(0.01) + + return True + + +class Collector(threading.Thread): + + def __init__(self, objects): + threading.Thread.__init__(self) + self.max_runs = len(objects) + self.objects = objects + self.data = [] + + def run(self): + i = 0 + while i < self.max_runs: + if self.objects[i].data is not None: + self.data.append(self.objects[i].data) + self.objects[i].read = True + i += 1 + time.sleep(0.01) + + +class TestEventLoopWithThread(unittest.TestCase): + '''Communication between a python thread and an simple + event loop in C++''' + + def testBasic(self): + '''Allowing threads and calling virtuals from C++''' + number = 10 + objs = [Producer() for x in range(number)] + thread = Collector(objs) + + thread.start() + + evaluated = ObjectType.processEvent(objs, + Event(Event.BASIC_EVENT)) + + thread.join() + + producer_data = [x.data for x in objs] + self.assertEqual(evaluated, number) + self.assertEqual(producer_data, thread.data) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/exception_test.py b/sources/shiboken6/tests/samplebinding/exception_test.py new file mode 100644 index 000000000..d9e6b377f --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/exception_test.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ExceptionTest + + +class CppExceptionTest(unittest.TestCase): + + def testVoid(self): + exceptionCount = 0 + et = ExceptionTest() + + et.voidThrowStdException(False) + + try: + et.voidThrowStdException(True) + except: # noqa: E722 + exceptionCount += 1 + + et.voidThrowInt(False) + + try: + et.voidThrowInt(True) + except: # noqa: E722 + exceptionCount += 1 + + self.assertEqual(exceptionCount, 2) + + def testReturnValue(self): + exceptionCount = 0 + et = ExceptionTest() + + result = et.intThrowStdException(False) + + try: + result = et.intThrowStdException(True) + except: # noqa: E722 + exceptionCount += 1 + + result = et.intThrowInt(False) + + try: + result = et.intThrowInt(True) # noqa: F841 + except: # noqa: E722 + exceptionCount += 1 + + self.assertEqual(exceptionCount, 2) + + def testModifications(self): + """PYSIDE-1995, test whether exceptions are propagated + when return ownership modifications are generated.""" + exceptionCount = 0 + try: + et = ExceptionTest.create(True) # noqa: F841 + except: # noqa: E722 + exceptionCount += 1 + self.assertEqual(exceptionCount, 1) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/filter_test.py b/sources/shiboken6/tests/samplebinding/filter_test.py new file mode 100644 index 000000000..df805093f --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/filter_test.py @@ -0,0 +1,29 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Data, Intersection, Union + + +class TestFilters(unittest.TestCase): + + def testAnd(self): + + f1 = Data(Data.Name, "joe") + f2 = Union() + + inter = f1 & f2 + + self.assertEqual(type(inter), Intersection) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/global.h b/sources/shiboken6/tests/samplebinding/global.h new file mode 100644 index 000000000..64806417a --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/global.h @@ -0,0 +1,73 @@ +// 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 "abstract.h" +#include "blackbox.h" +#include "bytearray.h" +#include "bucket.h" +#include "collector.h" +#include "complex.h" +#include "ctorconvrule.h" +#include "ctparam.h" +#include "cvlist.h" +#include "sbkdate.h" +#include "derived.h" +#include "derivedusingct.h" +#include "echo.h" +#include "exceptiontest.h" +#include "functions.h" +#include "implicitconv.h" +#include "nontypetemplate.h" +#include "overloadsort.h" +#include "handle.h" +#include "injectcode.h" +#include "list.h" +#include "listuser.h" +#include "mapuser.h" +#include "modelindex.h" +#include "modifications.h" +#include "modified_constructor.h" +#include "multiple_derived.h" +#include "noimplicitconversion.h" +#include "nondefaultctor.h" +#include "objectmodel.h" +#include "objecttype.h" +#include "objecttypebyvalue.h" +#include "objecttypeholder.h" +#include "objecttypelayout.h" +#include "objecttypeoperators.h" +#include "objectview.h" +#include "oddbool.h" +#include "onlycopy.h" +#include "overload.h" +#include "pairuser.h" +#include "pen.h" +#include "photon.h" +#include "point.h" +#include "pointf.h" +#include "pointerholder.h" +#include "polygon.h" +#include "privatector.h" +#include "privatedtor.h" +#include "protected.h" +#include "rect.h" +#include "reference.h" +#include "renaming.h" +#include "removednamespaces.h" +#include "sample.h" +#include "samplenamespace.h" +#include "stdcomplex.h" +#include "simplefile.h" +#include "size.h" +#include "snakecasetest.h" +#include "str.h" +#include "strlist.h" +#include "sometime.h" +#include "templateptr.h" +#include "transform.h" +#include "typesystypedef.h" +#include "virtualmethods.h" +#include "voidholder.h" +#include "valueandvirtual.h" +#include "expression.h" +#include "filter.h" diff --git a/sources/shiboken6/tests/samplebinding/handleholder_test.py b/sources/shiboken6/tests/samplebinding/handleholder_test.py new file mode 100644 index 000000000..af22328c5 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/handleholder_test.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +''' Test case for a class that holds a unknown handle object. + Test case for BUG #1105. +''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import HandleHolder + + +class HandleHolderTest(unittest.TestCase): + def testCreation(self): + holder = HandleHolder(HandleHolder.createHandle()) + holder2 = HandleHolder(HandleHolder.createHandle()) + self.assertEqual(holder.compare(holder2), False) + + def testTransfer(self): + holder = HandleHolder() + holder2 = HandleHolder(holder.handle()) + self.assertTrue(holder.compare(holder2)) + + def testUseDefinedType(self): + holder = HandleHolder(8) + holder2 = HandleHolder(holder.handle2()) + self.assertTrue(holder.compare2(holder2)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/hashabletype_test.py b/sources/shiboken6/tests/samplebinding/hashabletype_test.py new file mode 100644 index 000000000..c41f5cc06 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/hashabletype_test.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for __hash__''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType, Str + + +class HashableTest(unittest.TestCase): + + def testStrHash(self): + h = {} + s = Str("Hi") + h[s] = 2 + self.assertTrue(h.get(s), 2) + + def testObjectTypeHash(self): + h = {} + o = ObjectType() + h[o] = 2 + self.assertTrue(h.get(o), 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/ignorederefop_test.py b/sources/shiboken6/tests/samplebinding/ignorederefop_test.py new file mode 100644 index 000000000..feb78d045 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/ignorederefop_test.py @@ -0,0 +1,22 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import Reference + + +class TestLackOfDereferenceOperators (unittest.TestCase): + def testIf(self): + r = Reference() + self.assertFalse(hasattr(r, "__mul__")) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/implicitconv_numerical_test.py b/sources/shiboken6/tests/samplebinding/implicitconv_numerical_test.py new file mode 100644 index 000000000..081666281 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/implicitconv_numerical_test.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test case for inplicit converting C++ numeric types.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +import sys +import sample + +# Hardcode the limits of the underlying C-types depending on architecture and memory +# model (taking MSVC using LLP64 into account). +cIntMin = -2147483648 +cIntMax = 2147483647 +cLongMin = cIntMin +cLongMax = cIntMax +maxRepresentableInt = sys.maxsize +is64bitArchitecture = maxRepresentableInt > 2**32 +if is64bitArchitecture and sys.platform != 'win32': + cLongMin = -9223372036854775808 + cLongMax = 9223372036854775807 + + +class NumericTester(unittest.TestCase): + '''Helper class for numeric comparison testing''' + + def assertRaises(self, *args, **kwds): + if not hasattr(sys, "pypy_version_info"): + # PYSIDE-535: PyPy complains "Fatal RPython error: NotImplementedError" + return super().assertRaises(*args, **kwds) + + def check_value(self, source, expected, callback, desired_type=None): + result = callback(source) + self.assertEqual(result, expected) + + if desired_type: + self.assertEqual(type(result), desired_type) + + +class FloatImplicitConvert(NumericTester): + '''Test case for implicit converting C++ numeric types.''' + + def testFloatAsInt(self): + '''Float as Int''' + self.check_value(3.14, 3, sample.acceptInt, int) + self.assertRaises(OverflowError, sample.acceptInt, cIntMax + 400) + + def testFloatAsLong(self): + '''Float as Long''' + #C++ longs are python ints for us + self.check_value(3.14, 3, sample.acceptLong, int) + self.assertRaises(OverflowError, sample.acceptLong, cLongMax + 400) + + def testFloatAsUInt(self): + '''Float as unsigned Int''' + self.check_value(3.14, 3, sample.acceptUInt, int) + self.assertRaises(OverflowError, sample.acceptUInt, -3.14) + + def testFloatAsULong(self): + '''Float as unsigned Long''' + #FIXME Breaking with SystemError "bad argument to internal function" + self.check_value(3.14, 3, sample.acceptULong, int) + self.assertRaises(OverflowError, sample.acceptULong, -3.14) + + def testFloatAsDouble(self): + '''Float as double''' + self.check_value(3.14, 3.14, sample.acceptDouble, float) + + +class IntImplicitConvert(NumericTester): + '''Test case for implicit converting C++ numeric types.''' + + def testIntAsInt(self): + '''Int as Int''' + self.check_value(3, 3, sample.acceptInt, int) + + def testIntAsLong(self): + '''Int as Long''' + self.check_value(3, 3, sample.acceptLong, int) + + # cLongMax goes here as CPython implements int as a C long + self.check_value(cLongMax, cLongMax, sample.acceptLong, int) + self.check_value(cLongMin, cLongMin, sample.acceptLong, int) + + def testIntAsUInt(self): + '''Int as unsigned Int''' + self.check_value(3, 3, sample.acceptUInt, int) + self.assertRaises(OverflowError, sample.acceptUInt, -3) + + def testIntAsULong(self): + '''Int as unsigned Long''' + self.check_value(3, 3, sample.acceptULong, int) + self.assertRaises(OverflowError, sample.acceptULong, -3) + + def testFloatAsDouble(self): + '''Float as double''' + self.check_value(3.14, 3.14, sample.acceptDouble, float) + + +class LongImplicitConvert(NumericTester): + '''Test case for implicit converting C++ numeric types.''' + + def testLongAsInt(self): + '''Long as Int''' + self.check_value(24224, 24224, sample.acceptInt, int) + self.assertRaises(OverflowError, sample.acceptInt, cIntMax + 20) + + def testLongAsLong(self): + '''Long as Long''' + self.check_value(2405, 2405, sample.acceptLong, int) + self.assertRaises(OverflowError, sample.acceptLong, cLongMax + 20) + + def testLongAsUInt(self): + '''Long as unsigned Int''' + self.check_value(260, 260, sample.acceptUInt, int) + self.assertRaises(OverflowError, sample.acceptUInt, -42) + + def testLongAsULong(self): + '''Long as unsigned Long''' + self.check_value(128, 128, sample.acceptULong, int) + self.assertRaises(OverflowError, sample.acceptULong, -334) + + def testLongAsDouble(self): + '''Float as double''' + self.check_value(42, 42, sample.acceptDouble, float) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/implicitconv_test.py b/sources/shiboken6/tests/samplebinding/implicitconv_test.py new file mode 100644 index 000000000..ebafe0c52 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/implicitconv_test.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for implicit conversions''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ImplicitConv, ObjectType + + +class ImplicitConvTest(unittest.TestCase): + '''Test case for implicit conversions''' + + def testImplicitConversions(self): + '''Test if overloaded function call decisor takes implicit conversions into account.''' + ic = ImplicitConv.implicitConvCommon(ImplicitConv()) + self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorNone) + + ic = ImplicitConv.implicitConvCommon(3) + self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorOne) + self.assertEqual(ic.objId(), 3) + + ic = ImplicitConv.implicitConvCommon(ImplicitConv.CtorThree) + self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorThree) + + obj = ObjectType() + ic = ImplicitConv.implicitConvCommon(obj) + self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorObjectTypeReference) + + ic = ImplicitConv.implicitConvCommon(42.42) + self.assertEqual(ic.value(), 42.42) + + ic = ImplicitConv(None) + self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorPrimitiveType) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/inheritanceandscope_test.py b/sources/shiboken6/tests/samplebinding/inheritanceandscope_test.py new file mode 100644 index 000000000..28d62486a --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/inheritanceandscope_test.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for finding scope in cases involving inheritance.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import SampleNamespace + + +class ScopeAndInheritanceTest(unittest.TestCase): + '''Test cases for finding scope in cases involving inheritance.''' + + def testMethodCorrectlyWrapper(self): + '''A method returning a type declared in the scope of the method's + class parent must be found and the method correctly exported.''' + meth = getattr(SampleNamespace.DerivedFromNamespace, # noqa: F841 + 'methodReturningTypeFromParentScope') + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/injectcode_test.py b/sources/shiboken6/tests/samplebinding/injectcode_test.py new file mode 100644 index 000000000..f673a7807 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/injectcode_test.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for std::list container conversions''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import InjectCode + + +class MyInjectCode(InjectCode): + def __init__(self): + InjectCode.__init__(self) + self.multiplier = 2 + + def arrayMethod(self, values): + return self.multiplier * sum(values) + + +class InjectCodeTest(unittest.TestCase): + + @unittest.skipIf(hasattr(sys, "pypy_version_info"), + "PyPy type objects cannot be modified (yet) after creation") + def testTypeNativeBeginning_TypeTargetBeginning(self): + ic = InjectCode() + self.assertEqual(str(ic), "Hi! I'm the inject code dummy class.") + + def testFunctionTargetBeginning_FunctionTargetEnd(self): + ic = InjectCode() + ret = ic.simpleMethod1(2, 1) + self.assertEqual(ret, "4end") + ret = ic.simpleMethod1(4, 2) + self.assertEqual(ret, "7end") + + def testFunctionTargetBeginning(self): + ic = InjectCode() + ret = ic.simpleMethod2() + self.assertEqual(ret, "_end") + + def testArgsModification(self): + ic = InjectCode() + ret = ic.overloadedMethod(["1", "2", "3", "4"]) + self.assertEqual(ret, "1234") + ret = ic.overloadedMethod(2, 0.5) + self.assertEqual(ret, "2.5") + ret = ic.overloadedMethod(6, True) + self.assertEqual(ret, "6true") + + def testArgsModification2(self): + ic = InjectCode() + ret = ic.simpleMethod3(["1", "2", "3", "4"]) + self.assertEqual(ret, "1234") + + def testArgumentRemovalAndArgumentTypeModification(self): + '''A method has its first argument removed and the second modified.''' + ic = InjectCode() + values = (1, 2, 3, 4, 5) + result = ic.arrayMethod(values) + self.assertEqual(result, sum(values)) + + def testCallVirtualMethodWithArgumentRemovalAndArgumentTypeModification(self): + '''A virtual method has its first argument removed and the second modified.''' + ic = InjectCode() + values = (1, 2, 3, 4, 5) + result = ic.callArrayMethod(values) + self.assertEqual(result, sum(values)) + + def testCallReimplementedVirtualMethodWithArgumentRemovalAndArgumentTypeModification(self): + '''Calls a reimplemented virtual method that had its first argument removed + and the second modified.''' + ic = MyInjectCode() + values = (1, 2, 3, 4, 5) + result = ic.callArrayMethod(values) + self.assertEqual(result, ic.multiplier * sum(values)) + + def testUsageOfTypeSystemCheckVariableOnPrimitiveType(self): + '''When the sequence item is convertible to an integer -1 is returned, + or -2 if its not convertible.''' + ic = InjectCode() + values = (1, 2, 3, 4, '5', 6.7) + result = ic.arrayMethod(values) + + ints = [v for v in values if isinstance(v, int)] + floats = [-1 for v in values if isinstance(v, float)] + other = [-2 for v in values if not isinstance(v, int) and not isinstance(v, float)] + self.assertEqual(result, sum(ints + floats + other)) + + +class IntArrayTest(unittest.TestCase): + '''Test case for converting python sequence to int array''' + + def testBasic(self): + '''Shiboken::sequenceToIntArray - basic case''' + args = [1, 2, 3, 4] + ic = InjectCode() + self.assertEqual(sum(args) + len(args), ic.sumArrayAndLength(args)) + + def testEmpty(self): + '''Shiboken::sequenceToIntArray - empty sequence''' + args = [] + ic = InjectCode() + self.assertEqual(sum(args) + len(args), ic.sumArrayAndLength(args)) + + def testWithZero(self): + '''Shiboken::sequenceToIntArray - count only up to zero''' + args = [1, 2, 0, 3] + ic = InjectCode() + self.assertEqual(sum([1, 2]) + len([1, 2]), ic.sumArrayAndLength(args)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/innerclass_test.py b/sources/shiboken6/tests/samplebinding/innerclass_test.py new file mode 100644 index 000000000..721f33483 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/innerclass_test.py @@ -0,0 +1,23 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Derived + + +class TestInnerClass(unittest.TestCase): + def testInstaciate(self): + d = Derived.SomeInnerClass() # noqa: F841 + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/intlist_test.py b/sources/shiboken6/tests/samplebinding/intlist_test.py new file mode 100644 index 000000000..defa9ca71 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/intlist_test.py @@ -0,0 +1,80 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import IntList + + +class IntListTest(unittest.TestCase): + + def testAutoFunctionsToBaseList(self): + lst = IntList() + self.assertEqual(len(lst), 0) + lst.append(10) + self.assertEqual(lst[0], 10) + lst.append(20) + self.assertEqual(lst[1], 20) + lst.append(30) + self.assertEqual(lst[2], 30) + lst[1] = 25 + self.assertEqual(lst[0], 10) + self.assertEqual(lst[1], 25) + self.assertEqual(lst[2], 30) + self.assertEqual(len(lst), 3) + + def testIntListCtor_NoParams(self): + '''IntList constructor receives no parameter.''' + il = IntList() + self.assertEqual(len(il), 0) + self.assertEqual(il.constructorUsed(), IntList.NoParamsCtor) + + def testIntListCtor_int(self): + '''IntList constructor receives an integer.''' + value = 123 + il = IntList(value) + self.assertEqual(len(il), 1) + self.assertEqual(il[0], value) + self.assertEqual(il.constructorUsed(), IntList.IntCtor) + + def testIntListCtor_IntList(self): + '''IntList constructor receives an IntList object.''' + il1 = IntList(123) + il2 = IntList(il1) + self.assertEqual(len(il1), len(il2)) + for i in range(len(il1)): + self.assertEqual(il1[i], il2[i]) + self.assertEqual(il2.constructorUsed(), IntList.CopyCtor) + + def testIntListCtor_ListOfInts(self): + '''IntList constructor receives an integer list.''' + ints = [123, 456] + il = IntList(ints) + self.assertEqual(len(il), len(ints)) + for i in range(len(il)): + self.assertEqual(il[i], ints[i]) + self.assertEqual(il.constructorUsed(), IntList.ListOfIntCtor) + + def testIntListAttributeTypeCheck(self): + '''Attribute values to IntList.''' + il = IntList([0, 1, 2]) + self.assertEqual(len(il), 3) + il[0] = 123 + self.assertEqual(len(il), 3) + self.assertEqual(il[0], 123) + il[1] = 432.1 + self.assertEqual(len(il), 3) + self.assertEqual(il[1], int(432.1)) + self.assertRaises(TypeError, il.__setitem__, 2, '78') + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/intwrapper_test.py b/sources/shiboken6/tests/samplebinding/intwrapper_test.py new file mode 100644 index 000000000..d883adf47 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/intwrapper_test.py @@ -0,0 +1,39 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import IntWrapper + + +class IntWrapperTest(unittest.TestCase): + + def testOperators(self): + ten1 = IntWrapper(10) + ten2 = IntWrapper(10) + twenty = IntWrapper(20) + self.assertTrue(ten1 == ten2) + self.assertTrue(ten1 != twenty) + self.assertTrue(ten1 + ten2 == twenty) + self.assertTrue(ten1 - ten2 == IntWrapper(0)) + i = IntWrapper(ten1.toInt()) + i += ten2 + self.assertTrue(i == twenty) + i -= ten2 + self.assertTrue(i == ten1) + + def testAddPyMethodDef(self): + """Test of added free function (PYSIDE-1905).""" + i = IntWrapper(10) + self.assertEqual(i.add_ints(10, 20), 30) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/invalid_virtual_return_test.py b/sources/shiboken6/tests/samplebinding/invalid_virtual_return_test.py new file mode 100644 index 000000000..bb35b2bb1 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/invalid_virtual_return_test.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test case for returning invalid types in a virtual function''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import ObjectModel, ObjectType, ObjectView + +import warnings + + +class MyObject(ObjectType): + pass + + +class ListModelWrong(ObjectModel): + + def __init__(self, parent=None): + ObjectModel.__init__(self, parent) + self.obj = 0 + + def data(self): + warnings.simplefilter('error') + # Shouldn't segfault. Must set TypeError + return self.obj + + +class ModelWrongReturnTest(unittest.TestCase): + + def testWrongTypeReturn(self): + model = ListModelWrong() + view = ObjectView(model) + self.assertRaises(RuntimeWarning, view.getRawModelData) # calls model.data() + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/keep_reference_test.py b/sources/shiboken6/tests/samplebinding/keep_reference_test.py new file mode 100644 index 000000000..10591fec6 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/keep_reference_test.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectModel, ObjectView + + +class TestKeepReference(unittest.TestCase): + '''Test case for objects that keep references to other object without + owning them (e.g. model/view relationships).''' + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testReferenceCounting(self): + '''Tests reference count of model-like object referred by view-like objects.''' + model1 = ObjectModel() + refcount1 = sys.getrefcount(model1) + view1 = ObjectView() + view1.setModel(model1) + self.assertEqual(sys.getrefcount(view1.model()), refcount1 + 1) + + view2 = ObjectView() + view2.setModel(model1) + self.assertEqual(sys.getrefcount(view2.model()), refcount1 + 2) + + model2 = ObjectModel() + view2.setModel(model2) + self.assertEqual(sys.getrefcount(view1.model()), refcount1 + 1) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testReferenceCountingWhenDeletingReferrer(self): + '''Tests reference count of model-like object referred by deceased view-like object.''' + model = ObjectModel() + refcount1 = sys.getrefcount(model) + view = ObjectView() + view.setModel(model) + self.assertEqual(sys.getrefcount(view.model()), refcount1 + 1) + + del view + self.assertEqual(sys.getrefcount(model), refcount1) + + def testReferreedObjectSurvivalAfterContextEnd(self): + '''Model-like object assigned to a view-like object must survive + after get out of context.''' + def createModelAndSetToView(view): + model = ObjectModel() + model.setObjectName('created model') + view.setModel(model) + view = ObjectView() + createModelAndSetToView(view) + model = view.model() # noqa: F841 + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/list_test.py b/sources/shiboken6/tests/samplebinding/list_test.py new file mode 100644 index 000000000..b668bfd90 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/list_test.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for std::list container conversions''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ListUser, Point, PointF + + +class ExtendedListUser(ListUser): + def __init__(self): + ListUser.__init__(self) + self.create_list_called = False + + def createList(self): + self.create_list_called = True + return [2, 3, 5, 7, 13] + + +class ListConversionTest(unittest.TestCase): + '''Test case for std::list container conversions''' + + def testReimplementedVirtualMethodCall(self): + '''Test if a Python override of a virtual method is correctly called from C++.''' + lu = ExtendedListUser() + lst = lu.callCreateList() + self.assertTrue(lu.create_list_called) + self.assertEqual(type(lst), list) + for item in lst: + self.assertEqual(type(item), int) + + def testPrimitiveConversionInsideContainer(self): + '''Test primitive type conversion inside conversible std::list container.''' + cpx0 = complex(1.2, 3.4) + cpx1 = complex(5.6, 7.8) + lst = ListUser.createComplexList(cpx0, cpx1) + self.assertEqual(type(lst), list) + for item in lst: + self.assertEqual(type(item), complex) + self.assertEqual(lst, [cpx0, cpx1]) + + def testSumListIntegers(self): + '''Test method that sums a list of integer values.''' + lu = ListUser() + lst = [3, 5, 7] + result = lu.sumList(lst) + self.assertEqual(result, sum(lst)) + + def testSumListFloats(self): + '''Test method that sums a list of float values.''' + lu = ListUser() + lst = [3.3, 4.4, 5.5] + result = lu.sumList(lst) + self.assertEqual(result, sum(lst)) + + def testConversionInBothDirections(self): + '''Test converting a list from Python to C++ and back again.''' + lu = ListUser() + lst = [3, 5, 7] + lu.setList(lst) + result = lu.getList() + self.assertEqual(result, lst) + + def testConversionInBothDirectionsWithSimilarContainer(self): + '''Test converting a tuple, instead of the expected list, + from Python to C++ and back again.''' + lu = ListUser() + lst = (3, 5, 7) + lu.setList(lst) + result = lu.getList() + self.assertNotEqual(result, lst) + self.assertEqual(result, list(lst)) + + def testConversionOfListOfObjectsPassedAsArgument(self): + '''Calls method with a Python list of wrapped objects to be converted to a C++ list.''' + mult = 3 + pts0 = (Point(1.0, 2.0), Point(3.3, 4.4), Point(5, 6)) + pts1 = (Point(1.0, 2.0), Point(3.3, 4.4), Point(5, 6)) + ListUser.multiplyPointList(pts1, mult) + for pt0, pt1 in zip(pts0, pts1): + self.assertEqual(pt0.x() * mult, pt1.x()) + self.assertEqual(pt0.y() * mult, pt1.y()) + + def testConversionOfInvalidLists(self): + mult = 3 + pts = (Point(1.0, 2.0), 3, Point(5, 6)) + self.assertRaises(TypeError, ListUser.multiplyPointList, pts, mult) + + def testOverloadMethodReceivingRelatedContainerTypes(self): + self.assertEqual(ListUser.ListOfPointF, ListUser.listOfPoints([PointF()])) + self.assertEqual(ListUser.ListOfPoint, ListUser.listOfPoints([Point()])) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/lock_test.py b/sources/shiboken6/tests/samplebinding/lock_test.py new file mode 100644 index 000000000..acd47634a --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/lock_test.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Simple test with a blocking C++ method that should allow python + threads to run.''' + +import os +import sys +import threading +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Bucket + + +class Unlocker(threading.Thread): + + def __init__(self, bucket): + threading.Thread.__init__(self) + self.bucket = bucket + + def run(self): + while not self.bucket.locked(): + pass + + self.bucket.unlock() + + +class MyBucket(Bucket): + + def __init__(self): + Bucket.__init__(self) + + def virtualBlockerMethod(self): + self.lock() + return True + + +class TestLockUnlock(unittest.TestCase): + + def testBasic(self): + '''Locking in C++ and releasing in a python thread''' + bucket = Bucket() + unlocker = Unlocker(bucket) + + unlocker.start() + bucket.lock() + unlocker.join() + + def testVirtualBlocker(self): + '''Same as the basic case but blocker method is a C++ virtual called from C++.''' + bucket = Bucket() + unlocker = Unlocker(bucket) + + unlocker.start() + result = bucket.callVirtualBlockerMethodButYouDontKnowThis() + unlocker.join() + self.assertTrue(result) + + def testReimplementedVirtualBlocker(self): + '''Same as the basic case but blocker method is a C++ virtual reimplemented + in Python and called from C++.''' + mybucket = MyBucket() + unlocker = Unlocker(mybucket) + + unlocker.start() + result = mybucket.callVirtualBlockerMethodButYouDontKnowThis() + unlocker.join() + self.assertTrue(result) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/map_test.py b/sources/shiboken6/tests/samplebinding/map_test.py new file mode 100644 index 000000000..fa99ad2e7 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/map_test.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for std::map container conversions''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import MapUser + + +class ExtendedMapUser(MapUser): + def __init__(self): + MapUser.__init__(self) + self.create_map_called = False + + def createMap(self): + self.create_map_called = True + return {'two': (complex(2.2, 2.2), 2), + 'three': (complex(3.3, 3.3), 3), + 'five': (complex(5.5, 5.5), 5), + 'seven': (complex(7.7, 7.7), 7)} + + +class MapConversionTest(unittest.TestCase): + '''Test case for std::map container conversions''' + + def testReimplementedVirtualMethodCall(self): + '''Test if a Python override of a virtual method is correctly called from C++.''' + mu = ExtendedMapUser() + map_ = mu.callCreateMap() + self.assertTrue(mu.create_map_called) + self.assertEqual(type(map_), dict) + for key, value in map_.items(): + self.assertEqual(type(key), str) + self.assertEqual(type(value[0]), complex) + self.assertEqual(type(value[1]), int) + + def testConversionInBothDirections(self): + '''Test converting a map from Python to C++ and back again.''' + mu = MapUser() + map_ = {'odds': [2, 4, 6], 'evens': [3, 5, 7], 'primes': [3, 4, 6]} + mu.setMap(map_) + result = mu.getMap() + self.assertEqual(result, map_) + + def testConversionMapIntKeyValueTypeValue(self): + '''C++ signature: MapUser::passMapIntValueType(const std::map<int, const ByteArray>&)''' + mu = MapUser() + map_ = {0: 'string'} + result = mu.passMapIntValueType(map_) + self.assertEqual(map_, result) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/metaclass_test.py b/sources/shiboken6/tests/samplebinding/metaclass_test.py new file mode 100644 index 000000000..4d7eeda96 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/metaclass_test.py @@ -0,0 +1,52 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Point + + +class MetaA(type): + pass + + +class A(object): + __metaclass__ = MetaA + + +MetaB = type(Point) +B = Point + + +class MetaC(MetaA, MetaB): + pass + + +class C(A, B): + __metaclass__ = MetaC + + +class D(C): + pass + + +class TestMetaClass(unittest.TestCase): + def testIt(self): + w1 = C() # works + w1.setX(1) + w1.setY(2) + + w2 = D() # should work! + w2.setX(3) + w2.setY(4) + + w3 = w1 + w2 + self.assertEqual(w3.x(), 4) + self.assertEqual(w3.y(), 6) diff --git a/sources/shiboken6/tests/samplebinding/mi_virtual_methods_test.py b/sources/shiboken6/tests/samplebinding/mi_virtual_methods_test.py new file mode 100644 index 000000000..8d324db59 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/mi_virtual_methods_test.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for virtual methods in multiple inheritance scenarios''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import VirtualMethods, ObjectType, Event + + +class ImplementsNone(ObjectType, VirtualMethods): + '''Implements no virtual methods''' + + def __init__(self): + ObjectType.__init__(self) + VirtualMethods.__init__(self) + + +class ImplementsBoth(ObjectType, VirtualMethods): + '''Implements ObjectType.event and VirtualMethods.sum1''' + + def __init__(self): + ObjectType.__init__(self) + VirtualMethods.__init__(self) + self.event_processed = False + + def event(self, event): + self.event_processed = True + return True + + def sum1(self, arg0, arg1, arg2): + return (arg0 + arg1 + arg2) * 2 + + +class CppVirtualTest(unittest.TestCase): + '''Virtual method defined in c++ called from C++''' + + def testCpp(self): + '''C++ calling C++ virtual method in multiple inheritance scenario''' + obj = ImplementsNone() + self.assertTrue(ObjectType.processEvent([obj], Event(Event.BASIC_EVENT))) + self.assertRaises(AttributeError, getattr, obj, 'event_processed') + + self.assertEqual(obj.callSum0(1, 2, 3), 6) + + +class PyVirtualTest(unittest.TestCase): + '''Virtual method reimplemented in python called from C++''' + + def testEvent(self): + '''C++ calling Python reimplementation of virtual in multiple inheritance''' + obj = ImplementsBoth() + self.assertTrue(ObjectType.processEvent([obj], Event(Event.BASIC_EVENT))) + self.assertTrue(obj.event_processed) + + self.assertEqual(obj.callSum1(1, 2, 3), 12) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/mixed_mi_test.py b/sources/shiboken6/tests/samplebinding/mixed_mi_test.py new file mode 100644 index 000000000..fa8481600 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/mixed_mi_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for multiple inheritance in mixed Python/C++ scenarios''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType + + +class Base(object): + '''Base Python class''' + + def __init__(self): + self.name = '' + + def pythonName(self): + return self.name + + def setPythonName(self, name): + self.name = name + + +class Child(Base, ObjectType): + '''Dummy class with mixed parents''' + + def __init__(self): + Base.__init__(self) + ObjectType.__init__(self) + + +class MixedInheritanceTest(unittest.TestCase): + + def testMixed(self): + '''Mixed Python/C++ multiple inheritance''' + obj = Child() + + obj.setObjectName('aaa') + self.assertEqual(obj.objectName(), 'aaa') + + obj.setPythonName('python') + self.assertEqual(obj.pythonName(), 'python') + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/modelindex_test.py b/sources/shiboken6/tests/samplebinding/modelindex_test.py new file mode 100644 index 000000000..e23503eff --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/modelindex_test.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ModelIndex, ReferentModelIndex, PersistentModelIndex + + +class TestCastOperator(unittest.TestCase): + + def testCastOperatorReturningValue(self): + index = PersistentModelIndex() + index.setValue(123) + self.assertEqual(index.value(), 123) + self.assertEqual(index.value(), ModelIndex.getValue(index)) + + def testCastOperatorReturningReference(self): + index = ReferentModelIndex() + index.setValue(123) + self.assertEqual(index.value(), 123) + self.assertEqual(index.value(), ModelIndex.getValue(index)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/modelview_test.py b/sources/shiboken6/tests/samplebinding/modelview_test.py new file mode 100644 index 000000000..b5663a04e --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/modelview_test.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test case for objects that keep references to other object without owning them + (e.g. model/view relationships).''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import ObjectModel, ObjectType, ObjectView + + +object_name = 'test object' + + +class MyObject(ObjectType): + pass + + +class ListModelKeepsReference(ObjectModel): + def __init__(self, parent=None): + ObjectModel.__init__(self, parent) + self.obj = MyObject() + self.obj.setObjectName(object_name) + + def data(self): + return self.obj + + +class ListModelDoesntKeepsReference(ObjectModel): + def data(self): + obj = MyObject() + obj.setObjectName(object_name) + return obj + + +class ModelViewTest(unittest.TestCase): + + def testListModelDoesntKeepsReference(self): + model = ListModelDoesntKeepsReference() + view = ObjectView(model) + obj = view.getRawModelData() + self.assertEqual(type(obj), MyObject) + self.assertEqual(obj.objectName(), object_name) + + def testListModelKeepsReference(self): + model = ListModelKeepsReference() + view = ObjectView(model) + obj = view.getRawModelData() + self.assertEqual(type(obj), MyObject) + self.assertEqual(obj.objectName(), object_name) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/modifications_test.py b/sources/shiboken6/tests/samplebinding/modifications_test.py new file mode 100644 index 000000000..dced14396 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/modifications_test.py @@ -0,0 +1,224 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for method modifications performed as described on type system. ''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Modifications, Point, ByteArray + + +class ExtModifications(Modifications): + def __init__(self): + Modifications.__init__(self) + self.multiplier = 3.0 + self.increment = 10.0 + + def name(self): + return 'ExtModifications' + + def differenceOfPointCoordinates(self, point): + ok, res = Modifications.differenceOfPointCoordinates(self, point) + return ok, res * self.multiplier + self.increment + + +class ModificationsTest(unittest.TestCase): + '''Test cases for method modifications performed as described on type system. ''' + + def setUp(self): + self.mods = Modifications() + + def tearDown(self): + del self.mods + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + def testRenamedMethodAvailability(self): + '''Test if Modification class really have renamed the 'className' + virtual method to 'name'.''' + self.assertTrue('className' not in dir(Modifications)) + self.assertTrue('name' in dir(Modifications)) + + def testReimplementationOfRenamedVirtualMethod(self): + '''Test if class inheriting from Modification class have the reimplementation + of renamed virtual method called.''' + em = ExtModifications() + self.assertEqual(self.mods.name(), 'Modifications') + self.assertEqual(em.name(), 'ExtModifications') + + def testRegularMethodRenaming(self): + '''Test if Modifications::cppMultiply was correctly renamed to calculateArea.''' + self.assertTrue('cppMultiply' not in dir(Modifications)) + self.assertTrue('calculateArea' in dir(Modifications)) + self.assertEqual(self.mods.calculateArea(3, 6), 3 * 6) + + def testRegularMethodRemoval(self): + '''Test if 'Modifications::exclusiveCppStuff' was removed from Python bindings.''' + self.assertTrue('exclusiveCppStuff' not in dir(Modifications)) + + def testArgumentRemoval(self): + '''Test if second argument of Modifications::doublePlus(int, int) was removed.''' + self.assertRaises(TypeError, self.mods.doublePlus, 3, 7) + self.assertEqual(self.mods.doublePlus(7), 14) + + def testDefaultValueRemoval(self): + '''Test if default value was removed from first argument of + Modifications::increment(int).''' + self.assertRaises(TypeError, self.mods.increment) + self.assertEqual(self.mods.increment(7), 8) + + def testDefaultValueReplacement(self): + '''Test if default values for both arguments of Modifications::power(int, int) + were modified.''' + # original default values: int power(int base = 1, int exponent = 0); + self.assertNotEqual(self.mods.power(4), 1) + # modified default values: int power(int base = 2, int exponent = 1); + self.assertEqual(self.mods.power(), 2) + self.assertEqual(self.mods.power(3), 3) + self.assertEqual(self.mods.power(5, 3), 5**3) + + def testSetNewDefaultValue(self): + '''Test if default value was correctly set to 10 for first argument of + Modifications::timesTen(int).''' + self.assertEqual(self.mods.timesTen(7), 70) + self.assertEqual(self.mods.timesTen(), 100) + + def testArgumentRemovalAndReturnTypeModificationWithTypesystemTemplates1(self): + '''Test modifications to method signature and return value using type + system templates (case 1).''' + result, ok = self.mods.pointToPair(Point(2, 5)) + self.assertEqual(type(ok), bool) + self.assertEqual(type(result), tuple) + self.assertEqual(len(result), 2) + self.assertEqual(type(result[0]), float) + self.assertEqual(type(result[1]), float) + self.assertEqual(result[0], 2.0) + self.assertEqual(result[1], 5.0) + + def testArgumentRemovalAndReturnTypeModificationWithTypesystemTemplates2(self): + '''Test modifications to method signature and return value using + type system templates (case 2).''' + result, ok = self.mods.multiplyPointCoordsPlusValue(Point(2, 5), 4.1) + self.assertEqual(type(ok), bool) + self.assertEqual(type(result), float) + self.assertEqual(result, 14.1) + + def testOverloadedMethodModifications(self): + '''Tests modifications to an overloaded method''' + # overloaded(int, bool[removed], int, double) + self.assertEqual(self.mods.overloaded(1, 2, 3.1), Modifications.Overloaded_ibid) + # overloaded(int, bool, int[removed,default=321], int) + self.assertEqual(self.mods.overloaded(1, True, 2), Modifications.Overloaded_ibii) + # the others weren't modified + self.assertEqual(self.mods.overloaded(1, True, 2, False), Modifications.Overloaded_ibib) + self.assertEqual(self.mods.overloaded(1, False, 2, Point(3, 4)), + Modifications.Overloaded_ibiP) + self.assertRaises(TypeError, self.mods.overloaded, 1, True, Point(2, 3), Point(4, 5)) + self.assertEqual(self.mods.over(1, True, Point(2, 3), Point(4, 5)), + Modifications.Overloaded_ibPP) + + def testPointArrayModification(self): + points = (Point(1, 1), Point(2, 2)) + summedPoint = Point(1, 1) + Point(2, 2) + self.assertEqual(self.mods.sumPointArray(points), summedPoint) + + def testTypeSystemVariableReplacementInFunctionModification(self): + ba = ByteArray('12345') + self.assertEqual(self.mods.getSize(ba), len(ba)) + self.assertEqual(self.mods.getSize(ba, 20), 20) + + def testNoNulPointerTag(self): + point = Point(12, 34) + self.assertEqual(self.mods.sumPointCoordinates(point), 12 + 34) + self.assertRaises(TypeError, self.mods.sumPointCoordinates, None) + + def testNonConversionRuleForArgumentWithDefaultValue(self): + status, obj = self.mods.nonConversionRuleForArgumentWithDefaultValue() + self.assertTrue(status) + self.assertEqual(obj, self.mods.getObject()) + self.assertEqual(obj.objectName(), 'MyObject') + + def testInjectCodeWithConversionVariableForUserPrimitive(self): + self.assertTrue(Modifications.invertBoolean(False)) + self.assertFalse(Modifications.invertBoolean(True)) + + def testConversionRuleForReturnType(self): + x, y = 11, 2 + diff = float(abs(x - y)) + point = Point(x, y) + + ok, res = self.mods.differenceOfPointCoordinates(point) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, diff) + + ok, res = self.mods.callDifferenceOfPointCoordinates(point) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, diff) + + ok, res = self.mods.differenceOfPointCoordinates(None) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, 0.0) + + ok, res = self.mods.callDifferenceOfPointCoordinates(None) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, 0.0) + + def testConversionRuleForReturnTypeOnExtendedClass(self): + x, y = 11, 2 + diff = float(abs(x - y)) + point = Point(x, y) + em = ExtModifications() + + ok, res = em.differenceOfPointCoordinates(point) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, diff * em.multiplier + em.increment) + + ok, res = em.callDifferenceOfPointCoordinates(point) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, diff * em.multiplier + em.increment) + + ok, res = em.differenceOfPointCoordinates(None) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, em.increment) + + ok, res = em.callDifferenceOfPointCoordinates(None) + self.assertTrue(isinstance(ok, bool)) + self.assertTrue(isinstance(res, float)) + self.assertEqual(res, em.increment) + + def testDefaultValueModifications(self): + # PSYIDE-1095: setEnumValue() has the default value modified to + # calling defaultEnumValue() which returns Modifications.TestEnumValue2. + # This used to generated broken code since defaultEnumValue() was + # qualified by the enum scope. + modifications = Modifications() + modifications.setEnumValue() + self.assertEqual(modifications.enumValue(), Modifications.TestEnumValue2) + + def testSetGetAttro(self): + modifications = Modifications() + self.assertFalse(modifications.wasSetAttroCalled()) + setattr(modifications, 'Foo', 'Bar') + self.assertTrue(modifications.wasSetAttroCalled()) + self.assertEqual(getattr(modifications, 'Foo'), 'Bar') + self.assertTrue(modifications.wasGetAttroCalled()) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/modified_constructor_test.py b/sources/shiboken6/tests/samplebinding/modified_constructor_test.py new file mode 100644 index 000000000..9791a3491 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/modified_constructor_test.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests cases for ConstructorWithModifiedArgument class.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ModifiedConstructor + + +class ConstructorWithModifiedArgumentTest(unittest.TestCase): + '''Test cases for ConstructorWithModifiedArgument class.''' + + def testConstructorWithModifiedArgument(self): + sampleClass = ModifiedConstructor("10") + self.assertTrue(sampleClass.retrieveValue(), 10) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/modifiedvirtualmethods_test.py b/sources/shiboken6/tests/samplebinding/modifiedvirtualmethods_test.py new file mode 100644 index 000000000..dcb487f1a --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/modifiedvirtualmethods_test.py @@ -0,0 +1,233 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for modified virtual methods.''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import VirtualMethods, Str + + +class ExtendedVirtualMethods(VirtualMethods): + def __init__(self): + VirtualMethods.__init__(self) + self.name_called = False + self.sum0_called = False + self.sum1_called = False + self.sum2_called = False + self.sum3_called = False + self.sum4_called = False + self.sumThree_called = False + self.callMe_called = 0 + self.multiplier = 12345 + + def sum0(self, a0, a1, a2): + self.sum0_called = True + return VirtualMethods.sumThree(self, a0, a1, a2) * self.multiplier + + def sumThree(self, a0, a1, a2): + self.sumThree_called = True + return VirtualMethods.sumThree(self, a0, a1, a2) * self.multiplier + + def sum1(self, a0, a1, a2): + self.sum1_called = True + return VirtualMethods.sum1(self, a0, a1, a2) * self.multiplier + + def sum2(self, a0, a1): + self.sum2_called = True + return VirtualMethods.sum2(self, a0, a1) * self.multiplier + + def sum3(self, a0, a1): + self.sum3_called = True + return VirtualMethods.sum3(self, a0, a1) * self.multiplier + + def sum4(self, a0, a1): + self.sum4_called = True + return VirtualMethods.sum4(self, a0, a1) * self.multiplier + + def name(self): + self.name_called = True + return Str('ExtendedVirtualMethods') + + def callMe(self): + self.callMe_called += 1 + + def getMargins(self): + return tuple([m * 2 for m in VirtualMethods.getMargins(self)]) + + +class VirtualMethodsTest(unittest.TestCase): + '''Test case for modified virtual methods.''' + + def setUp(self): + self.vm = VirtualMethods() + self.evm = ExtendedVirtualMethods() + + def tearDown(self): + del self.vm + del self.evm + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + def testModifiedVirtualMethod0(self): + '''Renamed virtual method.''' + a0, a1, a2 = 2, 3, 5 + result0 = self.vm.callSum0(a0, a1, a2) + result1 = self.vm.sumThree(a0, a1, a2) + self.assertEqual(result0, a0 + a1 + a2) + self.assertEqual(result0, result1) + self.assertRaises(AttributeError, getattr, self.vm, 'sum0') + + def testReimplementedModifiedVirtualMethod0(self): + '''Override of a renamed virtual method.''' + a0, a1, a2 = 2, 3, 5 + result0 = self.vm.callSum0(a0, a1, a2) + result1 = self.vm.sumThree(a0, a1, a2) + result2 = self.evm.callSum0(a0, a1, a2) + self.assertEqual(result0, result1) + self.assertEqual(result0 * self.evm.multiplier, result2) + self.assertTrue(self.evm.sumThree_called) + self.assertFalse(self.evm.sum0_called) + + def testModifiedVirtualMethod1(self): + '''Virtual method with three arguments and the last one + changed to have the default value set to 1000.''' + a0, a1, a2 = 2, 3, 5 + result0 = self.vm.sum1(a0, a1) + self.assertEqual(result0, a0 + a1 + 1000) + result1 = self.vm.sum1(a0, a1, a2) + result2 = self.vm.callSum1(a0, a1, a2) + self.assertEqual(result1, result2) + + def testReimplementedModifiedVirtualMethod1(self): + '''Override of the virtual method with three arguments and + the last one changed to have the default value set to 1000.''' + a0, a1 = 2, 3 + result0 = self.vm.sum1(a0, a1) + result1 = self.evm.callSum1(a0, a1, 1000) + self.assertEqual(result0 * self.evm.multiplier, result1) + self.assertTrue(self.evm.sum1_called) + + def testModifiedVirtualMethod2(self): + '''Virtual method originally with three arguments, the last + one was removed and the default value set to 2000.''' + a0, a1 = 1, 2 + result0 = self.vm.sum2(a0, a1) + self.assertEqual(result0, a0 + a1 + 2000) + result1 = self.vm.sum2(a0, a1) + result2 = self.vm.callSum2(a0, a1, 2000) + self.assertEqual(result1, result2) + self.assertRaises(TypeError, self.vm.sum2, 1, 2, 3) + + def testReimplementedModifiedVirtualMethod2(self): + '''Override of the virtual method originally with three arguments, + the last one was removed and the default value set to 2000.''' + a0, a1 = 1, 2 + ignored = 54321 + result0 = self.vm.sum2(a0, a1) + result1 = self.evm.callSum2(a0, a1, ignored) + self.assertEqual(result0 * self.evm.multiplier, result1) + self.assertTrue(self.evm.sum2_called) + + def testModifiedVirtualMethod3(self): + '''Virtual method originally with three arguments have the second + one removed and replaced by custom code that replaces it by the sum + of the first and the last arguments.''' + a0, a1 = 1, 2 + result0 = self.vm.sum3(a0, a1) + self.assertEqual(result0, a0 + (a0 + a1) + a1) + result1 = self.vm.callSum3(a0, 10, a1) + self.assertNotEqual(result0, result1) + result2 = self.vm.callSum3(a0, a0 + a1, a1) + self.assertEqual(result0, result2) + self.assertRaises(TypeError, self.vm.sum3, 1, 2, 3) + + def testReimplementedModifiedVirtualMethod3(self): + '''Override of the virtual method originally with three arguments + have the second one removed and replaced by custom code that + replaces it by the sum of the first and the last arguments.''' + a0, a1 = 1, 2 + ignored = 54321 + result0 = self.vm.sum3(a0, a1) + result1 = self.evm.callSum3(a0, ignored, a1) + self.assertEqual(result0 * self.evm.multiplier, result1) + self.assertTrue(self.evm.sum3_called) + + def testModifiedVirtualMethod4(self): + '''Virtual method originally with three arguments, the + last one was removed and the default value set to 3000.''' + a0, a1 = 1, 2 + default_value = 3000 + result0 = self.vm.sum4(a0, a1) + self.assertEqual(result0, a0 + default_value + a1) + removed_arg_value = 100 + result1 = self.vm.callSum4(a0, removed_arg_value, a1) + self.assertEqual(result1, a0 + removed_arg_value + a1) + self.assertRaises(TypeError, self.vm.sum4, 1, 2, 3) + + def testReimplementedModifiedVirtualMethod4(self): + '''Override of the virtual method originally with three arguments, + the last one was removed and the default value set to 3000. + The method was modified with code injection on the binding override + (the one that receives calls from C++ with the original signature + and forwards it to Python overrides) that subtracts the value of the + second argument (removed in Python) from the value of the first + before sending them to Python.''' + a0, a1 = 1, 2 + removed_arg_value = 2011 + default_value = 3000 + result = self.evm.callSum4(a0, removed_arg_value, a1) + self.assertEqual(result, + (a0 - removed_arg_value + a1 + default_value) * self.evm.multiplier) + self.assertTrue(self.evm.sum4_called) + + def testOverridenMethodResultModification(self): + '''Injected code modifies the result of a call to a virtual + method overridden in Python.''' + orig_name = self.vm.callName() + self.assertEqual(orig_name, 'VirtualMethods') + name = self.evm.callName() + self.assertEqual(name, 'PimpedExtendedVirtualMethods') + self.assertEqual(name, Str('PimpedExtendedVirtualMethods')) + self.assertTrue(self.evm.name_called) + + def testInjectCodeCallsPythonVirtualMethodOverride(self): + '''When injected code calls the Python override by itself + no code for the method call should be generated.''' + self.evm.callCallMe() + self.assertEqual(self.evm.callMe_called, 1) + + def testAllArgumentsRemoved(self): + values = (10, 20, 30, 40) + self.vm.setMargins(*values) + self.assertEqual(self.vm.getMargins(), values) + + def testAllArgumentsRemovedCallVirtual(self): + values = (10, 20, 30, 40) + self.vm.setMargins(*values) + self.assertEqual(self.vm.callGetMargins(), values) + + def testExtendedAllArgumentsRemoved(self): + values = (10, 20, 30, 40) + self.evm.setMargins(*values) + double = tuple([m * 2 for m in values]) + self.assertEqual(self.evm.getMargins(), double) + + def testExtendedAllArgumentsRemovedCallVirtual(self): + values = (10, 20, 30, 40) + self.evm.setMargins(*values) + double = tuple([m * 2 for m in values]) + self.assertEqual(self.evm.callGetMargins(), double) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/multi_cpp_inheritance_test.py b/sources/shiboken6/tests/samplebinding/multi_cpp_inheritance_test.py new file mode 100644 index 000000000..fc6b26c3f --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/multi_cpp_inheritance_test.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for multiple inheritance''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType, Point, Str + + +class SimpleUseCase(ObjectType, Str): + def __init__(self, name): + ObjectType.__init__(self) + Str.__init__(self, name) + + +class SimpleUseCaseReverse(Str, ObjectType): + def __init__(self, name): + ObjectType.__init__(self) + Str.__init__(self, name) + + +class SimpleUseCase2(SimpleUseCase): + def __init__(self, name): + SimpleUseCase.__init__(self, name) + + +class ComplexUseCase(SimpleUseCase2, Point): + def __init__(self, name): + SimpleUseCase2.__init__(self, name) + Point.__init__(self) + + +class ComplexUseCaseReverse(Point, SimpleUseCase2): + def __init__(self, name): + SimpleUseCase2.__init__(self, name) + Point.__init__(self) + + +class MultipleCppDerivedTest(unittest.TestCase): + def testInstantiation(self): + s = SimpleUseCase("Hi") + self.assertEqual(s, "Hi") + s.setObjectName(s) + self.assertEqual(s.objectName(), "Hi") + + def testInstantiation2(self): + s = SimpleUseCase2("Hi") + self.assertEqual(s, "Hi") + s.setObjectName(s) + self.assertEqual(s.objectName(), "Hi") + + def testComplexInstantiation(self): + c = ComplexUseCase("Hi") + self.assertEqual(c, "Hi") + c.setObjectName(c) + self.assertEqual(c.objectName(), "Hi") + c.setX(2) + self.assertEqual(c.x(), 2) + + +class MultipleCppDerivedReverseTest(unittest.TestCase): + def testInstantiation(self): + s = SimpleUseCaseReverse("Hi") + self.assertEqual(s, "Hi") + s.setObjectName(s) + self.assertEqual(s.objectName(), "Hi") + + def testInstantiation2(self): + s = SimpleUseCase2("Hi") + self.assertEqual(s, "Hi") + s.setObjectName(s) + self.assertEqual(s.objectName(), "Hi") + + def testComplexInstantiation(self): + # PYSIDE-1564: This test can no longer work because of this MRO: + # ('ComplexUseCaseReverse', 'Point', 'SimpleUseCase2', 'SimpleUseCase', + # 'ObjectType', 'Str', 'Object', 'object') + # By multiple inheritance Point would be called first but has no argument. + with self.assertRaises(TypeError): + c = ComplexUseCaseReverse("Hi") # noqa: F841 + # c.setObjectName(c) + # self.assertEqual(c.objectName(), "Hi") + # c.setX(2); + # self.assertEqual(c, Point(2, 0)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/multiple_derived_test.py b/sources/shiboken6/tests/samplebinding/multiple_derived_test.py new file mode 100644 index 000000000..7497714a8 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/multiple_derived_test.py @@ -0,0 +1,223 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for multiple inheritance''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Base1, Base2 +from sample import MDerived1, MDerived2, MDerived3, MDerived4, MDerived5, SonOfMDerived1 + + +class ExtMDerived1(MDerived1): + def __init__(self): + MDerived1.__init__(self) + self.multiplier = 20 + self.base2Method_called = False + + def base2Method(self): + return Base2.base2Method(self) * self.multiplier + + +class MultipleDerivedTest(unittest.TestCase): + '''Test cases for multiple inheritance''' + + def testIsInstance(self): + '''MDerived1 is instance of its parents Base1 and Base2.''' + a = MDerived1() + self.assertTrue(isinstance(a, MDerived1)) + self.assertTrue(isinstance(a, Base1)) + self.assertTrue(isinstance(a, Base2)) + + def testIsSubclass(self): + '''MDerived1 is subclass of its parents Base1 and Base2.''' + self.assertTrue(issubclass(MDerived1, Base1)) + self.assertTrue(issubclass(MDerived1, Base2)) + + def testCallToFunctionWithBase1ArgumentThatCastsBackToMDerived1(self): + '''MDerived1 is passed as an Base1 argument to a method that returns + it casted back to MDerived1.''' + a = MDerived1() + b = MDerived1.transformFromBase1(a) + self.assertEqual(a, b) + + def testCallToFunctionWithBase2ArgumentThatCastsBackToMDerived1(self): + '''MDerived1 is passed as an Base2 argument to a method that returns + it casted back to MDerived1.''' + a = MDerived1() + b = MDerived1.transformFromBase2(a) + self.assertEqual(a, b) + + def testPythonClassIsInstance(self): + '''Python defined class ExtMDerived1 is instance of its parents + MDerived1, Base1 and Base2.''' + a = ExtMDerived1() + self.assertTrue(isinstance(a, ExtMDerived1)) + self.assertTrue(isinstance(a, MDerived1)) + self.assertTrue(isinstance(a, Base1)) + self.assertTrue(isinstance(a, Base2)) + + def testPythonClassIsSubclass(self): + '''Python defined class ExtMDerived1 is subclass of its parents + MDerived1, Base1 and Base2.''' + self.assertTrue(issubclass(ExtMDerived1, MDerived1)) + self.assertTrue(issubclass(ExtMDerived1, Base1)) + self.assertTrue(issubclass(ExtMDerived1, Base2)) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testCastFromMDerived1ToBases(self): + '''MDerived1 is casted by C++ to its parents and the binding must return the + MDerived1 wrapper.''' + a = MDerived1() + refcnt = sys.getrefcount(a) + b1 = a.castToBase1() + b2 = a.castToBase2() + self.assertTrue(isinstance(b1, MDerived1)) + self.assertTrue(isinstance(b2, MDerived1)) + self.assertEqual(a, b1) + self.assertEqual(a, b2) + self.assertEqual(sys.getrefcount(a), refcnt + 2) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testCastFromExtMDerived1ToMDerived1Bases(self): + '''Python defined class ExtMDerived1 is casted by C++ to MDerived1 parents + and the binding must return the correct ExtMDerived1 instance.''' + a = ExtMDerived1() + refcnt = sys.getrefcount(a) + b1 = a.castToBase1() + self.assertTrue(isinstance(b1, MDerived1)) + self.assertTrue(isinstance(b1, ExtMDerived1)) + b2 = a.castToBase2() + self.assertTrue(isinstance(b2, MDerived1)) + self.assertTrue(isinstance(b2, ExtMDerived1)) + self.assertEqual(a, b1) + self.assertEqual(a, b2) + self.assertEqual(sys.getrefcount(a), refcnt + 2) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testCastFromSonOfMDerived1ToBases(self): + '''SonOfMDerived1 is casted by C++ to its parents and the binding must return + the SonOfMDerived1 wrapper.''' + a = SonOfMDerived1() + refcnt = sys.getrefcount(a) + md1 = a.castToMDerived1() + b1 = a.castToBase1() + b2 = a.castToBase2() + self.assertTrue(isinstance(md1, SonOfMDerived1)) + self.assertTrue(isinstance(b2, SonOfMDerived1)) + self.assertTrue(isinstance(b2, SonOfMDerived1)) + self.assertEqual(a, md1) + self.assertEqual(a, b1) + self.assertEqual(a, b2) + self.assertEqual(sys.getrefcount(a), refcnt + 3) + + def testReimplementedBase2VirtualMethodOnClassInheritingFromMDerived1(self): + a = ExtMDerived1() + value = a.base2Method() + self.assertTrue(value, Base2.base2Method(a) * a.multiplier) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testCastFromMDerived2ToBases(self): + '''MDerived2 is casted by C++ to its parents and the binding must + return the MDerived2 wrapper.''' + a = MDerived2() + refcnt = sys.getrefcount(a) + b3 = a.castToBase3() + b4 = a.castToBase4() + b5 = a.castToBase5() + b6 = a.castToBase6() + self.assertTrue(isinstance(b3, MDerived2)) + self.assertTrue(isinstance(b4, MDerived2)) + self.assertTrue(isinstance(b5, MDerived2)) + self.assertTrue(isinstance(b6, MDerived2)) + self.assertEqual(a, b3) + self.assertEqual(a, b4) + self.assertEqual(a, b5) + self.assertEqual(a, b6) + self.assertEqual(sys.getrefcount(a), refcnt + 4) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testCastFromMDerived3ToBases(self): + '''MDerived3 is casted by C++ to its parents and the binding must + return the MDerived3 wrapper.''' + a = MDerived3() + refcnt = sys.getrefcount(a) + md1 = a.castToMDerived1() + md2 = a.castToMDerived2() + b1 = a.castToBase1() + b2 = a.castToBase2() + b3 = a.castToBase3() + b4 = a.castToBase4() + b5 = a.castToBase5() + b6 = a.castToBase6() + self.assertTrue(isinstance(md1, MDerived3)) + self.assertTrue(isinstance(md2, MDerived3)) + self.assertTrue(isinstance(b1, MDerived3)) + self.assertTrue(isinstance(b2, MDerived3)) + self.assertTrue(isinstance(b3, MDerived3)) + self.assertTrue(isinstance(b4, MDerived3)) + self.assertTrue(isinstance(b5, MDerived3)) + self.assertTrue(isinstance(b6, MDerived3)) + self.assertEqual(a, md1) + self.assertEqual(a, md2) + self.assertEqual(a, b1) + self.assertEqual(a, b2) + self.assertEqual(a, b3) + self.assertEqual(a, b4) + self.assertEqual(a, b5) + self.assertEqual(a, b6) + self.assertEqual(sys.getrefcount(a), refcnt + 8) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testCastFromMDerived4ToBases(self): + '''MDerived4 is casted by C++ to its parents and the binding must + return the MDerived4 wrapper.''' + a = MDerived4() + refcnt = sys.getrefcount(a) + b3 = a.castToBase3() + b4 = a.castToBase4() + self.assertTrue(isinstance(b3, MDerived4)) + self.assertTrue(isinstance(b4, MDerived4)) + self.assertEqual(a, b3) + self.assertEqual(a, b4) + self.assertEqual(sys.getrefcount(a), refcnt + 2) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testCastFromMDerived5ToBases(self): + '''MDerived5 is casted by C++ to its parents and the binding must + return the MDerived5 wrapper.''' + a = MDerived5() + refcnt = sys.getrefcount(a) + b3 = a.castToBase3() + b4 = a.castToBase4() + self.assertTrue(isinstance(b3, MDerived5)) + self.assertTrue(isinstance(b4, MDerived5)) + self.assertEqual(a, b3) + self.assertEqual(a, b4) + self.assertEqual(sys.getrefcount(a), refcnt + 2) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testCastFromMDerived3ToBase3(self): + '''MDerived3 is casted by C++ to Base3 grandparent using both the inherited + and reimplement castToBase3 methods.''' + a = MDerived3() + refcnt = sys.getrefcount(a) + b3_reimplemented = a.castToBase3() + b3_inherited = MDerived2.castToBase3(a) + self.assertTrue(isinstance(b3_reimplemented, MDerived3)) + self.assertTrue(isinstance(b3_inherited, MDerived3)) + self.assertEqual(a, b3_reimplemented) + self.assertEqual(a, b3_inherited) + self.assertEqual(sys.getrefcount(a), refcnt + 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/namespace_test.py b/sources/shiboken6/tests/samplebinding/namespace_test.py new file mode 100644 index 000000000..64a6792ac --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/namespace_test.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for std::map container conversions''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import SampleNamespace +from shiboken_test_helper import objectFullname + +from shibokensupport.signature import get_signature + +# For tests of invisible namespaces, see +# enumfromremovednamespace_test.py / removednamespaces.h + + +class TestVariablesUnderNamespace(unittest.TestCase): + def testIt(self): + self.assertEqual(SampleNamespace.variableInNamespace, 42) + + +class TestClassesUnderNamespace(unittest.TestCase): + def testIt(self): + c1 = SampleNamespace.SomeClass() # noqa F841 + e1 = SampleNamespace.SomeClass.ProtectedEnum() # noqa F841 + c2 = SampleNamespace.SomeClass.SomeInnerClass() # noqa F841 + e2 = SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum() # noqa F841 + c3 = SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough() # noqa F841 + e3 = SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum(0) # noqa F841 + + def testFunctionAddedOnNamespace(self): + res = SampleNamespace.ImInsideANamespace(2, 2) + self.assertEqual(res, 4) + + def testTpNames(self): + self.assertEqual(str(SampleNamespace.SomeClass), + "<class 'sample.SampleNamespace.SomeClass'>") + self.assertEqual(str(SampleNamespace.SomeClass.ProtectedEnum), + "<enum 'ProtectedEnum'>") + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.ProtectedEnum), + "<enum 'ProtectedEnum'>") + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough), + "<class 'sample.SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough'>") # noqa: E501 + self.assertEqual(str(SampleNamespace.SomeClass.SomeInnerClass.OkThisIsRecursiveEnough.NiceEnum), # noqa: E501 + "<enum 'NiceEnum'>") + + # Test if enum inside of class is correct represented + an = objectFullname(get_signature(SampleNamespace.enumInEnumOut).parameters['in_'].annotation) # noqa: E501 + self.assertEqual(an, "sample.SampleNamespace.InValue") + an = objectFullname(get_signature(SampleNamespace.enumAsInt).parameters['value'].annotation) + self.assertEqual(an, "sample.SampleNamespace.SomeClass.PublicScopedEnum") + + def testInlineNamespaces(self): + cls = SampleNamespace.ClassWithinInlineNamespace() + cls.setValue(SampleNamespace.EWIN_Value1) + self.assertEqual(cls.value(), SampleNamespace.EWIN_Value1) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/newdivision_test.py b/sources/shiboken6/tests/samplebinding/newdivision_test.py new file mode 100644 index 000000000..0e7dfbee1 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/newdivision_test.py @@ -0,0 +1,25 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Point + + +class TestNewDivision(unittest.TestCase): + + def testIt(self): + p = Point(4, 4) + p2 = p / 2 + self.assertEqual(p2, Point(2, 2)) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/nondefaultctor_test.py b/sources/shiboken6/tests/samplebinding/nondefaultctor_test.py new file mode 100644 index 000000000..bc8d29e50 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/nondefaultctor_test.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for ...''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import NonDefaultCtor + + +class DerivedNonDefaultCtor (NonDefaultCtor): + def returnMyselfVirtual(self): + return NonDefaultCtor(self.value() + 1) + + +class AnotherDerivedNonDefaultCtor (NonDefaultCtor): + def __init__(self, some_string): + pass + + +class NonDefaultCtorTest(unittest.TestCase): + + def testNonDefaultCtor(self): + c = NonDefaultCtor(2) + # these functions returns NonDefaultCtor by value, so a PyObjecy is created every time + self.assertNotEqual(c.returnMyself(), c) + self.assertEqual(c.returnMyself().value(), 2) + self.assertNotEqual(c.returnMyself(3), c) + self.assertEqual(c.returnMyself(3).value(), 2) + self.assertNotEqual(c.returnMyself(4, c), c) + self.assertEqual(c.returnMyself(4, c).value(), 2) + + def testVirtuals(self): + c = DerivedNonDefaultCtor(3) + # these functions returns NonDefaultCtor by value, so a PyObjecy is created every time + self.assertNotEqual(c.returnMyselfVirtual(), c) + self.assertEqual(c.returnMyselfVirtual().value(), 4) + self.assertEqual(c.callReturnMyselfVirtual().value(), 4) + + def testCtorOverload(self): + c = AnotherDerivedNonDefaultCtor("testing") # noqa: F841 + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/nontypetemplate_test.py b/sources/shiboken6/tests/samplebinding/nontypetemplate_test.py new file mode 100644 index 000000000..a10547728 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/nontypetemplate_test.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +hasNumPy = False + +try: + import numpy + hasNumPy = True +except ImportError: + pass + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import IntArray2, IntArray3 + + +class NonTypeTemplateTest(unittest.TestCase): + + def testNonTypeTemplate(self): + array2 = IntArray2(3) + self.assertEqual(array2.sum(), 6) + array3 = IntArray3(5) + self.assertEqual(array3.sum(), 15) + + def testArrayInitializer(self): + if not hasNumPy: + return + array3 = IntArray3(numpy.array([1, 2, 3], dtype='int32')) + self.assertEqual(array3.sum(), 6) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/nonzero_test.py b/sources/shiboken6/tests/samplebinding/nonzero_test.py new file mode 100644 index 000000000..7be239fc4 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/nonzero_test.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Color, Brush + + +class TestNonZeroOperator(unittest.TestCase): + def testColor(self): + """Color has a Qt-style isNull()""" + c = Color() + self.assertFalse(c) + c = Color(2) + self.assertTrue(c) + + def testBrush(self): + """Brush enables its operator bool in the typesystem XML""" + b = Brush() + self.assertFalse(b) + b = Brush(Color(2)) + self.assertTrue(b) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/numericaltypedef_test.py b/sources/shiboken6/tests/samplebinding/numericaltypedef_test.py new file mode 100644 index 000000000..f714a4fc8 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/numericaltypedef_test.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import SizeF + + +class NumericalTypedefTest(unittest.TestCase): + + def testNumericalTypedefExact(self): + width, height = (1.1, 2.2) + size = SizeF(width, height) + self.assertEqual(size.width(), width) + self.assertEqual(size.height(), height) + + def testNumericalTypedefConvertible(self): + width, height = (1, 2) + size = SizeF(width, height) + self.assertEqual(size.width(), float(width)) + self.assertEqual(size.height(), float(height)) + + def testNumericalTypedefOfUnsignedShort(self): + self.assertEqual(SizeF.passTypedefOfUnsignedShort(123), 123) + self.assertEqual(SizeF.passTypedefOfUnsignedShort(321), 321) + self.assertNotEqual(SizeF.passTypedefOfUnsignedShort(123), 0) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/numpy_test.py b/sources/shiboken6/tests/samplebinding/numpy_test.py new file mode 100644 index 000000000..42094a463 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/numpy_test.py @@ -0,0 +1,41 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import sys + +try: + import sysconfig + if bool(sysconfig.get_config_var('Py_DEBUG')): + sys.exit(0) + import numpy +except: # noqa: E722 + sys.exit(0) + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import PointF + + +class TestNumpyTypes(unittest.TestCase): + + def testNumpyConverted(self): + x, y = (0.1, 0.2) + p = PointF(float(numpy.float32(x)), float(numpy.float32(y))) + self.assertAlmostEqual(p.x(), x) + self.assertAlmostEqual(p.y(), y) + + def testNumpyAsIs(self): + x, y = (0.1, 0.2) + p = PointF(numpy.float32(x), numpy.float32(y)) + self.assertAlmostEqual(p.x(), x) + self.assertAlmostEqual(p.y(), y) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/objecttype_test.py b/sources/shiboken6/tests/samplebinding/objecttype_test.py new file mode 100644 index 000000000..ead68ba13 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/objecttype_test.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests ObjectType class of object-type with privates copy constructor and = operator.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +import sys + +from sample import ObjectType, Str +from shiboken6 import Shiboken + + +class ObjectTypeTest(unittest.TestCase): + '''Test cases ObjectType class of object-type with privates copy constructor and = operator.''' + + def testObjectTypeSetObjectNameWithStrVariable(self): + '''ObjectType.setObjectName with Str variable as argument.''' + s = Str('object name') + o = ObjectType() + o.setObjectName(s) + self.assertEqual(str(o.objectName()), str(s)) + + def testObjectTypeSetObjectNameWithStrInstantiation(self): + '''ObjectType.setObjectName with Str instantiation as argument.''' + s = 'object name' + o = ObjectType() + o.setObjectName(Str(s)) + self.assertEqual(str(o.objectName()), s) + + def testObjectTypeSetObjectNameWithPythonString(self): + '''ObjectType.setObjectName with Python string as argument.''' + o = ObjectType() + o.setObjectName('object name') + self.assertEqual(str(o.objectName()), 'object name') + + def testNullOverload(self): + o = ObjectType() + o.setObject(None) + self.assertEqual(o.callId(), 0) + o.setNullObject(None) + self.assertEqual(o.callId(), 1) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testParentFromCpp(self): + o = ObjectType() + self.assertEqual(sys.getrefcount(o), 2) + o.getCppParent().setObjectName('parent') + self.assertEqual(sys.getrefcount(o), 3) + o.getCppParent().setObjectName('parent') + self.assertEqual(sys.getrefcount(o), 3) + o.getCppParent().setObjectName('parent') + self.assertEqual(sys.getrefcount(o), 3) + o.getCppParent().setObjectName('parent') + self.assertEqual(sys.getrefcount(o), 3) + o.getCppParent().setObjectName('parent') + self.assertEqual(sys.getrefcount(o), 3) + o.destroyCppParent() + self.assertEqual(sys.getrefcount(o), 2) + + def testNextInFocusChainCycle(self): + parent = ObjectType() + child = ObjectType(parent) + next_focus = child.nextInFocusChain() # noqa: F841 + + Shiboken.invalidate(parent) + + def testNextInFocusChainCycleList(self): + '''As above but in for a list of objects''' + parents = [] + children = [] + focus_chains = [] + for i in range(10): + parent = ObjectType() + child = ObjectType(parent) + next_focus = child.nextInFocusChain() + parents.append(parent) + children.append(child) + focus_chains.append(next_focus) + + Shiboken.invalidate(parents) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testClassDecref(self): + # Bug was that class PyTypeObject wasn't decrefed when instance died + before = sys.getrefcount(ObjectType) + + for i in range(1000): + obj = ObjectType() + Shiboken.delete(obj) + + after = sys.getrefcount(ObjectType) + + self.assertLess(abs(before - after), 5) + + def testInvalidProperty(self): + o = ObjectType() + with self.assertRaises(AttributeError): + o.typo + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/objecttype_with_named_args_test.py b/sources/shiboken6/tests/samplebinding/objecttype_with_named_args_test.py new file mode 100644 index 000000000..285e2313b --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/objecttype_with_named_args_test.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType + + +class NamedArgsTest(unittest.TestCase): + + def testOneArgument(self): + p = ObjectType() + o = ObjectType(parent=p) + self.assertEqual(o.parent(), p) + + def testMoreArguments(self): + o = ObjectType() + + o.setObjectSplittedName("", prefix="pys", suffix="ide") + self.assertEqual(o.objectName(), "pyside") + + o.setObjectSplittedName("", suffix="ide", prefix="pys") + self.assertEqual(o.objectName(), "pyside") + + o.setObjectNameWithSize(name="pyside", size=6) + self.assertEqual(o.objectName(), "pyside") + + o.setObjectNameWithSize(size=6, name="pyside") + self.assertEqual(o.objectName(), "pyside") + + def testUseDefaultValues(self): + o = ObjectType() + + o.setObjectNameWithSize(size=3) + self.assertEqual(o.objectName(), "<un") # use name='unknown' default argument + + o.setObjectSplittedName("") + self.assertEqual(o.objectName(), "<unknown>") # user prefix='<unk' and suffix='nown>' + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/objecttypebyvalue_test.py b/sources/shiboken6/tests/samplebinding/objecttypebyvalue_test.py new file mode 100644 index 000000000..8f74af3ab --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/objecttypebyvalue_test.py @@ -0,0 +1,27 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectTypeByValue + + +class ObjectTypeByValueTest (unittest.TestCase): + def testIt(self): + factory = ObjectTypeByValue() + obj = factory.returnSomeKindOfMe() + # This should crash! + obj.prop.protectedValueTypeProperty.setX(1.0) + # just to make sure it will segfault + obj.prop.protectedValueTypeProperty.setY(2.0) + + +if __name__ == "__main__": + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/objecttypelayout_test.py b/sources/shiboken6/tests/samplebinding/objecttypelayout_test.py new file mode 100644 index 000000000..677b89281 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/objecttypelayout_test.py @@ -0,0 +1,301 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests cases for ObjectTypeLayout class.''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType, ObjectTypeLayout + + +class ObjectTypeLayoutTest(unittest.TestCase): + '''Test cases for ObjectTypeLayout class.''' + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testOwnershipOverride(self): + lt = ObjectTypeLayout() + + o1 = ObjectType(lt) + o1.setObjectName('o1') + + self.assertEqual(sys.getrefcount(o1), 3) + lt.takeChild('o1') + self.assertEqual(sys.getrefcount(o1), 2) + + def testSetNullLayout(self): + '''ObjectType.setLayout(0).''' + o2 = ObjectType() + o2.setLayout(None) + + def testSetNullLayoutToObjectTypeCreatedInCpp(self): + '''ObjectType.setLayout(0) to object created in C++.''' + o1 = ObjectType.create() + o1.setLayout(None) + + def testObjectTypeLayout(self): + '''ObjectType.setLayout.''' + p1 = ObjectType() + c1 = ObjectType() + c2 = ObjectType() + c3 = ObjectType() + layout = ObjectTypeLayout() + layout.addObject(c1) + layout.addObject(c2) + layout.addObject(c3) + self.assertEqual(c1.parent(), None) + self.assertEqual(c2.parent(), None) + self.assertEqual(c3.parent(), None) + + p1.setLayout(layout) + del p1 # This must kill c1, c2 and c3 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + self.assertRaises(RuntimeError, c1.objectName) + self.assertRaises(RuntimeError, c2.objectName) + self.assertRaises(RuntimeError, c3.objectName) + self.assertRaises(RuntimeError, layout.objectName) + + def testObjectTypeLayoutWithObjectsCreatedInCpp(self): + '''ObjectType.setLayout with objects created in C++.''' + p1 = ObjectType.create() + c1 = ObjectType.create() + c2 = ObjectType.create() + c3 = ObjectType.create() + layout = ObjectTypeLayout() + layout.addObject(c1) + layout.addObject(c2) + layout.addObject(c3) + self.assertEqual(c1.parent(), None) + self.assertEqual(c2.parent(), None) + self.assertEqual(c3.parent(), None) + + p1.setLayout(layout) + del p1 # This must kill c1, c2 and c3 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + self.assertRaises(RuntimeError, c1.objectName) + self.assertRaises(RuntimeError, c2.objectName) + self.assertRaises(RuntimeError, c3.objectName) + self.assertRaises(RuntimeError, layout.objectName) + + def testObjectTypeLayoutTransference(self): + '''Transfer a layout from one ObjectType to another, so that all the items in + the layout get reparented.''' + p1 = ObjectType() + p2 = ObjectType() + c1 = ObjectType() + c2 = ObjectType() + + layout = ObjectTypeLayout() + layout.addObject(c1) + layout.addObject(c2) + + p1.setLayout(layout) + + self.assertEqual(len(p2.children()), 0) + self.assertEqual(c1.parent(), p1) + self.assertEqual(c2.parent(), p1) + self.assertEqual(set(p1.children()), set([c1, c2, layout])) + + p2.setLayout(layout) + + self.assertEqual(len(p1.children()), 0) + self.assertEqual(c1.parent(), p2) + self.assertEqual(c2.parent(), p2) + self.assertEqual(set(p2.children()), set([c1, c2, layout])) + + def testObjectTypeLayoutInsideAnotherLayout(self): + '''Adds one ObjectTypeLayout to another and sets the parent to an ObjectType.''' + p1 = ObjectType() + + l1 = ObjectTypeLayout() + c1 = ObjectType() + l1.addObject(c1) + c2 = ObjectType() + l1.addObject(c2) + + l2 = ObjectTypeLayout() + c3 = ObjectType() + l2.addObject(c3) + c4 = ObjectType() + l2.addObject(c4) + + l1.addObject(l2) + + p1.setLayout(l1) + + self.assertEqual(c1.parent(), p1) + self.assertEqual(c2.parent(), p1) + self.assertEqual(c3.parent(), p1) + self.assertEqual(c4.parent(), p1) + self.assertEqual(l1.parent(), p1) + self.assertEqual(l2.parent(), l1) + + del p1 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + self.assertRaises(RuntimeError, c1.objectName) + self.assertRaises(RuntimeError, c2.objectName) + self.assertRaises(RuntimeError, c3.objectName) + self.assertRaises(RuntimeError, c4.objectName) + self.assertRaises(RuntimeError, l1.objectName) + self.assertRaises(RuntimeError, l2.objectName) + + def testObjectTypeLayoutInsideAnotherLayoutAndEveryoneCreatedInCpp(self): + '''Adds one ObjectTypeLayout to another and sets the parent to an ObjectType. + All the objects are created in C++.''' + p1 = ObjectType.create() + + l1 = ObjectTypeLayout.create() + c1 = ObjectType.create() + l1.addObject(c1) + c2 = ObjectType.create() + l1.addObject(c2) + + l2 = ObjectTypeLayout.create() + c3 = ObjectType.create() + l2.addObject(c3) + c4 = ObjectType.create() + l2.addObject(c4) + + l1.addObject(l2) + + p1.setLayout(l1) + + self.assertEqual(c1.parent(), p1) + self.assertEqual(c2.parent(), p1) + self.assertEqual(c3.parent(), p1) + self.assertEqual(c4.parent(), p1) + self.assertEqual(l1.parent(), p1) + self.assertEqual(l2.parent(), l1) + + del p1 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + self.assertRaises(RuntimeError, c1.objectName) + self.assertRaises(RuntimeError, c2.objectName) + self.assertRaises(RuntimeError, c3.objectName) + self.assertRaises(RuntimeError, c4.objectName) + self.assertRaises(RuntimeError, l1.objectName) + self.assertRaises(RuntimeError, l2.objectName) + + def testTransferNestedLayoutsBetweenObjects(self): + '''Adds one ObjectTypeLayout to another, sets the parent to an ObjectType + and then transfer it to another object.''' + p1 = ObjectType() + p2 = ObjectType() + + l1 = ObjectTypeLayout() + c1 = ObjectType() + l1.addObject(c1) + c2 = ObjectType() + l1.addObject(c2) + + l2 = ObjectTypeLayout() + c3 = ObjectType() + l2.addObject(c3) + c4 = ObjectType() + l2.addObject(c4) + + l1.addObject(l2) + + p1.setLayout(l1) + + self.assertEqual(c1.parent(), p1) + self.assertEqual(c2.parent(), p1) + self.assertEqual(c3.parent(), p1) + self.assertEqual(c4.parent(), p1) + self.assertEqual(l1.parent(), p1) + self.assertEqual(l2.parent(), l1) + + p2.setLayout(l1) + del p1 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + self.assertEqual(c1.parent(), p2) + self.assertEqual(c2.parent(), p2) + self.assertEqual(c3.parent(), p2) + self.assertEqual(c4.parent(), p2) + self.assertEqual(l1.parent(), p2) + self.assertEqual(l2.parent(), l1) + + del p2 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + self.assertRaises(RuntimeError, c1.objectName) + self.assertRaises(RuntimeError, c2.objectName) + self.assertRaises(RuntimeError, c3.objectName) + self.assertRaises(RuntimeError, c4.objectName) + self.assertRaises(RuntimeError, l1.objectName) + self.assertRaises(RuntimeError, l2.objectName) + + def testTransferNestedLayoutsBetweenObjectsAndEveryoneCreatedInCpp(self): + '''Adds one ObjectTypeLayout to another, sets the parent to an ObjectType and then + transfer it to another object. All the objects are created in C++.''' + p1 = ObjectType.create() + p2 = ObjectType.create() + + l1 = ObjectTypeLayout.create() + c1 = ObjectType.create() + l1.addObject(c1) + c2 = ObjectType.create() + l1.addObject(c2) + + l2 = ObjectTypeLayout.create() + c3 = ObjectType.create() + l2.addObject(c3) + c4 = ObjectType.create() + l2.addObject(c4) + + l1.addObject(l2) + + p1.setLayout(l1) + + self.assertEqual(c1.parent(), p1) + self.assertEqual(c2.parent(), p1) + self.assertEqual(c3.parent(), p1) + self.assertEqual(c4.parent(), p1) + self.assertEqual(l1.parent(), p1) + self.assertEqual(l2.parent(), l1) + + p2.setLayout(l1) + del p1 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + self.assertEqual(c1.parent(), p2) + self.assertEqual(c2.parent(), p2) + self.assertEqual(c3.parent(), p2) + self.assertEqual(c4.parent(), p2) + self.assertEqual(l1.parent(), p2) + self.assertEqual(l2.parent(), l1) + + del p2 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + self.assertRaises(RuntimeError, c1.objectName) + self.assertRaises(RuntimeError, c2.objectName) + self.assertRaises(RuntimeError, c3.objectName) + self.assertRaises(RuntimeError, c4.objectName) + self.assertRaises(RuntimeError, l1.objectName) + self.assertRaises(RuntimeError, l2.objectName) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/objecttypeoperators_test.py b/sources/shiboken6/tests/samplebinding/objecttypeoperators_test.py new file mode 100644 index 000000000..ceeee6c8d --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/objecttypeoperators_test.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import ObjectTypeOperators + + +class ObjectTypeOperatorsTest(unittest.TestCase): + + def testIt(self): + a = ObjectTypeOperators("a") + b = ObjectTypeOperators("b") + self.assertFalse(a == b) + self.assertEqual(a, a < b) + + # this should change a.key() and return nothing. + self.assertEqual(None, a > b) + self.assertEqual(a.key(), "aoperator>") + + def testPointerOpeators(self): + a = ObjectTypeOperators("a") + b = ObjectTypeOperators("b") # noqa: F841 + self.assertEqual(a + "bc", "abc") + self.assertEqual("bc" + a, "bca") + self.assertEqual("a", a) + self.assertEqual(a, "a") + + def testOperatorInjection(self): + a = ObjectTypeOperators("a") + self.assertNotEqual(a, "b") + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/objecttypereferenceasvirtualmethodargument_test.py b/sources/shiboken6/tests/samplebinding/objecttypereferenceasvirtualmethodargument_test.py new file mode 100644 index 000000000..5fa6f824e --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/objecttypereferenceasvirtualmethodargument_test.py @@ -0,0 +1,31 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import ObjectTypeHolder + + +class TestObjectTypeReferenceAsVirtualMethodArgument(unittest.TestCase): + + def testBasic(self): + holder = ObjectTypeHolder('TheObjectFromC++') + self.assertEqual(holder.callPassObjectTypeAsReference(), 'TheObjectFromC++') + + def testExtended(self): + class Holder(ObjectTypeHolder): + def passObjectTypeAsReference(self, objectType): + return objectType.objectName().prepend(('ThisIs')) + holder = Holder('TheObjectFromC++') + self.assertEqual(holder.callPassObjectTypeAsReference(), 'ThisIsTheObjectFromC++') + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/oddbool_test.py b/sources/shiboken6/tests/samplebinding/oddbool_test.py new file mode 100644 index 000000000..87a8cdb1f --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/oddbool_test.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for OddBool user's primitive type conversion.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import OddBoolUser, ComparisonTester, SpaceshipComparisonTester + + +class DerivedOddBoolUser (OddBoolUser): + def returnMyselfVirtual(self): + return OddBoolUser() + pass + + +class OddBoolTest(unittest.TestCase): + + def testOddBoolUser(self): + obuTrue = OddBoolUser() + obuFalse = OddBoolUser() + obuTrue.setOddBool(True) + self.assertEqual(obuFalse.oddBool(), False) + self.assertEqual(obuTrue.oddBool(), True) + self.assertEqual(obuTrue.callInvertedOddBool(), False) + + self.assertTrue(obuTrue.oddBool()) + self.assertFalse(obuFalse.oddBool()) + self.assertTrue(obuTrue.oddBool() != obuFalse.oddBool()) + + self.assertFalse(obuFalse.oddBool()) + self.assertFalse(obuFalse.oddBool()) + self.assertTrue(obuTrue.oddBool() != obuFalse.oddBool()) + + def testVirtuals(self): + dobu = DerivedOddBoolUser() + self.assertEqual(dobu.invertedOddBool(), True) + + def testImplicitConversionWithUsersPrimitiveType(self): + obu = OddBoolUser(True) + self.assertTrue(obu.oddBool()) + obu = OddBoolUser(False) + self.assertFalse(obu.oddBool()) + cpx = complex(1.0, 0.0) + obu = OddBoolUser(cpx) + self.assertTrue(obu.oddBool()) + cpx = complex(0.0, 0.0) + obu = OddBoolUser(cpx) + self.assertFalse(obu.oddBool()) + + def testOddOperators(self): + t1 = ComparisonTester(42) + t2 = ComparisonTester(42) + self.assertEqual(t1, t2) + + def testSpaceshipOperator(self): + if not SpaceshipComparisonTester.HasSpaceshipOperator: + print("Skipping Spaceship Operator test") + return + t1 = SpaceshipComparisonTester(42) + t2 = SpaceshipComparisonTester(42) + self.assertEqual(t1, t2) + self.assertTrue(t1 <= t2) + self.assertTrue(t1 >= t2) + t2 = SpaceshipComparisonTester(43) + self.assertTrue(t1 < t2) + self.assertFalse(t1 > t2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/onlycopyclass_test.py b/sources/shiboken6/tests/samplebinding/onlycopyclass_test.py new file mode 100644 index 000000000..bcb154c52 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/onlycopyclass_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import OnlyCopy, FriendOfOnlyCopy + + +class ClassWithOnlyCopyCtorTest(unittest.TestCase): + def testGetOne(self): + obj = FriendOfOnlyCopy.createOnlyCopy(123) + self.assertEqual(type(obj), OnlyCopy) + self.assertEqual(obj.value(), 123) + + def testGetMany(self): + objs = FriendOfOnlyCopy.createListOfOnlyCopy(3) + self.assertEqual(type(objs), list) + self.assertEqual(len(objs), 3) + for value, obj in enumerate(objs): + self.assertEqual(obj.value(), value) + + def testPassAsValue(self): + obj = FriendOfOnlyCopy.createOnlyCopy(123) + self.assertEqual(obj.value(), OnlyCopy.getValue(obj)) + + def testPassAsReference(self): + obj = FriendOfOnlyCopy.createOnlyCopy(123) + self.assertEqual(obj.value(), OnlyCopy.getValueFromReference(obj)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/overflow_test.py b/sources/shiboken6/tests/samplebinding/overflow_test.py new file mode 100644 index 000000000..84442306a --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/overflow_test.py @@ -0,0 +1,75 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test case for overflowing C++ numeric types.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import (Point, doubleLongLong, doubleShort, doubleUnsignedInt, + doubleUnsignedLongLong) + + +class OverflowTest(unittest.TestCase): + '''Test case for overflowing C++ numeric types.''' + + def assertRaises(self, *args, **kwds): + if not hasattr(sys, "pypy_version_info"): + # PYSIDE-535: PyPy complains "Fatal RPython error: NotImplementedError" + return super().assertRaises(*args, **kwds) + + def testUnsignedInt(self): + '''C++ function receives an unsigned int argument and raise OverflowError + if the value is negative.''' + val = 100 + self.assertEqual(doubleUnsignedInt(val), 2 * val) + val *= -1 + self.assertRaises(OverflowError, doubleUnsignedInt, val) + + def testLongLong(self): + '''C++ function receives an long long argument and raise OverflowError + if the value is negative.''' + val = 100 + self.assertEqual(doubleLongLong(val), 2 * val) + val = int(100) + self.assertEqual(doubleLongLong(val), 2 * val) + val = (2 << 64) + 1 + self.assertRaises(OverflowError, doubleLongLong, val) + + def testUnsignedLongLong(self): + '''C++ function receives an unsigned long long argument and raise OverflowError + if the value is negative.''' + val = 100 + self.assertEqual(doubleUnsignedLongLong(val), 2 * val) + val = int(100) + self.assertEqual(doubleUnsignedLongLong(val), 2 * val) + val = -100 + self.assertRaises(OverflowError, doubleUnsignedLongLong, val) + val = int(-200) + self.assertRaises(OverflowError, doubleUnsignedLongLong, val) + + def testOverflow(self): + '''Calls function with unsigned int parameter using an overflowing value.''' + self.assertRaises(OverflowError, doubleUnsignedInt, 42415335332353253) + doubleUnsignedInt(0xdeadbeef) + + def testShortOverflow(self): + '''Calls function with short parameter using an overflowing value.''' + doubleShort(-3) + self.assertRaises(OverflowError, doubleShort, 0xFFFF * -1) + self.assertRaises(OverflowError, doubleShort, 0xFFFF + 1) + + def testOverflowOnCtor(self): + '''Calls object ctor with int parameter using overflowing values.''' + self.assertRaises(OverflowError, Point, 42415335332353253, 42415335332353253) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/overload_sorting_test.py b/sources/shiboken6/tests/samplebinding/overload_sorting_test.py new file mode 100644 index 000000000..060d91510 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/overload_sorting_test.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for overload sorting''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import (CustomOverloadSequence, ImplicitBase, ImplicitConv, + ImplicitTarget, SortedOverload) + + +class Dummy(object): + pass + + +class SimpleOverloadSorting(unittest.TestCase): + + def setUp(self): + self.obj = SortedOverload() + + def testIntDouble(self): + '''Overloads with int and double''' + self.assertEqual(self.obj.overload(3), "int") + self.assertEqual(self.obj.overload(3.14), "double") + + def testImplicitConvert(self): + '''Overloads with implicit convertible types''' + self.assertEqual(self.obj.overload(ImplicitTarget()), "ImplicitTarget") + self.assertEqual(self.obj.overload(ImplicitBase()), "ImplicitBase") + + def testContainer(self): + '''Overloads with containers arguments''' + self.assertEqual(self.obj.overload([ImplicitBase()]), "list(ImplicitBase)") + + def testPyObject(self): + '''Overloads with PyObject args''' + self.assertEqual(self.obj.overload(Dummy()), "PyObject") + + def testImplicitOnly(self): + '''Passing an implicit convertible object to an overload''' + self.assertTrue(self.obj.implicit_overload(ImplicitTarget())) + + def testPyObjectSort(self): + self.assertEqual(self.obj.pyObjOverload(1, 2), "int,int") + self.assertEqual(self.obj.pyObjOverload(object(), 2), "PyObject,int") + + +class DeepOverloadSorting(unittest.TestCase): + + def setUp(self): + self.obj = SortedOverload() + + def testPyObject(self): + '''Deep Overload - (int, PyObject *)''' + self.assertEqual(self.obj.overloadDeep(1, Dummy()), "PyObject") + + def testImplicit(self): + '''Deep Overload - (int, ImplicitBase *)''' + self.assertEqual(self.obj.overloadDeep(1, ImplicitBase()), "ImplicitBase") + + +class EnumOverIntSorting(unittest.TestCase): + def testEnumOverInt(self): + ic = ImplicitConv(ImplicitConv.CtorTwo) + self.assertEqual(ic.ctorEnum(), ImplicitConv.CtorTwo) + + +class TestCustomOverloadSequence(unittest.TestCase): + '''Ensure the int-overload (returning v + sizeof(v)) is first as specified via + overload-number in XML.''' + def testCustomOverloadSequence(self): + s = CustomOverloadSequence() + self.assertEqual(s.overload(42), 46) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/overload_test.py b/sources/shiboken6/tests/samplebinding/overload_test.py new file mode 100644 index 000000000..62fa8d8d2 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/overload_test.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for Overload class''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import Echo, Overload, Point, PointF, Polygon, Rect, RectF, Size, Str + + +def raisesWithErrorMessage(func, arguments, errorType, errorMsg): + '''NOTE: Using 'try' because assertRaisesRegexp is not available + to check the error message.''' + try: + func(*arguments) + return False + except TypeError as err: + return errorMsg in str(err) + except Exception: + return False + return True + + +class OverloadTest(unittest.TestCase): + '''Test case for Overload class''' + + def testOverloadMethod0(self): + '''Check overloaded method call for signature "overloaded()".''' + overload = Overload() + self.assertEqual(overload.overloaded(), Overload.Function0) + + def testOverloadMethod1(self): + '''Check overloaded method call for signature "overloaded(Size*)".''' + overload = Overload() + size = Size() + self.assertEqual(overload.overloaded(size), Overload.Function1) + + def testOverloadMethod2(self): + '''Check overloaded method call for signature "overloaded(Point*, ParamEnum)".''' + overload = Overload() + point = Point() + self.assertEqual(overload.overloaded(point, Overload.Param1), Overload.Function2) + + def testOverloadMethod3(self): + '''Check overloaded method call for signature "overloaded(const Point&)".''' + overload = Overload() + point = Point() + self.assertEqual(overload.overloaded(point), Overload.Function3) + + def testDifferentReturnTypes(self): + '''Check method calls for overloads with different return types.''' + overload = Overload() + self.assertEqual(overload.differentReturnTypes(), None) + self.assertEqual(overload.differentReturnTypes(Overload.Param1), None) + self.assertEqual(overload.differentReturnTypes(Overload.Param0, 13), 13) + + def testIntOverloads(self): + overload = Overload() + self.assertEqual(overload.intOverloads(2, 3), 2) + self.assertEqual(overload.intOverloads(2, 4.5), 3) + self.assertEqual(overload.intOverloads(Point(0, 0), 3), 1) + + def testIntDoubleOverloads(self): + overload = Overload() + self.assertEqual(overload.intDoubleOverloads(1, 2), Overload.Function0) + self.assertEqual(overload.intDoubleOverloads(1, 2.0), Overload.Function0) + self.assertEqual(overload.intDoubleOverloads(1.0, 2), Overload.Function1) + self.assertEqual(overload.intDoubleOverloads(1.0, 2.0), Overload.Function1) + + def testWrapperIntIntOverloads(self): + overload = Overload() + self.assertEqual(overload.wrapperIntIntOverloads(Point(), 1, 2), Overload.Function0) + self.assertEqual(overload.wrapperIntIntOverloads(Polygon(), 1, 2), Overload.Function1) + + def testDrawTextPointAndStr(self): + overload = Overload() + self.assertEqual(overload.drawText(Point(), Str()), Overload.Function0) + self.assertEqual(overload.drawText(Point(), ''), Overload.Function0) + self.assertEqual(overload.drawText(PointF(), Str()), Overload.Function1) + self.assertEqual(overload.drawText(PointF(), ''), Overload.Function1) + + def testDrawTextRectIntStr(self): + overload = Overload() + self.assertEqual(overload.drawText(Rect(), 1, Str()), Overload.Function2) + self.assertEqual(overload.drawText(Rect(), 1, ''), Overload.Function2) + self.assertEqual(overload.drawText(RectF(), 1, Str()), Overload.Function3) + self.assertEqual(overload.drawText(RectF(), 1, ''), Overload.Function3) + + def testDrawTextRectFStrEcho(self): + overload = Overload() + self.assertEqual(overload.drawText(RectF(), Str()), Overload.Function4) + self.assertEqual(overload.drawText(RectF(), ''), Overload.Function4) + self.assertEqual(overload.drawText(RectF(), Str(), Echo()), Overload.Function4) + self.assertEqual(overload.drawText(RectF(), '', Echo()), Overload.Function4) + self.assertEqual(overload.drawText(Rect(), Str()), Overload.Function4) + self.assertEqual(overload.drawText(Rect(), ''), Overload.Function4) + self.assertEqual(overload.drawText(Rect(), Str(), Echo()), Overload.Function4) + self.assertEqual(overload.drawText(Rect(), '', Echo()), Overload.Function4) + + def testDrawTextIntIntStr(self): + overload = Overload() + self.assertEqual(overload.drawText(1, 2, Str()), Overload.Function5) + self.assertEqual(overload.drawText(1, 2, ''), Overload.Function5) + + def testDrawTextIntIntIntIntStr(self): + overload = Overload() + self.assertEqual(overload.drawText(1, 2, 3, 4, 5, Str()), Overload.Function6) + self.assertEqual(overload.drawText(1, 2, 3, 4, 5, ''), Overload.Function6) + + def testDrawText2IntIntIntIntStr(self): + overload = Overload() + self.assertEqual(overload.drawText2(1, 2, 3, 4, 5, Str()), Overload.Function6) + self.assertEqual(overload.drawText2(1, 2, 3, 4, 5, ''), Overload.Function6) + self.assertEqual(overload.drawText2(1, 2, 3, 4, 5), Overload.Function6) + self.assertEqual(overload.drawText2(1, 2, 3, 4), Overload.Function6) + self.assertEqual(overload.drawText2(1, 2, 3), Overload.Function6) + + def testDrawText3(self): + overload = Overload() + self.assertEqual(overload.drawText3(Str(), Str(), Str()), Overload.Function0) + self.assertEqual(overload.drawText3('', '', ''), Overload.Function0) + self.assertEqual(overload.drawText3(1, 2, 3, 4, 5), Overload.Function1) + self.assertEqual(overload.drawText3(1, 2, 3, 4, 5), Overload.Function1) + + def testDrawText3Exception(self): + overload = Overload() + args = (Str(), Str(), Str(), 4, 5) + result = raisesWithErrorMessage(overload.drawText3, args, + TypeError, 'called with wrong argument types:') + self.assertTrue(result) + + def testDrawText4(self): + overload = Overload() + self.assertEqual(overload.drawText4(1, 2, 3), Overload.Function0) + self.assertEqual(overload.drawText4(1, 2, 3, 4, 5), Overload.Function1) + + def testAcceptSequence(self): + # Overload.acceptSequence() + overload = Overload() + self.assertEqual(overload.acceptSequence(), Overload.Function0) + + def testAcceptSequenceIntInt(self): + # Overload.acceptSequence(int,int) + overload = Overload() + self.assertEqual(overload.acceptSequence(1, 2), Overload.Function1) + + def testAcceptSequenceStrParamEnum(self): + # Overload.acceptSequence(Str,Overload::ParamEnum) + overload = Overload() + self.assertEqual(overload.acceptSequence(''), Overload.Function2) + self.assertEqual(overload.acceptSequence('', Overload.Param0), Overload.Function2) + self.assertEqual(overload.acceptSequence(Str('')), Overload.Function2) + self.assertEqual(overload.acceptSequence(Str(''), Overload.Param0), Overload.Function2) + + def testAcceptSequenceSize(self): + # Overload.acceptSequence(Size) + overload = Overload() + self.assertEqual(overload.acceptSequence(Size()), Overload.Function3) + + def testAcceptSequenceStringList(self): + # Overload.acceptSequence(const char**) + overload = Overload() + strings = ['line 1', 'line 2'] + self.assertEqual(overload.acceptSequence(strings), Overload.Function4) + args = (['line 1', 2], ) + result = raisesWithErrorMessage(overload.acceptSequence, args, + TypeError, 'The argument must be a sequence of strings.') + self.assertTrue(result) + + def testAcceptSequencePyObject(self): + # Overload.acceptSequence(void*) + overload = Overload() + + class Foo(object): + pass + + foo = Foo() + self.assertEqual(overload.acceptSequence(foo), Overload.Function5) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/overloadwithdefault_test.py b/sources/shiboken6/tests/samplebinding/overloadwithdefault_test.py new file mode 100644 index 000000000..269b97299 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/overloadwithdefault_test.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Overload, Str + + +class OverloadTest(unittest.TestCase): + + def testNoArgument(self): + overload = Overload() + self.assertEqual(overload.strBufferOverloads(), Overload.Function2) + + def testStrArgument(self): + overload = Overload() + self.assertEqual(overload.strBufferOverloads(Str('')), Overload.Function0) + self.assertEqual(overload.strBufferOverloads(Str(''), ''), Overload.Function0) + self.assertEqual(overload.strBufferOverloads(Str(''), '', False), Overload.Function0) + + def testStringArgumentAsStr(self): + overload = Overload() + self.assertEqual(overload.strBufferOverloads('', ''), Overload.Function0) + self.assertEqual(overload.strBufferOverloads('', '', False), Overload.Function0) + + def testStringArgumentAsBuffer(self): + overload = Overload() + self.assertEqual(overload.strBufferOverloads(bytes('', "UTF-8"), 0), Overload.Function1) + + def testBufferArgument(self): + overload = Overload() + self.assertEqual(overload.strBufferOverloads(bytes('', "UTF-8"), 0), Overload.Function1) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/ownership_argument_invalidation_test.py b/sources/shiboken6/tests/samplebinding/ownership_argument_invalidation_test.py new file mode 100644 index 000000000..8a55d3ab8 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/ownership_argument_invalidation_test.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Wrapper validity tests for arguments.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Polygon, Point + + +class WrapperValidityOfArgumentsTest(unittest.TestCase): + '''Wrapper validity tests for arguments.''' + + def testInvalidArgumentToMethod(self): + '''Call to method using invalidated Python wrapper as argument should raise RuntimeError.''' + poly = Polygon() + Polygon.stealOwnershipFromPython(poly) + self.assertRaises(RuntimeError, Polygon.doublePolygonScale, poly) + + def testInvalidArgumentToConstructor(self): + '''Call to constructor using invalidated Python wrapper as argument + should raise RuntimeError.''' + pt = Point(1, 2) + Polygon.stealOwnershipFromPython(pt) + self.assertRaises(RuntimeError, Polygon, pt) + + def testInvalidArgumentWithImplicitConversion(self): + '''Call to method using invalidated Python wrapper to be implicitly converted + should raise RuntimeError.''' + pt = Point(1, 2) + Polygon.stealOwnershipFromPython(pt) + self.assertRaises(RuntimeError, Polygon.doublePolygonScale, pt) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/ownership_delete_child_in_cpp_test.py b/sources/shiboken6/tests/samplebinding/ownership_delete_child_in_cpp_test.py new file mode 100644 index 000000000..25c6fea26 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/ownership_delete_child_in_cpp_test.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests for destroy a child object in C++''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType + + +class DeleteChildInCpp(unittest.TestCase): + '''Test case for destroying a child in c++''' + + def testDeleteChild(self): + '''Delete child in C++ should invalidate child - using C++ wrapper''' + parent = ObjectType() + parent.setObjectName('parent') + child = ObjectType(parent) + child.setObjectName('child') + + parent.killChild('child') + self.assertRaises(RuntimeError, child.objectName) + self.assertEqual(parent.objectName(), 'parent') + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/ownership_delete_child_in_python_test.py b/sources/shiboken6/tests/samplebinding/ownership_delete_child_in_python_test.py new file mode 100644 index 000000000..3ae186815 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/ownership_delete_child_in_python_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests for deleting a child object in python''' + +import gc +import os +import random +import string +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType + + +class DeleteChildInPython(unittest.TestCase): + '''Test case for deleting (unref) a child in python''' + + def testDeleteChild(self): + '''Delete child in python should not invalidate child''' + parent = ObjectType() + child = ObjectType(parent) + name = ''.join(random.sample(string.ascii_letters, 5)) + child.setObjectName(name) + + del child + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + new_child = parent.children()[0] + self.assertEqual(new_child.objectName(), name) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/ownership_delete_parent_test.py b/sources/shiboken6/tests/samplebinding/ownership_delete_parent_test.py new file mode 100644 index 000000000..8f654639c --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/ownership_delete_parent_test.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests for destroying the parent''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType + + +class DeleteParentTest(unittest.TestCase): + '''Test case for deleting a parent object''' + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testParentDestructor(self): + '''Delete parent object should invalidate child''' + parent = ObjectType() + child = ObjectType() + child.setParent(parent) + + refcount_before = sys.getrefcount(child) + + del parent + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertRaises(RuntimeError, child.objectName) + self.assertEqual(sys.getrefcount(child), refcount_before - 1) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testParentDestructorMultipleChildren(self): + '''Delete parent object should invalidate all children''' + parent = ObjectType() + children = [ObjectType() for _ in range(10)] + + for child in children: + child.setParent(parent) + + del parent + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + for i, child in enumerate(children): + self.assertRaises(RuntimeError, child.objectName) + self.assertEqual(sys.getrefcount(child), 4) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testRecursiveParentDelete(self): + '''Delete parent should invalidate grandchildren''' + parent = ObjectType() + child = ObjectType(parent) + grandchild = ObjectType(child) + + del parent + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertRaises(RuntimeError, child.objectName) + self.assertEqual(sys.getrefcount(child), 2) + self.assertRaises(RuntimeError, grandchild.objectName) + self.assertEqual(sys.getrefcount(grandchild), 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/ownership_invalidate_after_use_test.py b/sources/shiboken6/tests/samplebinding/ownership_invalidate_after_use_test.py new file mode 100644 index 000000000..37b7591e4 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/ownership_invalidate_after_use_test.py @@ -0,0 +1,95 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Ownership tests for cases of invalidation of Python wrapper after use.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType, ObjectTypeDerived, Event + + +class ExtObjectType(ObjectType): + def __init__(self): + ObjectType.__init__(self) + self.type_of_last_event = None + self.last_event = None + + def event(self, event): + self.last_event = event + self.type_of_last_event = event.eventType() + return True + + +class MyObjectType (ObjectType): + def __init__(self): + super(MyObjectType, self).__init__() + self.fail = False + + def event(self, ev): + self.callInvalidateEvent(ev) + try: + ev.eventType() + except: # noqa: E722 + self.fail = True + raise + return True + + def invalidateEvent(self, ev): + pass + + +class ExtObjectTypeDerived(ObjectTypeDerived): + def __init__(self): + ObjectTypeDerived.__init__(self) + self.type_of_last_event = None + self.last_event = None + + def event(self, event): + self.last_event = event + self.type_of_last_event = event.eventType() + return True + + +class OwnershipInvalidateAfterUseTest(unittest.TestCase): + '''Ownership tests for cases of invalidation of Python wrapper after use.''' + + def testInvalidateAfterUse(self): + '''In ObjectType.event(Event*) the wrapper object created for Event + must me marked as invalid after the method is called.''' + eot = ExtObjectType() + eot.causeEvent(Event.SOME_EVENT) + self.assertEqual(eot.type_of_last_event, Event.SOME_EVENT) + self.assertRaises(RuntimeError, eot.last_event.eventType) + + def testObjectInvalidatedAfterUseAsParameter(self): + '''Tries to use wrapper invalidated after use as a parameter to another method.''' + eot = ExtObjectType() + ot = ObjectType() + eot.causeEvent(Event.ANY_EVENT) + self.assertEqual(eot.type_of_last_event, Event.ANY_EVENT) + self.assertRaises(RuntimeError, ot.event, eot.last_event) + + def testit(self): + obj = MyObjectType() + obj.causeEvent(Event.BASIC_EVENT) + self.assertFalse(obj.fail) + + def testInvalidateAfterUseInDerived(self): + '''Invalidate was failing in a derived C++ class that also inherited + other base classes''' + eot = ExtObjectTypeDerived() + eot.causeEvent(Event.SOME_EVENT) + self.assertEqual(eot.type_of_last_event, Event.SOME_EVENT) + self.assertRaises(RuntimeError, eot.last_event.eventType) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/ownership_invalidate_child_test.py b/sources/shiboken6/tests/samplebinding/ownership_invalidate_child_test.py new file mode 100644 index 000000000..77b7c576c --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/ownership_invalidate_child_test.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests for invalidating a C++ created child that was already on the care of a parent.''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType, BlackBox + + +class InvalidateChildTest(unittest.TestCase): + '''Tests for invalidating a C++ created child that was already on the care of a parent.''' + + def testInvalidateChild(self): + '''Invalidating method call should remove child from the care of a parent if it has one.''' + parent = ObjectType() + child1 = ObjectType(parent) + child1.setObjectName('child1') + child2 = ObjectType.create() + child2.setParent(parent) + child2.setObjectName('child2') + + self.assertEqual(parent.children(), [child1, child2]) + + bbox = BlackBox() + + # This method steals ownership from Python to C++. + bbox.keepObjectType(child1) + self.assertEqual(parent.children(), [child2]) + + bbox.keepObjectType(child2) + self.assertEqual(parent.children(), []) + + del parent + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + # PYSIDE-535: Why do I need to do it twice, here? + gc.collect() + + self.assertEqual(child1.objectName(), 'child1') + self.assertRaises(RuntimeError, child2.objectName) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/ownership_invalidate_nonpolymorphic_test.py b/sources/shiboken6/tests/samplebinding/ownership_invalidate_nonpolymorphic_test.py new file mode 100644 index 000000000..8cbefc30c --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/ownership_invalidate_nonpolymorphic_test.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''The BlackBox class has cases of ownership transference between Python and C++.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Point, BlackBox + + +class OwnershipInvalidateNonPolymorphicTest(unittest.TestCase): + '''The BlackBox class has cases of ownership transference between Python and C++.''' + + def testOwnershipTransference(self): + '''Ownership transference from Python to C++ and back again.''' + p1 = Point(10, 20) + bb = BlackBox() + p1_ticket = bb.keepPoint(p1) + self.assertRaises(RuntimeError, p1.x) + p1_ret = bb.retrievePoint(p1_ticket) + self.assertEqual(p1_ret, Point(10, 20)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/ownership_invalidate_parent_test.py b/sources/shiboken6/tests/samplebinding/ownership_invalidate_parent_test.py new file mode 100644 index 000000000..c721a212c --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/ownership_invalidate_parent_test.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests for invalidating a parent of other objects.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType, BlackBox + + +class InvalidateParentTest(unittest.TestCase): + '''Tests for invalidating a parent of other objects.''' + + def testInvalidateParent(self): + '''Invalidate parent should invalidate children''' + parent = ObjectType.create() + child1 = ObjectType(parent) + child1.setObjectName("child1") + child2 = ObjectType.create() + child2.setObjectName("child2") + child2.setParent(parent) + grandchild1 = ObjectType(child1) + grandchild1.setObjectName("grandchild1") + grandchild2 = ObjectType.create() + grandchild2.setObjectName("grandchild2") + grandchild2.setParent(child2) + bbox = BlackBox() + + bbox.keepObjectType(parent) # Should invalidate the parent + + self.assertRaises(RuntimeError, parent.objectName) + # some children still valid they are wrapper classes + self.assertEqual(child1.objectName(), "child1") + self.assertRaises(RuntimeError, child2.objectName) + self.assertEqual(grandchild1.objectName(), "grandchild1") + self.assertRaises(RuntimeError, grandchild2.objectName) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/ownership_reparenting_test.py b/sources/shiboken6/tests/samplebinding/ownership_reparenting_test.py new file mode 100644 index 000000000..304223063 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/ownership_reparenting_test.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests for object reparenting.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +import sys + +from sample import ObjectType + + +class ExtObjectType(ObjectType): + def __init__(self): + ObjectType.__init__(self) + + +class ReparentingTest(unittest.TestCase): + '''Tests for object reparenting.''' + + def testReparentedObjectTypeIdentity(self): + '''Reparent children from one parent to another.''' + object_list = [] + old_parent = ObjectType() + new_parent = ObjectType() + for i in range(3): + obj = ObjectType() + object_list.append(obj) + obj.setParent(old_parent) + for obj in object_list: + obj.setParent(new_parent) + for child in new_parent.children(): + self.assertTrue(child in object_list) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testReparentWithTheSameParent(self): + '''Set the same parent twice to check if the ref continue the same''' + obj = ObjectType() + parent = ObjectType() + self.assertEqual(sys.getrefcount(obj), 2) + obj.setParent(parent) + self.assertEqual(sys.getrefcount(obj), 3) + obj.setParent(parent) + self.assertEqual(sys.getrefcount(obj), 3) + + def testReparentedExtObjectType(self): + '''Reparent children from one extended parent to another.''' + object_list = [] + old_parent = ExtObjectType() + new_parent = ExtObjectType() + for i in range(3): + obj = ExtObjectType() + object_list.append(obj) + obj.setParent(old_parent) + for obj in object_list: + obj.setParent(new_parent) + for orig, child in zip(object_list, new_parent.children()): + self.assertEqual(type(orig), type(child)) + + def testReparentedObjectTypeIdentityWithParentsCreatedInCpp(self): + '''Reparent children from one parent to another, both created in C++.''' + object_list = [] + old_parent = ObjectType.create() + new_parent = ObjectType.create() + for i in range(3): + obj = ObjectType() + object_list.append(obj) + obj.setParent(old_parent) + for obj in object_list: + obj.setParent(new_parent) + for child in new_parent.children(): + self.assertTrue(child in object_list) + + def testReparentedObjectTypeIdentityWithChildrenCreatedInCpp(self): + '''Reparent children created in C++ from one parent to another.''' + object_list = [] + old_parent = ObjectType() + new_parent = ObjectType() + for i in range(3): + obj = ObjectType.create() + object_list.append(obj) + obj.setParent(old_parent) + for obj in object_list: + obj.setParent(new_parent) + for child in new_parent.children(): + self.assertTrue(child in object_list) + + def testReparentedObjectTypeIdentityWithParentsAndChildrenCreatedInCpp(self): + '''Reparent children from one parent to another. Parents and children are created in C++.''' + object_list = [] + old_parent = ObjectType.create() + new_parent = ObjectType.create() + for i in range(3): + obj = ObjectType.create() + object_list.append(obj) + obj.setParent(old_parent) + for obj in object_list: + obj.setParent(new_parent) + for child in new_parent.children(): + self.assertTrue(child in object_list) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/ownership_transference_test.py b/sources/shiboken6/tests/samplebinding/ownership_transference_test.py new file mode 100644 index 000000000..0e9f08b72 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/ownership_transference_test.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''The BlackBox class has cases of ownership transference between C++ and Python.''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType, BlackBox + + +class BlackBoxTest(unittest.TestCase): + '''The BlackBox class has cases of ownership transference between C++ and Python.''' + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testOwnershipTransference(self): + '''Ownership transference from Python to C++ and back again.''' + o1 = ObjectType() + o1.setObjectName('object1') + o1_refcnt = sys.getrefcount(o1) + o2 = ObjectType() + o2.setObjectName('object2') + o2_refcnt = sys.getrefcount(o2) + bb = BlackBox() + o1_ticket = bb.keepObjectType(o1) # noqa: F841 + o2_ticket = bb.keepObjectType(o2) + self.assertEqual(set(bb.objects()), set([o1, o2])) + self.assertEqual(str(o1.objectName()), 'object1') + self.assertEqual(str(o2.objectName()), 'object2') + # PySide give +1 ref to object with c++ ownership + self.assertEqual(sys.getrefcount(o1), o1_refcnt + 1) + self.assertEqual(sys.getrefcount(o2), o2_refcnt + 1) + o2 = bb.retrieveObjectType(o2_ticket) + self.assertEqual(sys.getrefcount(o2), o2_refcnt) + del bb + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertRaises(RuntimeError, o1.objectName) + self.assertEqual(str(o2.objectName()), 'object2') + self.assertEqual(sys.getrefcount(o2), o2_refcnt) + + def testBlackBoxReleasingUnknownObjectType(self): + '''Asks BlackBox to release an unknown ObjectType.''' + o1 = ObjectType() + o2 = ObjectType() # noqa: F841 + bb = BlackBox() + o1_ticket = bb.keepObjectType(o1) # noqa: F841 + o3 = bb.retrieveObjectType(-5) + self.assertEqual(o3, None) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testOwnershipTransferenceCppCreated(self): + '''Ownership transference using a C++ created object.''' + o1 = ObjectType.create() + o1.setObjectName('object1') + o1_refcnt = sys.getrefcount(o1) # noqa: F841 + bb = BlackBox() + o1_ticket = bb.keepObjectType(o1) # noqa: F841 + self.assertRaises(RuntimeError, o1.objectName) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/pair_test.py b/sources/shiboken6/tests/samplebinding/pair_test.py new file mode 100644 index 000000000..4bd5c697c --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/pair_test.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for std::pair container conversions''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import PairUser + + +class ExtendedPairUser(PairUser): + def __init__(self): + PairUser.__init__(self) + self.create_pair_called = False + + def createPair(self): + self.create_pair_called = True + return (7, 13) + + +class PairConversionTest(unittest.TestCase): + '''Test case for std::pair container conversions''' + + def testReimplementedVirtualMethodCall(self): + '''Test if a Python override of a virtual method is correctly called from C++.''' + pu = ExtendedPairUser() + pair = pu.callCreatePair() + self.assertTrue(pu.create_pair_called) + self.assertEqual(type(pair), tuple) + self.assertEqual(type(pair[0]), int) + self.assertEqual(type(pair[1]), int) + self.assertEqual(pair, (7, 13)) + + def testPrimitiveConversionInsideContainer(self): + '''Test primitive type conversion inside conversible std::pair container.''' + cpx0 = complex(1.2, 3.4) + cpx1 = complex(5.6, 7.8) + cp = PairUser.createComplexPair(cpx0, cpx1) + self.assertEqual(type(cp), tuple) + self.assertEqual(type(cp[0]), complex) + self.assertEqual(type(cp[1]), complex) + self.assertEqual(cp, (cpx0, cpx1)) + + def testSumPair(self): + '''Test method that sums the items of a pair using values of the types + expected by C++ (int and double)''' + pu = PairUser() + pair = (3, 7.13) + result = pu.sumPair(pair) + self.assertEqual(result, sum(pair)) + + def testSumPairDifferentTypes(self): + '''Test method that sums the items of a pair using values of types different + from the ones expected by C++ (int and double)''' + pu = PairUser() + pair = (3.3, 7) + result = pu.sumPair(pair) + self.assertNotEqual(result, sum(pair)) + self.assertEqual(result, int(pair[0]) + pair[1]) + + def testConversionInBothDirections(self): + '''Test converting a pair from Python to C++ and the other way around.''' + pu = PairUser() + pair = (3, 5) + pu.setPair(pair) + result = pu.getPair() + self.assertEqual(result, pair) + + def testConversionInBothDirectionsWithSimilarContainer(self): + '''Test converting a list, instead of the expected tuple, from Python to C++ + and the other way around.''' + pu = PairUser() + pair = [3, 5] + pu.setPair(pair) + result = pu.getPair() + self.assertNotEqual(result, pair) + self.assertEqual(result, tuple(pair)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/pen_test.py b/sources/shiboken6/tests/samplebinding/pen_test.py new file mode 100644 index 000000000..106f3bd61 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/pen_test.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for <add-function> with const char* as argument''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Color, Pen, SampleNamespace + + +class TestPen(unittest.TestCase): + '''Simple test case for Pen.''' + + def testPenWithEmptyConstructor(self): + pen = Pen() + self.assertEqual(pen.ctorType(), Pen.EmptyCtor) + + def testPenWithEnumConstructor(self): + pen = Pen(SampleNamespace.RandomNumber) + self.assertEqual(pen.ctorType(), Pen.EnumCtor) + + def testPenWithColorConstructor(self): + pen = Pen(Color()) + self.assertEqual(pen.ctorType(), Pen.ColorCtor) + + def testPenWithCopyConstructor(self): + pen = Pen(Pen()) + self.assertEqual(pen.ctorType(), Pen.CopyCtor) + + def testPenWithIntConvertedToColor(self): + pen = Pen(1) + self.assertEqual(pen.ctorType(), Pen.ColorCtor) + pen.drawLine(0, 0, 5, 5) + + def testPenRenderHintsProperty(self): + """Exercise the generated property setter and getters, checking + against the C++ getter/setter functions.""" + pen = Pen(1) + self.assertEqual(pen.getRenderHints(), Pen.RenderHints.None_) + self.assertEqual(pen.renderHints, Pen.RenderHints.None_) + pen.renderHints = Pen.RenderHints.TextAntialiasing + self.assertEqual(pen.getRenderHints(), Pen.RenderHints.TextAntialiasing) + self.assertEqual(pen.renderHints, Pen.RenderHints.TextAntialiasing) + pen.setRenderHints(Pen.RenderHints.Antialiasing) + self.assertEqual(pen.getRenderHints(), Pen.RenderHints.Antialiasing) + self.assertEqual(pen.renderHints, Pen.RenderHints.Antialiasing) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/point_test.py b/sources/shiboken6/tests/samplebinding/point_test.py new file mode 100644 index 000000000..f86c0f423 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/point_test.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for Point class''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Point + + +class PointTest(unittest.TestCase): + '''Test case for Point class, including operator overloads.''' + + def assertRaises(self, *args, **kwds): + if not hasattr(sys, "pypy_version_info"): + # PYSIDE-535: PyPy complains "Fatal RPython error: NotImplementedError" + return super().assertRaises(*args, **kwds) + + def testConstructor(self): + '''Test Point class constructor.''' + pt = Point(5.0, 2.3) + self.assertEqual(pt.x(), 5.0) + self.assertEqual(pt.y(), 2.3) + + def testPlusOperator(self): + '''Test Point class + operator.''' + pt1 = Point(5.0, 2.3) + pt2 = Point(0.5, 3.2) + self.assertEqual(pt1 + pt2, Point(5.0 + 0.5, 2.3 + 3.2)) + + def testEqualOperator(self): + '''Test Point class == operator.''' + pt1 = Point(5.0, 2.3) + pt2 = Point(5.0, 2.3) + pt3 = Point(0.5, 3.2) + self.assertTrue(pt1 == pt1) + self.assertTrue(pt1 == pt2) + self.assertFalse(pt1 == pt3) + self.assertFalse(pt1 == object()) + + def testNotEqualOperator(self): + '''Test Point class != operator.''' + pt1 = Point(5.0, 2.3) + pt2 = Point(5.0, 2.3) + # This test no longer makes sense because we always supply default `==`, `!=`. + #self.assertRaises(NotImplementedError, pt1.__ne__, pt2) + # Since we use the default identity comparison, this results in `!=` . + self.assertTrue(pt1 != pt2) + + def testReturnNewCopy(self): + '''Point returns a copy of itself.''' + pt1 = Point(1.1, 2.3) + pt2 = pt1.copy() + self.assertEqual(pt1, pt2) + pt2 += pt1 + self.assertFalse(pt1 == pt2) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testReturnConstPointer(self): + '''Point returns a const pointer for itself.''' + pt1 = Point(5.0, 2.3) + refcount1 = sys.getrefcount(pt1) + pt2 = pt1.getSelf() + self.assertEqual(pt1, pt2) + self.assertEqual(sys.getrefcount(pt1), refcount1 + 1) + self.assertEqual(sys.getrefcount(pt1), sys.getrefcount(pt2)) + + def testUintOverflow(self): + pt1 = Point(0.0, 0.0) + self.assertRaises(OverflowError, pt1.setXAsUint, 840835495615213080) + self.assertEqual(pt1.x(), 0.0) + + def testAddedOperator(self): + p = Point(0.0, 0.0) + r = p - 'Hi' + self.assertEqual(r, 'Hi') + + # now the reverse op. + r = 'Hi' - p + self.assertEqual(r, 'Hi') + + def testModifiedMethod(self): + pt1 = Point(0.0, 0.0) + pt2 = Point(10.0, 10.0) + expected = Point((pt1.x() + pt2.x()) / 2.0, (pt1.y() + pt2.y()) / 2.0) + self.assertEqual(pt1.midpoint(pt2), expected) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/pointerholder_test.py b/sources/shiboken6/tests/samplebinding/pointerholder_test.py new file mode 100644 index 000000000..633525a9c --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/pointerholder_test.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for a class that holds an arbitraty pointer and is modified to hold an PyObject.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import PointerHolder + + +class TestPointerHolder(unittest.TestCase): + '''Test cases for a class that holds an arbitraty pointer and + is modified to hold an PyObject.''' + + def testStoringAndRetrievingPointer(self): + ph = PointerHolder('Hello') + self.assertEqual(ph.pointer(), 'Hello') + a = (1, 2, 3) + ph = PointerHolder(a) + self.assertEqual(ph.pointer(), a) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testReferenceCounting(self): + '''Test reference counting when retrieving data with PointerHolder.pointer().''' + a = (1, 2, 3) + refcnt = sys.getrefcount(a) + ph = PointerHolder(a) + ptr = ph.pointer() # noqa: F841 + self.assertEqual(sys.getrefcount(a), refcnt + 1) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/pointerprimitivetype_test.py b/sources/shiboken6/tests/samplebinding/pointerprimitivetype_test.py new file mode 100644 index 000000000..4da1a89c6 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/pointerprimitivetype_test.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +""" +pointerprimitivetype_test.py + +check that the primitive types are correctly mapped by the signature module. + +Mapping +------- +IntArray2(const int*) -- <Signature (self, data: typing.Sequence)> +getMargins(int*,int*,int*,int*)const -- <Signature (self) -> typing.Tuple[int, int, int, int]> + +We explicitly check only against typing.Iterable in the first test, +because typing.Sequence is a subclass, but we will generalize this +to typing.Iterable in the future. +""" + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import IntArray2, VirtualMethods + +from shibokensupport.signature import get_signature + +import typing + + +class PointerPrimitiveTypeTest(unittest.TestCase): + + def testArraySignature(self): + # signature="IntArray2(const int*)" + found = False + for sig in get_signature(IntArray2): + if "data" in sig.parameters: + found = True + break + self.assertTrue(found) + ann = sig.parameters["data"].annotation + self.assertEqual(ann.__args__, (int,)) + self.assertTrue(issubclass(ann.__origin__, typing.Iterable)) + + def testReturnVarSignature(self): + # signature="getMargins(int*,int*,int*,int*)const"> + ann = get_signature(VirtualMethods.getMargins).return_annotation + self.assertEqual(ann, typing.Tuple[int, int, int, int]) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/pointf_test.py b/sources/shiboken6/tests/samplebinding/pointf_test.py new file mode 100644 index 000000000..91c58eb1d --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/pointf_test.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for PointF class''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import PointF + + +class PointFTest(unittest.TestCase): + '''Test case for PointF class, including operator overloads.''' + + def testConstructor(self): + '''Test PointF class constructor.''' + pt = PointF(5.0, 2.3) + self.assertEqual(pt.x(), 5.0) + self.assertEqual(pt.y(), 2.3) + + def testPlusOperator(self): + '''Test PointF class + operator.''' + pt1 = PointF(5.0, 2.3) + pt2 = PointF(0.5, 3.2) + self.assertEqual(pt1 + pt2, PointF(5.0 + 0.5, 2.3 + 3.2)) + + def testEqualOperator(self): + '''Test PointF class == operator.''' + pt1 = PointF(5.0, 2.3) + pt2 = PointF(5.0, 2.3) + pt3 = PointF(0.5, 3.2) + self.assertTrue(pt1 == pt1) + self.assertTrue(pt1 == pt2) + self.assertFalse(pt1 == pt3) + + def testModifiedMethod(self): + pt1 = PointF(0.0, 0.0) + pt2 = PointF(10.0, 10.0) + expected = PointF((pt1.x() + pt2.x()) / 2.0, (pt1.y() + pt2.y()) / 2.0) + self.assertEqual(pt1.midpoint(pt2), expected) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/primitivereferenceargument_test.py b/sources/shiboken6/tests/samplebinding/primitivereferenceargument_test.py new file mode 100644 index 000000000..0b9fe2249 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/primitivereferenceargument_test.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +import sample + + +class PrimitiveReferenceArgumentTest(unittest.TestCase): + + def testIntReferenceArgument(self): + '''C++ signature: int acceptIntReference(int&)''' + self.assertEqual(sample.acceptIntReference(123), 123) + + def testIntReturnPtr(self): + '''C++ signature: const int *acceptIntReturnPtr(int x)''' + self.assertEqual(sample.acceptIntReturnPtr(123), 123) + + def testOddBoolReferenceArgument(self): + '''C++ signature: OddBool acceptOddBoolReference(OddBool&)''' + self.assertEqual(sample.acceptOddBoolReference(True), True) + self.assertEqual(sample.acceptOddBoolReference(False), False) + self.assertNotEqual(sample.acceptOddBoolReference(True), False) + self.assertNotEqual(sample.acceptOddBoolReference(False), True) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/privatector_test.py b/sources/shiboken6/tests/samplebinding/privatector_test.py new file mode 100644 index 000000000..63040388d --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/privatector_test.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for a class with only a private constructor.''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import PrivateCtor + + +class PrivateCtorTest(unittest.TestCase): + '''Test case for PrivateCtor class''' + + def assertRaises(self, *args, **kwds): + if not hasattr(sys, "pypy_version_info"): + # PYSIDE-535: PyPy complains "Fatal RPython error: NotImplementedError" + return super().assertRaises(*args, **kwds) + + def testPrivateCtorInstanciation(self): + '''Test if instanciation of class with a private constructor raises an exception.''' + self.assertRaises(TypeError, PrivateCtor) + + def testPrivateCtorInheritance(self): + '''Test if inheriting from PrivateCtor raises an exception.''' + def inherit(): + class Foo(PrivateCtor): + pass + self.assertRaises(TypeError, inherit) + + def testPrivateCtorInstanceMethod(self): + '''Test if PrivateCtor.instance() method return the proper singleton.''' + pd1 = PrivateCtor.instance() + calls = pd1.instanceCalls() + self.assertEqual(type(pd1), PrivateCtor) + pd2 = PrivateCtor.instance() + self.assertEqual(pd2, pd1) + self.assertEqual(pd2.instanceCalls(), calls + 1) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testPrivateCtorRefCounting(self): + '''Test refcounting of the singleton returned by PrivateCtor.instance().''' + pd1 = PrivateCtor.instance() + calls = pd1.instanceCalls() + refcnt = sys.getrefcount(pd1) + pd2 = PrivateCtor.instance() + self.assertEqual(pd2.instanceCalls(), calls + 1) + self.assertEqual(sys.getrefcount(pd2), sys.getrefcount(pd1)) + self.assertEqual(sys.getrefcount(pd2), refcnt + 1) + del pd1 + self.assertEqual(sys.getrefcount(pd2), refcnt) + del pd2 + gc.collect() + pd3 = PrivateCtor.instance() + self.assertEqual(type(pd3), PrivateCtor) + self.assertEqual(pd3.instanceCalls(), calls + 2) + self.assertEqual(sys.getrefcount(pd3), refcnt) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/privatedtor_test.py b/sources/shiboken6/tests/samplebinding/privatedtor_test.py new file mode 100644 index 000000000..651f63b15 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/privatedtor_test.py @@ -0,0 +1,85 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for a class with a private destructor.''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from shiboken6 import Shiboken +from sample import PrivateDtor + + +class PrivateDtorTest(unittest.TestCase): + '''Test case for PrivateDtor class''' + + def assertRaises(self, *args, **kwds): + if not hasattr(sys, "pypy_version_info"): + # PYSIDE-535: PyPy complains "Fatal RPython error: NotImplementedError" + return super().assertRaises(*args, **kwds) + + def testPrivateDtorInstanciation(self): + '''Test if instanciation of class with a private destructor raises an exception.''' + self.assertRaises(TypeError, PrivateDtor) + + def testPrivateDtorInheritance(self): + '''Test if inheriting from PrivateDtor raises an exception.''' + def inherit(): + class Foo(PrivateDtor): + pass + self.assertRaises(TypeError, inherit) + + def testPrivateDtorInstanceMethod(self): + '''Test if PrivateDtor.instance() method return the proper singleton.''' + pd1 = PrivateDtor.instance() + calls = pd1.instanceCalls() + self.assertEqual(type(pd1), PrivateDtor) + pd2 = PrivateDtor.instance() + self.assertEqual(pd2, pd1) + self.assertEqual(pd2.instanceCalls(), calls + 1) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testPrivateDtorRefCounting(self): + '''Test refcounting of the singleton returned by PrivateDtor.instance().''' + pd1 = PrivateDtor.instance() + calls = pd1.instanceCalls() + refcnt = sys.getrefcount(pd1) + pd2 = PrivateDtor.instance() + self.assertEqual(pd2.instanceCalls(), calls + 1) + self.assertEqual(sys.getrefcount(pd2), sys.getrefcount(pd1)) + self.assertEqual(sys.getrefcount(pd2), refcnt + 1) + del pd1 + self.assertEqual(sys.getrefcount(pd2), refcnt) + del pd2 + gc.collect() + pd3 = PrivateDtor.instance() + self.assertEqual(type(pd3), PrivateDtor) + self.assertEqual(pd3.instanceCalls(), calls + 2) + self.assertEqual(sys.getrefcount(pd3), refcnt) + + @unittest.skipUnless(hasattr(sys, "getrefcount"), f"{sys.implementation.name} has no refcount") + def testClassDecref(self): + # Bug was that class PyTypeObject wasn't decrefed when instance + # was invalidated + + before = sys.getrefcount(PrivateDtor) + + for i in range(1000): + obj = PrivateDtor.instance() + Shiboken.invalidate(obj) + + after = sys.getrefcount(PrivateDtor) + + self.assertLess(abs(before - after), 5) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/protected_test.py b/sources/shiboken6/tests/samplebinding/protected_test.py new file mode 100644 index 000000000..e4ccf721d --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/protected_test.py @@ -0,0 +1,401 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for protected methods.''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import cacheSize +from sample import ProtectedNonPolymorphic, ProtectedVirtualDestructor +from sample import (ProtectedPolymorphic, ProtectedPolymorphicDaughter, + ProtectedPolymorphicGrandDaughter) +from sample import createProtectedProperty, ProtectedProperty, ProtectedEnumClass +from sample import PrivateDtor +from sample import Event, ObjectType, Point + + +class ExtendedProtectedPolymorphic(ProtectedPolymorphic): + def __init__(self, name): + ProtectedPolymorphic.__init__(self, name) + self.protectedName_called = False + + def protectedName(self): + self.protectedName_called = True + self._name = 'Extended' + ProtectedPolymorphic.protectedName(self) + return self._name + + +class ExtendedProtectedPolymorphicDaughter(ProtectedPolymorphicDaughter): + def __init__(self, name): + self.protectedName_called = False + ProtectedPolymorphicDaughter.__init__(self, name) + + def protectedName(self): + self.protectedName_called = True + self._name = 'ExtendedDaughter' + ProtectedPolymorphicDaughter.protectedName(self) + return self._name + + +class ExtendedProtectedPolymorphicGrandDaughter(ProtectedPolymorphicGrandDaughter): + def __init__(self, name): + self.protectedName_called = False + ProtectedPolymorphicGrandDaughter.__init__(self, name) + + def protectedName(self): + self.protectedName_called = True + self._name = 'ExtendedGrandDaughter' + ProtectedPolymorphicGrandDaughter.protectedName(self) + return self._name + + +class ExtendedProtectedVirtualDestructor(ProtectedVirtualDestructor): + def __init__(self): + ProtectedVirtualDestructor.__init__(self) + + +class ProtectedNonPolymorphicTest(unittest.TestCase): + '''Test cases for protected method in a class without virtual methods.''' + + def tearDown(self): + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(cacheSize(), 0) + + def testProtectedCall(self): + '''Calls a non-virtual protected method.''' + p = ProtectedNonPolymorphic('NonPoly') + self.assertEqual(p.publicName(), p.protectedName()) + a0, a1 = 1, 2 + self.assertEqual(p.protectedSum(a0, a1), a0 + a1) + + def testProtectedCallWithInstanceCreatedOnCpp(self): + '''Calls a non-virtual protected method on an instance created in C++.''' + p = ProtectedNonPolymorphic.create() + self.assertEqual(p.publicName(), p.protectedName()) + a0, a1 = 1, 2 + self.assertEqual(p.protectedSum(a0, a1), a0 + a1) + + def testModifiedProtectedCall(self): + '''Calls a non-virtual protected method modified with code injection.''' + p = ProtectedNonPolymorphic('NonPoly') + self.assertEqual(p.dataTypeName(), 'integer') + self.assertEqual(p.dataTypeName(1), 'integer') + self.assertEqual(p.dataTypeName(Point(1, 2)), 'pointer') + + +class ProtectedPolymorphicTest(unittest.TestCase): + '''Test cases for protected method in a class with virtual methods.''' + + def tearDown(self): + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(cacheSize(), 0) + + def testProtectedCall(self): + '''Calls a virtual protected method.''' + p = ProtectedNonPolymorphic('Poly') + self.assertEqual(p.publicName(), p.protectedName()) + a0, a1 = 1, 2 + self.assertEqual(p.protectedSum(a0, a1), a0 + a1) + + def testProtectedCallWithInstanceCreatedOnCpp(self): + '''Calls a virtual protected method on an instance created in C++.''' + p = ProtectedPolymorphic.create() + self.assertEqual(p.publicName(), p.protectedName()) + self.assertEqual(p.callProtectedName(), p.protectedName()) + + def testReimplementedProtectedCall(self): + '''Calls a reimplemented virtual protected method.''' + original_name = 'Poly' + p = ExtendedProtectedPolymorphic(original_name) + name = p.callProtectedName() + self.assertTrue(p.protectedName_called) + self.assertEqual(p.protectedName(), name) + self.assertEqual(ProtectedPolymorphic.protectedName(p), original_name) + + +class ProtectedPolymorphicDaugherTest(unittest.TestCase): + '''Test cases for protected method in a class inheriting for a class with virtual methods.''' + + def testProtectedCallWithInstanceCreatedOnCpp(self): + '''Calls a virtual protected method from parent class on an instance created in C++.''' + p = ProtectedPolymorphicDaughter.create() + self.assertEqual(p.publicName(), p.protectedName()) + self.assertEqual(p.callProtectedName(), p.protectedName()) + + def testReimplementedProtectedCall(self): + '''Calls a reimplemented virtual protected method from parent class.''' + original_name = 'Poly' + p = ExtendedProtectedPolymorphicDaughter(original_name) + name = p.callProtectedName() + self.assertTrue(p.protectedName_called) + self.assertEqual(p.protectedName(), name) + self.assertEqual(ProtectedPolymorphicDaughter.protectedName(p), original_name) + + +class ProtectedPolymorphicGrandDaugherTest(unittest.TestCase): + '''Test cases for protected method in a class inheriting for a class that inherits from + another with protected virtual methods.''' + + def tearDown(self): + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(cacheSize(), 0) + + def testProtectedCallWithInstanceCreatedOnCpp(self): + '''Calls a virtual protected method from parent class on an instance created in C++.''' + p = ProtectedPolymorphicGrandDaughter.create() + self.assertEqual(p.publicName(), p.protectedName()) + self.assertEqual(p.callProtectedName(), p.protectedName()) + + def testReimplementedProtectedCall(self): + '''Calls a reimplemented virtual protected method from parent class.''' + original_name = 'Poly' + p = ExtendedProtectedPolymorphicGrandDaughter(original_name) + name = p.callProtectedName() + self.assertTrue(p.protectedName_called) + self.assertEqual(p.protectedName(), name) + self.assertEqual(ProtectedPolymorphicGrandDaughter.protectedName(p), original_name) + + +class ProtectedVirtualDtorTest(unittest.TestCase): + '''Test cases for protected virtual destructor.''' + + def setUp(self): + ProtectedVirtualDestructor.resetDtorCounter() + + def tearDown(self): + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(cacheSize(), 0) + + def testVirtualProtectedDtor(self): + '''Original protected virtual destructor is being called.''' + dtor_called = ProtectedVirtualDestructor.dtorCalled() + for i in range(1, 10): + pvd = ProtectedVirtualDestructor() + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + del pvd + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(ProtectedVirtualDestructor.dtorCalled(), dtor_called + i) + + def testVirtualProtectedDtorOnCppCreatedObject(self): + '''Original protected virtual destructor is being called for a C++ created object.''' + dtor_called = ProtectedVirtualDestructor.dtorCalled() + for i in range(1, 10): + pvd = ProtectedVirtualDestructor.create() + del pvd + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(ProtectedVirtualDestructor.dtorCalled(), dtor_called + i) + + def testProtectedDtorOnDerivedClass(self): + '''Original protected virtual destructor is being called for a derived class.''' + dtor_called = ExtendedProtectedVirtualDestructor.dtorCalled() + for i in range(1, 10): + pvd = ExtendedProtectedVirtualDestructor() + del pvd + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(ExtendedProtectedVirtualDestructor.dtorCalled(), dtor_called + i) + + +class ExtendedProtectedEnumClass(ProtectedEnumClass): + def __init__(self): + ProtectedEnumClass.__init__(self) + + def protectedEnumMethod(self, value): + if value == ProtectedEnumClass.ProtectedItem0: + return ProtectedEnumClass.ProtectedItem1 + return ProtectedEnumClass.ProtectedItem0 + + def publicEnumMethod(self, value): + if value == ProtectedEnumClass.PublicItem0: + return ProtectedEnumClass.PublicItem1 + return ProtectedEnumClass.PublicItem0 + + +class ProtectedEnumTest(unittest.TestCase): + '''Test cases for protected enum.''' + + def tearDown(self): + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(cacheSize(), 0) + + def testProtectedMethodWithProtectedEnumArgument(self): + '''Calls protected method with protected enum argument.''' + obj = ProtectedEnumClass() + + self.assertEqual(type(ProtectedEnumClass.ProtectedItem0), ProtectedEnumClass.ProtectedEnum) + + self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem0), + ProtectedEnumClass.ProtectedItem0) + self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem1), + ProtectedEnumClass.ProtectedItem1) + self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem0), + ProtectedEnumClass.ProtectedItem0) + self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem1), + ProtectedEnumClass.ProtectedItem1) + + def testProtectedMethodWithPublicEnumArgument(self): + '''Calls protected method with public enum argument.''' + obj = ProtectedEnumClass() + + self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem0), + ProtectedEnumClass.PublicItem0) + self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem1), + ProtectedEnumClass.PublicItem1) + + self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem0), + ProtectedEnumClass.PublicItem0) + self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem1), + ProtectedEnumClass.PublicItem1) + + def testOverriddenProtectedMethodWithProtectedEnumArgument(self): + '''Calls overridden protected method with protected enum argument.''' + obj = ExtendedProtectedEnumClass() + + self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem0), + ProtectedEnumClass.ProtectedItem1) + self.assertEqual(obj.protectedEnumMethod(ProtectedEnumClass.ProtectedItem1), + ProtectedEnumClass.ProtectedItem0) + + self.assertEqual(ProtectedEnumClass.protectedEnumMethod(obj, ProtectedEnumClass.ProtectedItem0), # noqa: E501 + ProtectedEnumClass.ProtectedItem0) + self.assertEqual(ProtectedEnumClass.protectedEnumMethod(obj, + ProtectedEnumClass.ProtectedItem1), ProtectedEnumClass.ProtectedItem1) + + self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem0), + ProtectedEnumClass.ProtectedItem1) + self.assertEqual(obj.callProtectedEnumMethod(ProtectedEnumClass.ProtectedItem1), + ProtectedEnumClass.ProtectedItem0) + + def testOverriddenProtectedMethodWithPublicEnumArgument(self): + '''Calls overridden protected method with public enum argument.''' + obj = ExtendedProtectedEnumClass() + + self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem0), + ProtectedEnumClass.PublicItem1) + self.assertEqual(obj.publicEnumMethod(ProtectedEnumClass.PublicItem1), + ProtectedEnumClass.PublicItem0) + + self.assertEqual(ProtectedEnumClass.publicEnumMethod(obj, ProtectedEnumClass.PublicItem0), + ProtectedEnumClass.PublicItem0) + self.assertEqual(ProtectedEnumClass.publicEnumMethod(obj, ProtectedEnumClass.PublicItem1), + ProtectedEnumClass.PublicItem1) + + self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem0), + ProtectedEnumClass.PublicItem1) + self.assertEqual(obj.callPublicEnumMethod(ProtectedEnumClass.PublicItem1), + ProtectedEnumClass.PublicItem0) + + +class ProtectedPropertyTest(unittest.TestCase): + '''Test cases for a class with a protected property (or field in C++).''' + + def setUp(self): + self.obj = ProtectedProperty() + + def tearDown(self): + del self.obj + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(cacheSize(), 0) + + def testProtectedProperty(self): + '''Writes and reads a protected integer property.''' + self.obj.protectedProperty = 3 + self.assertEqual(self.obj.protectedProperty, 3) + + def testProtectedContainerProperty(self): + '''Writes and reads a protected list of integers property.''' + lst = [1, 2, 3, 4] + self.obj.protectedContainerProperty = lst + self.assertEqual(self.obj.protectedContainerProperty, lst) + + def testProtectedEnumProperty(self): + '''Writes and reads a protected enum property.''' + self.obj.protectedEnumProperty = Event.SOME_EVENT + self.assertEqual(self.obj.protectedEnumProperty, Event.SOME_EVENT) + + def testProtectedValueTypeProperty(self): + '''Writes and reads a protected value type property.''' + point = Point(12, 34) + self.obj.protectedValueTypeProperty = point + self.assertEqual(self.obj.protectedValueTypeProperty, point) + self.assertFalse(self.obj.protectedValueTypeProperty is point) + pointProperty = self.obj.protectedValueTypeProperty + self.assertTrue(self.obj.protectedValueTypeProperty is pointProperty) + + def testProtectedValueTypePropertyWrapperRegistration(self): + '''Access colocated protected value type property.''' + cache_size = cacheSize() + point = Point(12, 34) + obj = createProtectedProperty() + obj.protectedValueTypeProperty + self.assertEqual(obj.protectedValueTypeProperty.copy(), + obj.protectedValueTypeProperty) + obj.protectedValueTypeProperty = point + self.assertEqual(obj.protectedValueTypeProperty, point) + self.assertFalse(obj.protectedValueTypeProperty is point) + pointProperty = obj.protectedValueTypeProperty + self.assertTrue(obj.protectedValueTypeProperty is pointProperty) + del obj, point, pointProperty + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(cacheSize(), cache_size) + + def testProtectedValueTypePointerProperty(self): + '''Writes and reads a protected value type pointer property.''' + pt1 = Point(12, 34) + pt2 = Point(12, 34) + self.obj.protectedValueTypePointerProperty = pt1 + self.assertEqual(self.obj.protectedValueTypePointerProperty, pt1) + self.assertEqual(self.obj.protectedValueTypePointerProperty, pt2) + self.assertTrue(self.obj.protectedValueTypePointerProperty is pt1) + self.assertFalse(self.obj.protectedValueTypePointerProperty is pt2) + # PYSIDE-535: Need to assign None to break the cycle + self.obj.protectedValueTypePointerProperty = None + + def testProtectedObjectTypeProperty(self): + '''Writes and reads a protected object type property.''' + obj = ObjectType() + self.obj.protectedObjectTypeProperty = obj + self.assertEqual(self.obj.protectedObjectTypeProperty, obj) + # PYSIDE-535: Need to assign None to break the cycle + self.obj.protectedObjectTypeProperty = None + + +class PrivateDtorProtectedMethodTest(unittest.TestCase): + '''Test cases for classes with private destructors and protected methods.''' + + def tearDown(self): + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(cacheSize(), 0) + + def testProtectedMethod(self): + '''Calls protected method of a class with a private destructor.''' + obj = PrivateDtor.instance() + + self.assertEqual(type(obj), PrivateDtor) + self.assertEqual(obj.instanceCalls(), 1) + self.assertEqual(obj.instanceCalls(), obj.protectedInstanceCalls()) + obj = PrivateDtor.instance() + self.assertEqual(obj.instanceCalls(), 2) + self.assertEqual(obj.instanceCalls(), obj.protectedInstanceCalls()) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/pstrlist_test.py b/sources/shiboken6/tests/samplebinding/pstrlist_test.py new file mode 100644 index 000000000..d60f9cf35 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/pstrlist_test.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +import sample + + +class PStrListTest(unittest.TestCase): + + def testPStrList(self): + a = 'str0' + b = 'str1' + lst = sample.createPStrList(a, b) + self.assertEqual(lst, [a, b]) + + def testListOfPStr(self): + a = 'str0' + b = 'str1' + lst = sample.createListOfPStr(a, b) + self.assertEqual(lst, [a, b]) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/pystr_test.py b/sources/shiboken6/tests/samplebinding/pystr_test.py new file mode 100644 index 000000000..ec64c1e31 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/pystr_test.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for definition of __str__ method.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Point + + +class PyStrTest(unittest.TestCase): + '''Test case for definition of __str__ method.''' + + def testPyStr(self): + '''Test case for defined __str__ method.''' + pt = Point(5, 2) + self.assertEqual(str(pt), 'Point(5.0, 2.0)') + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/python_thread_test.py b/sources/shiboken6/tests/samplebinding/python_thread_test.py new file mode 100644 index 000000000..65398b5c6 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/python_thread_test.py @@ -0,0 +1,96 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#!/usr/bin/env python + +'''Tests for using Shiboken-based bindings with python threads''' + +import logging +import os +from random import random +import sys +import threading +import time +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +import sample + +#logging.basicConfig(level=logging.DEBUG) + + +class Producer(threading.Thread): + '''Producer thread''' + + def __init__(self, bucket, max_runs, *args): + #Constructor. Receives the bucket + super(Producer, self).__init__(*args) + self.runs = 0 + self.bucket = bucket + self.max_runs = max_runs + self.production_list = [] + + def run(self): + while self.runs < self.max_runs: + value = int(random() * 10) % 10 + self.bucket.push(value) + self.production_list.append(value) + logging.debug(f'PRODUCER - pushed {value}') + self.runs += 1 + #self.msleep(5) + time.sleep(0.01) + + +class Consumer(threading.Thread): + '''Consumer thread''' + def __init__(self, bucket, max_runs, *args): + #Constructor. Receives the bucket + super(Consumer, self).__init__(*args) + self.runs = 0 + self.bucket = bucket + self.max_runs = max_runs + self.consumption_list = [] + + def run(self): + while self.runs < self.max_runs: + if not self.bucket.empty(): + value = self.bucket.pop() + self.consumption_list.append(value) + logging.debug(f'CONSUMER - got {value}') + self.runs += 1 + else: + logging.debug('CONSUMER - empty bucket') + time.sleep(0.01) + + +class ProducerConsumer(unittest.TestCase): + '''Basic test case for producer-consumer QThread''' + + def finishCb(self): + #Quits the application + self.app.exit(0) + + def testProdCon(self): + #QThread producer-consumer example + bucket = sample.Bucket() + prod = Producer(bucket, 10) + cons = Consumer(bucket, 10) + + prod.start() + cons.start() + + #QObject.connect(prod, SIGNAL('finished()'), self.finishCb) + #QObject.connect(cons, SIGNAL('finished()'), self.finishCb) + + prod.join() + cons.join() + + self.assertEqual(prod.production_list, cons.consumption_list) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/receive_null_cstring_test.py b/sources/shiboken6/tests/samplebinding/receive_null_cstring_test.py new file mode 100644 index 000000000..1d19de941 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/receive_null_cstring_test.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test case for a function that could receive a NULL pointer in a '[const] char*' parameter.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import countCharacters + + +class ReceiveNullCStringTest(unittest.TestCase): + '''Test case for a function that could receive a NULL pointer in a '[const] char*' + parameter.''' + + def testBasic(self): + '''The test function should be working for the basic cases.''' + a = '' + b = 'abc' + self.assertEqual(countCharacters(a), len(a)) + self.assertEqual(countCharacters(b), len(b)) + + def testReceiveNull(self): + '''The test function returns '-1' when receives a None value instead of a string.''' + self.assertEqual(countCharacters(None), -1) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/reference_test.py b/sources/shiboken6/tests/samplebinding/reference_test.py new file mode 100644 index 000000000..1b6dd3a7a --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/reference_test.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for methods that receive references to objects.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Reference, Str + + +class ExtendedReference(Reference): + def __init__(self): + Reference.__init__(self) + self.uses_reference_virtual_called = False + self.uses_const_reference_virtual_called = False + self.reference_inc = 1 + self.const_reference_inc = 2 + self.multiplier = 333 + + def usesReferenceVirtual(self, ref, inc): + self.uses_reference_virtual_called = True + return ref.objId() + inc + self.reference_inc + + def usesConstReferenceVirtual(self, ref, inc): + self.uses_const_reference_virtual_called = True + return ref.objId() + inc + self.const_reference_inc + + def alterReferenceIdVirtual(self, ref): + ref.setObjId(ref.objId() * self.multiplier) + + +class ReferenceTest(unittest.TestCase): + '''Test case for methods that receive references to objects.''' + + def testMethodThatReceivesReference(self): + '''Test a method that receives a reference to an object as argument.''' + objId = 123 + r = Reference(objId) + self.assertEqual(Reference.usesReference(r), objId) + + def testCantSegFaultWhenReceiveNone(self): + '''do not segfault when receiving None as argument.''' + s = Str() + self.assertFalse(bool(s)) + + def testMethodThatReceivesConstReference(self): + '''Test a method that receives a const reference to an object as argument.''' + objId = 123 + r = Reference(objId) + self.assertEqual(Reference.usesConstReference(r), objId) + + def testModificationOfReference(self): + '''Tests if the identity of a reference argument is preserved when passing + it to be altered in C++.''' + objId = 123 + r1 = Reference(objId) + r1.alterReferenceIdVirtual(r1) + self.assertEqual(r1.objId(), objId * Reference.multiplier()) + + def testModificationOfReferenceCallingAVirtualIndirectly(self): + '''Tests if the identity of a reference argument is preserved when passing it + to be altered in C++ through a method that calls a virtual method.''' + objId = 123 + r1 = Reference(objId) + r1.callAlterReferenceIdVirtual(r1) + self.assertEqual(r1.objId(), objId * Reference.multiplier()) + + def testModificationOfReferenceCallingAReimplementedVirtualIndirectly(self): + '''Test if a Python override of a virtual method with a reference parameter + called from C++ alters the argument properly.''' + objId = 123 + r = Reference(objId) + er = ExtendedReference() + result = er.callAlterReferenceIdVirtual(r) # noqa: F841 + self.assertEqual(r.objId(), objId * er.multiplier) + + def testReimplementedVirtualMethodCallWithReferenceParameter(self): + '''Test if a Python override of a virtual method with a reference parameter + is correctly called from C++.''' + inc = 9 + objId = 123 + r = Reference(objId) + er = ExtendedReference() + result = er.callUsesReferenceVirtual(r, inc) + self.assertEqual(result, objId + inc + er.reference_inc) + + def testReimplementedVirtualMethodCallWithConstReferenceParameter(self): + '''Test if a Python override of a virtual method with a const reference + parameter is correctly called from C++.''' + inc = 9 + objId = 123 + r = Reference(objId) + er = ExtendedReference() + result = er.callUsesConstReferenceVirtual(r, inc) + self.assertEqual(result, objId + inc + er.const_reference_inc) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/referencetopointer_test.py b/sources/shiboken6/tests/samplebinding/referencetopointer_test.py new file mode 100644 index 000000000..942c7ea29 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/referencetopointer_test.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for a reference to pointer argument type.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import VirtualMethods, Str + + +class ExtendedVirtualMethods(VirtualMethods): + def __init__(self): + VirtualMethods.__init__(self) + self.prefix = 'Ext' + + def createStr(self, text): + ext_text = text + if text is not None: + ext_text = self.prefix + text + return VirtualMethods.createStr(self, ext_text) + + +class ReferenceToPointerTest(unittest.TestCase): + '''Test cases for a reference to pointer argument type.''' + + def testSimpleCallWithNone(self): + '''Simple call to createStr method with a None argument.''' + obj = VirtualMethods() + ok, string = obj.createStr(None) + self.assertFalse(ok) + self.assertEqual(string, None) + + def testSimpleCallWithString(self): + '''Simple call to createStr method with a Python string argument.''' + obj = VirtualMethods() + ok, string = obj.createStr('foo') + self.assertTrue(ok) + self.assertEqual(string, Str('foo')) + + def testCallNonReimplementedMethodWithNone(self): + '''Calls createStr method from C++ with a None argument.''' + obj = VirtualMethods() + ok, string = obj.callCreateStr(None) + self.assertFalse(ok) + self.assertEqual(string, None) + + def testCallNonReimplementedMethodWithString(self): + '''Calls createStr method from C++ with a Python string argument.''' + obj = VirtualMethods() + ok, string = obj.callCreateStr('foo') + self.assertTrue(ok) + self.assertEqual(string, Str('foo')) + + def testCallReimplementedMethodWithNone(self): + '''Calls reimplemented createStr method from C++ with a None argument.''' + obj = ExtendedVirtualMethods() + ok, string = obj.callCreateStr(None) + self.assertFalse(ok) + self.assertEqual(string, None) + + def testCallReimplementedMethodWithString(self): + '''Calls reimplemented createStr method from C++ with a Python string argument.''' + obj = ExtendedVirtualMethods() + ok, string = obj.callCreateStr('foo') + self.assertTrue(ok) + self.assertEqual(string, Str(obj.prefix + 'foo')) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/renaming_test.py b/sources/shiboken6/tests/samplebinding/renaming_test.py new file mode 100644 index 000000000..b08438ef3 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/renaming_test.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for renaming using target-lang-name attribute.''' + +import os +import re +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import RenamedValue, RenamedUser + +from shibokensupport.signature import get_signature + + +class RenamingTest(unittest.TestCase): + def test(self): + '''Tests whether the C++ class ToBeRenamedValue renamed via attribute + target-lang-name to RenamedValue shows up in consuming function + signature strings correctly. + ''' + renamed_value = RenamedValue() + self.assertEqual(str(type(renamed_value)), + "<class 'sample.RenamedValue'>") + rename_user = RenamedUser() + rename_user.useRenamedValue(renamed_value) + actual_signature = str(get_signature(rename_user.useRenamedValue)) + self.assertTrue(re.match(r"^\(self,\s*?v:\s*?sample.RenamedValue\)\s*?->\s*?None$", + actual_signature)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/return_null_test.py b/sources/shiboken6/tests/samplebinding/return_null_test.py new file mode 100644 index 000000000..2c4f07c65 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/return_null_test.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test case for functions that could return a NULL pointer.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import (returnNullPrimitivePointer, returnNullValueTypePointer, + returnNullObjectTypePointer) + + +class ReturnNullTest(unittest.TestCase): + '''Test case for functions that could return a NULL pointer.''' + + def testReturnNull(self): + '''Function returns a NULL pointer to a primitive type.''' + o = returnNullPrimitivePointer() + self.assertEqual(o, None) + + def testReturnNullObjectType(self): + '''Function returns a NULL pointer to an object-type.''' + o = returnNullObjectTypePointer() + self.assertEqual(o, None) + + def testReturnNullValueType(self): + '''Function returns a NULL pointer to a value-type.''' + o = returnNullValueTypePointer() + self.assertEqual(o, None) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/richcompare_test.py b/sources/shiboken6/tests/samplebinding/richcompare_test.py new file mode 100644 index 000000000..3146d0faf --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/richcompare_test.py @@ -0,0 +1,28 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Expression + + +class TestRichCompare(unittest.TestCase): + + def testIt(self): + a = Expression(2) + b = Expression(3) + c = a + b + d = a + c < b + a + self.assertEqual(d.toString(), "((2+(2+3))<(3+2))") + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/sample-binding.txt.in b/sources/shiboken6/tests/samplebinding/sample-binding.txt.in new file mode 100644 index 000000000..bcf9de90f --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/sample-binding.txt.in @@ -0,0 +1,16 @@ +[generator-project] + +generator-set = shiboken + +header-file = @CMAKE_CURRENT_SOURCE_DIR@/global.h +typesystem-file = @sample_TYPESYSTEM@ + +output-directory = @CMAKE_CURRENT_BINARY_DIR@ + +include-path = @libsample_SOURCE_DIR@ + +typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@ + +enable-parent-ctor-heuristic +use-isnull-as-nb_nonzero +lean-headers diff --git a/sources/shiboken6/tests/samplebinding/sample_test.py b/sources/shiboken6/tests/samplebinding/sample_test.py new file mode 100644 index 000000000..19b2f708d --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/sample_test.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for libsample bindings module''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +import sample + + +class ModuleTest(unittest.TestCase): + '''Test case for module and global functions''' + + def testAddedFunctionAtModuleLevel(self): + '''Calls function added to module from type system description.''' + str1 = 'Foo' + self.assertEqual(sample.multiplyString(str1, 3), str1 * 3) + self.assertEqual(sample.multiplyString(str1, 0), str1 * 0) + + def testAddedFunctionWithVarargs(self): + '''Calls function that receives varargs added to module from type system description.''' + self.assertEqual(sample.countVarargs(1), 0) + self.assertEqual(sample.countVarargs(1, 2), 1) + self.assertEqual(sample.countVarargs(1, 2, 3, 'a', 'b', 4, (5, 6)), 6) + + def testSampleComparisonOpInNamespace(self): + s1 = sample.sample.sample(10) + s2 = sample.sample.sample(10) + self.assertEqual(s1, s2) + + def testConstant(self): + self.assertEqual(sample.sample.INT_CONSTANT, 42) + + def testStringFunctions(self): + # Test plain ASCII, UCS1 and UCS4 encoding which have different + # representations in the PyUnicode objects. + for t1 in ["ascii", "Ãœmläut", "😀"]: + expected = t1 + t1 + self.assertEqual(sample.addStdStrings(t1, t1), expected) + self.assertEqual(sample.addStdWStrings(t1, t1), expected) + + def testNullPtrT(self): + sample.testNullPtrT(None) + self.assertRaises(TypeError, sample.testNullPtrT, 42) + + def testRValueRefsWithValueTypes(self): + """Passing value types by rvalue refs: For value types, nothing should + happen since the argument is copied in the call and the copy is + moved from.""" + polygon = sample.Polygon() + polygon.addPoint(sample.Point(1, 2)) + polygon.addPoint(sample.Point(3, 4)) + point_count = len(polygon.points()) + self.assertEqual(point_count, sample.takePolygon(polygon)) + + def testRValueRefsWithObjectTypes(self): + """Passing object types by rvalue refs: The underlying object should + be moved from.""" + o = sample.ObjectType() + object_name = "Name" + o.setObjectName(object_name) + self.assertEqual(len(object_name), sample.takeObjectType(o)) + # o should be moved from, name is now empty + self.assertEqual(len(o.objectName()), 0) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/samplebinding.pyproject b/sources/shiboken6/tests/samplebinding/samplebinding.pyproject new file mode 100644 index 000000000..ba6ba6f8f --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/samplebinding.pyproject @@ -0,0 +1,131 @@ +{ + "files": ["__del___test.py", + "abstract_test.py", + "addedfunction_test.py", + "addedfunction_with_container_args_test.py", + "argumentmodifications_test.py", + "array_numpy_test.py", + "array_sequence_test.py", + "bug_554_test.py", + "bug_704_test.py", + "bytearray_test.py", + "child_return_test.py", + "class_fields_test.py", + "collector_test.py", + "complex_test.py", + "conversion_operator_test.py", + "copy_test.py", + "ctorconvrule_test.py", + "cyclic_test.py", + "date_test.py", + "decisor_test.py", + "delete_test.py", + "deprecated_test.py", + "derived_test.py", + "duck_punching_test.py", + "echo_test.py", + "enum_test.py", + "enumfromremovednamespace_test.py", + "event_loop_call_virtual_test.py", + "event_loop_thread_test.py", + "exception_test.py", + "filter_test.py", + "handleholder_test.py", + "hashabletype_test.py", + "ignorederefop_test.py", + "implicitconv_numerical_test.py", + "implicitconv_test.py", + "inheritanceandscope_test.py", + "injectcode_test.py", + "innerclass_test.py", + "intlist_test.py", + "intwrapper_test.py", + "invalid_virtual_return_test.py", + "keep_reference_test.py", + "list_test.py", + "lock_test.py", + "map_test.py", + "metaclass_test.py", + "mi_virtual_methods_test.py", + "mixed_mi_test.py", + "modelindex_test.py", + "modelview_test.py", + "modifications_test.py", + "modified_constructor_test.py", + "modifiedvirtualmethods_test.py", + "multi_cpp_inheritance_test.py", + "multiple_derived_test.py", + "namespace_test.py", + "newdivision_test.py", + "nondefaultctor_test.py", + "nontypetemplate_test.py", + "nonzero_test.py", + "numericaltypedef_test.py", + "numpy_test.py", + "objecttype_test.py", + "objecttype_with_named_args_test.py", + "objecttypebyvalue_test.py", + "objecttypelayout_test.py", + "objecttypeoperators_test.py", + "objecttypereferenceasvirtualmethodargument_test.py", + "oddbool_test.py", + "onlycopyclass_test.py", + "overflow_test.py", + "overload_sorting_test.py", + "overload_test.py", + "overloadwithdefault_test.py", + "ownership_argument_invalidation_test.py", + "ownership_delete_child_in_cpp_test.py", + "ownership_delete_child_in_python_test.py", + "ownership_delete_parent_test.py", + "ownership_invalidate_after_use_test.py", + "ownership_invalidate_child_test.py", + "ownership_invalidate_nonpolymorphic_test.py", + "ownership_invalidate_parent_test.py", + "ownership_reparenting_test.py", + "ownership_transference_test.py", + "pair_test.py", + "pen_test.py", + "point_test.py", + "pointerholder_test.py", + "pointerprimitivetype_test.py", + "pointf_test.py", + "primitivereferenceargument_test.py", + "privatector_test.py", + "privatedtor_test.py", + "protected_test.py", + "pstrlist_test.py", + "pystr_test.py", + "python_thread_test.py", + "receive_null_cstring_test.py", + "reference_test.py", + "referencetopointer_test.py", + "renaming_test.py", + "return_null_test.py", + "richcompare_test.py", + "sample_test.py", + "samplesnippets.cpp", + "simplefile_glue.cpp", + "simplefile_test.py", + "size_test.py", + "snakecase_test.py", + "static_nonstatic_methods_test.py", + "str_test.py", + "strlist_test.py", + "templateinheritingclass_test.py", + "time_test.py", + "transform_test.py", + "typeconverters_test.py", + "typedealloc_test.py", + "typedtordoublefree_test.py", + "typesystypedef_test.py", + "unsafe_parent_test.py", + "useraddedctor_test.py", + "virtualdtor_test.py", + "virtualmethods_test.py", + "visibilitychange_test.py", + "voidholder_test.py", + "weakref_test.py", + "writableclassdict_test.py", + "typesystem_sample.xml"] +} diff --git a/sources/shiboken6/tests/samplebinding/samplesnippets.cpp b/sources/shiboken6/tests/samplebinding/samplesnippets.cpp new file mode 100644 index 000000000..43e6b08de --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/samplesnippets.cpp @@ -0,0 +1,54 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +// @snippet intwrapper_add_ints +extern "C" { +static PyObject *Sbk_IntWrapper_add_ints(PyObject * /* self */, PyObject *args) +{ + PyObject *result = nullptr; + if (PyTuple_Check(args) != 0 && PyTuple_Size(args) == 2) { + PyObject *arg1 = PyTuple_GetItem(args, 0); + PyObject *arg2 = PyTuple_GetItem(args, 1); + if (PyLong_Check(arg1) != 0 && PyLong_Check(arg2) != 0) + result = PyLong_FromLong(PyLong_AsLong(arg1) + PyLong_AsLong(arg2)); + } + if (result == nullptr) + PyErr_SetString(PyExc_TypeError, "expecting 2 ints"); + return result; +} +} +// @snippet intwrapper_add_ints + +// @snippet stdcomplex_floor +%PYARG_0 = PyFloat_FromDouble(std::floor(%CPPSELF.abs_value())); +// @snippet stdcomplex_floor + +// @snippet stdcomplex_ceil +%PYARG_0 = PyFloat_FromDouble(std::ceil(%CPPSELF.abs_value())); +// @snippet stdcomplex_ceil + +// @snippet stdcomplex_abs +%PYARG_0 = PyFloat_FromDouble(%CPPSELF.abs_value()); +// @snippet stdcomplex_abs + +// @snippet stdcomplex_pow +%RETURN_TYPE %0 = %CPPSELF.pow(%1); +%PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); +// @snippet stdcomplex_pow + +// @snippet size_char_ct +// Convert a string "{width}x{height}" specification +{ + double width = -1; + double height = -1; + const std::string s = %1; + const auto pos = s.find('x'); + if (pos != std::string::npos) { + std::istringstream wstr(s.substr(0, pos)); + wstr >> width; + std::istringstream hstr(s.substr(pos + 1, s.size() - pos - 1)); + hstr >> height; + } + %0 = new %TYPE(width, height); +} +// @snippet size_char_ct diff --git a/sources/shiboken6/tests/samplebinding/simplefile_glue.cpp b/sources/shiboken6/tests/samplebinding/simplefile_glue.cpp new file mode 100644 index 000000000..76c0cfaf2 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/simplefile_glue.cpp @@ -0,0 +1,9 @@ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +if (!%CPPSELF.%FUNCTION_NAME()) { + PyObject* error_msg = PyBytes_FromFormat( + "Could not open file: \"%s\"", %CPPSELF->filename()); + PyErr_SetObject(PyExc_IOError, error_msg); + return 0; +} diff --git a/sources/shiboken6/tests/samplebinding/simplefile_test.py b/sources/shiboken6/tests/samplebinding/simplefile_test.py new file mode 100644 index 000000000..55c894a35 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/simplefile_test.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for SimpleFile class''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import SimpleFile + + +class SimpleFileTest(unittest.TestCase): + '''Test cases for SimpleFile class.''' + + def setUp(self): + filename = f'simplefile{os.getpid()}.txt' + self.existing_filename = Path(os.curdir) / filename + self.delete_file = False + if not self.existing_filename.exists(): + with self.existing_filename.open('w') as f: + for line in range(10): + f.write('sbrubbles\n') + self.delete_file = True + + self.non_existing_filename = Path(os.curdir) / 'inexistingfile.txt' + i = 0 + while self.non_existing_filename.exists(): + i += 1 + filename = f'inexistingfile-{i}.txt' + self.non_existing_filename = Path(os.curdir) / filename + + def tearDown(self): + if self.delete_file: + os.remove(self.existing_filename) + + def testExistingFile(self): + '''Test SimpleFile class with existing file.''' + f = SimpleFile(os.fspath(self.existing_filename)) + self.assertEqual(f.filename(), os.fspath(self.existing_filename)) + f.open() + self.assertNotEqual(f.size(), 0) + f.close() + + def testNonExistingFile(self): + '''Test SimpleFile class with non-existing file.''' + f = SimpleFile(os.fspath(self.non_existing_filename)) + self.assertEqual(f.filename(), os.fspath(self.non_existing_filename)) + self.assertRaises(IOError, f.open) + self.assertEqual(f.size(), 0) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/size_test.py b/sources/shiboken6/tests/samplebinding/size_test.py new file mode 100644 index 000000000..069ce59b3 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/size_test.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for operator overloads on Size class''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Size + + +class PointTest(unittest.TestCase): + '''Test case for Size class, including operator overloads.''' + + def testConstructor(self): + '''Test Size class constructor.''' + width, height = (5.0, 2.3) + size = Size(width, height) + self.assertEqual(size.width(), width) + self.assertEqual(size.height(), height) + self.assertEqual(size.calculateArea(), width * height) + + def testCopyConstructor(self): + '''Test Size class copy constructor.''' + width, height = (5.0, 2.3) + s1 = Size(width, height) + s2 = Size(s1) + self.assertFalse(s1 is s2) + self.assertEqual(s1, s2) + + def testPlusOperator(self): + '''Test Size class + operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(0.5, 3.2) + self.assertEqual(s1 + s2, Size(5.0 + 0.5, 2.3 + 3.2)) + + def testEqualOperator(self): + '''Test Size class == operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(5.0, 2.3) + s3 = Size(0.5, 3.2) + self.assertTrue(s1 == s1) + self.assertTrue(s1 == s2) + self.assertFalse(s1 == s3) + + def testNotEqualOperator(self): + '''Test Size class != operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(5.0, 2.3) + s3 = Size(0.5, 3.2) + self.assertFalse(s1 != s1) + self.assertFalse(s1 != s2) + self.assertTrue(s1 != s3) + + def testMinorEqualOperator(self): + '''Test Size class <= operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(5.0, 2.3) + s3 = Size(0.5, 3.2) + self.assertTrue(s1 <= s1) + self.assertTrue(s1 <= s2) + self.assertTrue(s3 <= s1) + self.assertFalse(s1 <= s3) + + def testMinorOperator(self): + '''Test Size class < operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(0.5, 3.2) + self.assertFalse(s1 < s1) + self.assertFalse(s1 < s2) + self.assertTrue(s2 < s1) + + def testMajorEqualOperator(self): + '''Test Size class >= operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(5.0, 2.3) + s3 = Size(0.5, 3.2) + self.assertTrue(s1 >= s1) + self.assertTrue(s1 >= s2) + self.assertTrue(s1 >= s3) + self.assertFalse(s3 >= s1) + + def testMajorOperator(self): + '''Test Size class > operator.''' + s1 = Size(5.0, 2.3) + s2 = Size(0.5, 3.2) + self.assertFalse(s1 > s1) + self.assertTrue(s1 > s2) + self.assertFalse(s2 > s1) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/snakecase_test.py b/sources/shiboken6/tests/samplebinding/snakecase_test.py new file mode 100644 index 000000000..a1538796a --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/snakecase_test.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for snake case generation''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import (SnakeCaseTest, SnakeCaseDerivedTest, + snake_case_global_function) + + +class OverrideTest(SnakeCaseDerivedTest): + def virtual_func(self): + return 4711 + + +class SnakeCaseTestCase(unittest.TestCase): + '''Test for SnakeCaseTest''' + def testMemberFunctions(self): + s = SnakeCaseTest() + self.assertEqual(s.test_function1(), 42) + + self.assertEqual(s.testFunctionDisabled(), 42) + + self.assertEqual(s.testFunctionBoth(), 42) + self.assertEqual(s.test_function_both(), 42) + + def virtualFunctions(self): + s = OverrideTest() + self.assertEqual(s.call_virtual_func(), 4711) + + def testMemberFields(self): + s = SnakeCaseTest() + old_value = s.test_field + s.test_field = old_value + 1 + self.assertEqual(s.test_field, old_value + 1) + + old_value = s.testFieldDisabled + s.testFieldDisabled = old_value + 1 + self.assertEqual(s.testFieldDisabled, old_value + 1) + + old_value = s.test_field_both + s.test_field_both = old_value + 1 + self.assertEqual(s.test_field_both, old_value + 1) + self.assertEqual(s.testFieldBoth, old_value + 1) + + def testGlobalFunction(self): + self.assertEqual(snake_case_global_function(), 42) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/static_nonstatic_methods_test.py b/sources/shiboken6/tests/samplebinding/static_nonstatic_methods_test.py new file mode 100644 index 000000000..cf0889299 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/static_nonstatic_methods_test.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for overloads involving static and non-static versions of a method.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import SimpleFile + + +class SimpleFile2 (SimpleFile): + def exists(self): + return "Mooo" + + +class SimpleFile3 (SimpleFile): + pass + + +class SimpleFile4 (SimpleFile): + exists = 5 + + +class StaticNonStaticMethodsTest(unittest.TestCase): + '''Test cases for overloads involving static and non-static versions of a method.''' + + def setUp(self): + filename = f'simplefile{os.getpid()}.txt' + self.existing_filename = Path(filename) + self.delete_file = False + if not self.existing_filename.exists(): + with self.existing_filename.open('w') as f: + for line in range(10): + f.write('sbrubbles\n') + self.delete_file = True + + self.non_existing_filename = Path('inexistingfile.txt') + i = 0 + while self.non_existing_filename.exists(): + i += 1 + filename = 'inexistingfile-{i}.txt' + self.non_existing_filename = Path(filename) + + def tearDown(self): + if self.delete_file: + os.remove(self.existing_filename) + + def testCallingStaticMethodWithClass(self): + '''Call static method using class.''' + self.assertTrue(SimpleFile.exists(os.fspath(self.existing_filename))) + self.assertFalse(SimpleFile.exists(os.fspath(self.non_existing_filename))) + + def testCallingStaticMethodWithInstance(self): + '''Call static method using instance of class.''' + f = SimpleFile(os.fspath(self.non_existing_filename)) + self.assertTrue(f.exists(os.fspath(self.existing_filename))) + self.assertFalse(f.exists(os.fspath(self.non_existing_filename))) + + def testCallingInstanceMethod(self): + '''Call instance method.''' + f1 = SimpleFile(os.fspath(self.non_existing_filename)) + self.assertFalse(f1.exists()) + f2 = SimpleFile(os.fspath(self.existing_filename)) + self.assertTrue(f2.exists()) + + def testOverridingStaticNonStaticMethod(self): + f = SimpleFile2(os.fspath(self.existing_filename)) + self.assertEqual(f.exists(), "Mooo") + + f = SimpleFile3(os.fspath(self.existing_filename)) + self.assertTrue(f.exists()) + + f = SimpleFile4(os.fspath(self.existing_filename)) + self.assertEqual(f.exists, 5) + + def testDuckPunchingStaticNonStaticMethod(self): + f = SimpleFile(os.fspath(self.existing_filename)) + f.exists = lambda: "Meee" + self.assertEqual(f.exists(), "Meee") + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/stdcomplex_test.py b/sources/shiboken6/tests/samplebinding/stdcomplex_test.py new file mode 100644 index 000000000..0caa9764d --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/stdcomplex_test.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for StdComplex class''' + +import os +import math +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import StdComplex + + +REAL = 5.0 +IMAG = 2.3 + + +class StdComplexTest(unittest.TestCase): + '''Test case for StdComplex class, exercising esoteric number + protocols (Py_nb_). For standard number protocols, see Point.''' + + def testConversion(self): + pt = StdComplex(REAL, IMAG) + self.assertEqual(int(pt), int(round(pt.abs_value()))) + self.assertEqual(float(pt), pt.abs_value()) + + def testAbs(self): + pt = StdComplex(REAL, IMAG) + self.assertEqual(abs(pt), pt.abs_value()) + + def testPow(self): + '''Compare pow() function to builtin Python type.''' + pt = StdComplex(REAL, IMAG) + result = pow(pt, StdComplex(2.0, 0)) + py_pt = complex(REAL, IMAG) + py_result = pow(py_pt, complex(2.0, 0)) + self.assertAlmostEqual(result.real(), py_result.real) + self.assertAlmostEqual(result.imag(), py_result.imag) + + def testFloor(self): + pt = StdComplex(REAL, IMAG) + self.assertEqual(math.floor(pt), math.floor(pt.abs_value())) + + def testCeil(self): + pt = StdComplex(REAL, IMAG) + self.assertEqual(math.ceil(pt), math.ceil(pt.abs_value())) + + def testPlusOperator(self): + '''Test StdComplex class + operator.''' + pt1 = StdComplex(REAL, IMAG) + pt2 = StdComplex(0.5, 3.2) + self.assertEqual(pt1 + pt2, StdComplex(REAL + 0.5, IMAG + 3.2)) + + def testEqualOperator(self): + '''Test StdComplex class == operator.''' + pt1 = StdComplex(REAL, IMAG) + pt2 = StdComplex(REAL, IMAG) + pt3 = StdComplex(0.5, 3.2) + self.assertTrue(pt1 == pt1) + self.assertTrue(pt1 == pt2) + self.assertFalse(pt1 == pt3) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/str_test.py b/sources/shiboken6/tests/samplebinding/str_test.py new file mode 100644 index 000000000..c06fd6428 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/str_test.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for a method that receives a reference to class that is implicitly + convertible from a Python native type.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Str + + +class StrTest(unittest.TestCase): + '''Test cases for thr Str class.''' + + def test__str__Method(self): + '''Test if the binding correcly implements the Python __str__ method.''' + s1 = 'original string' + s2 = Str(s1) + self.assertEqual(s1, s2) + self.assertEqual(s1, str(s2)) + + def testPassExactClassAsReferenceToArgument(self): + '''Test passing the expected class as an argument to a method that expects a reference.''' + s1 = Str('This is %VAR!').arg(Str('Sparta')) + self.assertEqual(str(s1), 'This is Sparta!') + + def testPassPythonTypeImplictlyConvertibleToAClassUsedAsReference(self): + '''Test passing a Python class implicitly convertible to a wrapped class + that is expected to be passed as reference.''' + s1 = Str('This is %VAR!').arg('Athens') + self.assertEqual(str(s1), 'This is Athens!') + + def testSequenceOperators(self): + s1 = Str("abcdef") + self.assertEqual(len(s1), 6) + self.assertEqual(len(Str()), 0) + + # getitem + self.assertEqual(s1[0], "a") + self.assertEqual(s1[1], "b") + self.assertEqual(s1[2], "c") + self.assertEqual(s1[3], "d") + self.assertEqual(s1[4], "e") + self.assertEqual(s1[5], "f") + self.assertEqual(s1[-1], "f") + self.assertEqual(s1[-2], "e") + + self.assertRaises(TypeError, s1.__getitem__, 6) + + # setitem + s1[0] = 'A' + s1[1] = 'B' + self.assertEqual(s1[0], 'A') + self.assertEqual(s1[1], 'B') + self.assertRaises(TypeError, s1.__setitem__(6, 67)) + + def testReverseOperator(self): + s1 = Str("hello") + self.assertEqual(s1 + 2, "hello2") + self.assertEqual(2 + s1, "2hello") + + def testToIntError(self): + self.assertEqual(Str('Z').toInt(), (0, False)) + + def testToIntWithDecimal(self): + decimal = Str('37') + val, ok = decimal.toInt() + self.assertEqual(type(val), int) + self.assertEqual(type(ok), bool) + self.assertEqual(val, int(str(decimal))) + + def testToIntWithOctal(self): + octal = Str('52') + val, ok = octal.toInt(8) + self.assertEqual(type(val), int) + self.assertEqual(type(ok), bool) + self.assertEqual(val, int(str(octal), 8)) + + def testToIntWithHexadecimal(self): + hexa = Str('2A') + val, ok = hexa.toInt(16) + self.assertEqual(type(val), int) + self.assertEqual(type(ok), bool) + self.assertEqual(val, int(str(hexa), 16)) + self.assertEqual(hexa.toInt(), (0, False)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/strlist_test.py b/sources/shiboken6/tests/samplebinding/strlist_test.py new file mode 100644 index 000000000..2bfb80b67 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/strlist_test.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for StrList class that inherits from std::list<Str>.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Str, StrList + + +class StrListTest(unittest.TestCase): + '''Test cases for StrList class that inherits from std::list<Str>.''' + + def testStrListCtor_NoParams(self): + '''StrList constructor receives no parameter.''' + sl = StrList() + self.assertEqual(len(sl), 0) + self.assertEqual(sl.constructorUsed(), StrList.NoParamsCtor) + + def testStrListCtor_Str(self): + '''StrList constructor receives a Str object.''' + s = Str('Foo') + sl = StrList(s) + self.assertEqual(len(sl), 1) + self.assertEqual(sl[0], s) + self.assertEqual(sl.constructorUsed(), StrList.StrCtor) + + def testStrListCtor_PythonString(self): + '''StrList constructor receives a Python string.''' + s = 'Foo' + sl = StrList(s) + self.assertEqual(len(sl), 1) + self.assertEqual(sl[0], s) + self.assertEqual(sl.constructorUsed(), StrList.StrCtor) + + def testStrListCtor_StrList(self): + '''StrList constructor receives a StrList object.''' + sl1 = StrList(Str('Foo')) + sl2 = StrList(sl1) + #self.assertEqual(len(sl1), len(sl2)) + #self.assertEqual(sl1, sl2) + self.assertEqual(sl2.constructorUsed(), StrList.CopyCtor) + + def testStrListCtor_ListOfStrs(self): + '''StrList constructor receives a Python list of Str objects.''' + strs = [Str('Foo'), Str('Bar')] + sl = StrList(strs) + self.assertEqual(len(sl), len(strs)) + self.assertEqual(sl, strs) + self.assertEqual(sl.constructorUsed(), StrList.ListOfStrCtor) + + def testStrListCtor_MixedListOfStrsAndPythonStrings(self): + '''StrList constructor receives a Python list of mixed Str objects and Python strings.''' + strs = [Str('Foo'), 'Bar'] + sl = StrList(strs) + self.assertEqual(len(sl), len(strs)) + self.assertEqual(sl, strs) + self.assertEqual(sl.constructorUsed(), StrList.ListOfStrCtor) + + def testCompareStrListWithTupleOfStrs(self): + '''Compares StrList with a Python tuple of Str objects.''' + sl = StrList() + sl.append(Str('Foo')) + sl.append(Str('Bar')) + self.assertEqual(len(sl), 2) + self.assertEqual(sl, (Str('Foo'), Str('Bar'))) + + def testCompareStrListWithTupleOfPythonStrings(self): + '''Compares StrList with a Python tuple of Python strings.''' + sl = StrList() + sl.append(Str('Foo')) + sl.append(Str('Bar')) + self.assertEqual(len(sl), 2) + self.assertEqual(sl, ('Foo', 'Bar')) + + def testCompareStrListWithTupleOfStrAndPythonString(self): + '''Compares StrList with a Python tuple of mixed Str objects and Python strings.''' + sl = StrList() + sl.append(Str('Foo')) + sl.append(Str('Bar')) + self.assertEqual(len(sl), 2) + self.assertEqual(sl, (Str('Foo'), 'Bar')) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/templateinheritingclass_test.py b/sources/shiboken6/tests/samplebinding/templateinheritingclass_test.py new file mode 100644 index 000000000..11279c7ec --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/templateinheritingclass_test.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Photon + +'''This tests classes that inherit from template classes, + simulating a situation found in Qt's phonon module.''' + + +class TemplateInheritingClassTest(unittest.TestCase): + def testClassBasics(self): + self.assertEqual(Photon.ValueIdentity.classType(), Photon.IdentityType) + self.assertEqual(Photon.ValueDuplicator.classType(), Photon.DuplicatorType) + + def testInstanceBasics(self): + value = 123 + samer = Photon.ValueIdentity(value) + self.assertEqual(samer.multiplicator(), 1) + doubler = Photon.ValueDuplicator(value) + self.assertEqual(doubler.multiplicator(), 2) + self.assertEqual(samer.value(), doubler.value()) + self.assertEqual(samer.calculate() * 2, doubler.calculate()) + + def testPassToFunctionAsPointer(self): + obj = Photon.ValueDuplicator(123) + self.assertEqual(Photon.callCalculateForValueDuplicatorPointer(obj), obj.calculate()) + + def testPassToFunctionAsReference(self): + obj = Photon.ValueDuplicator(321) + self.assertEqual(Photon.callCalculateForValueDuplicatorReference(obj), obj.calculate()) + + def testPassToMethodAsValue(self): + value1, value2 = 123, 321 + one = Photon.ValueIdentity(value1) + other = Photon.ValueIdentity(value2) + self.assertEqual(one.sumValueUsingPointer(other), value1 + value2) + + def testPassToMethodAsReference(self): + value1, value2 = 123, 321 + one = Photon.ValueDuplicator(value1) + other = Photon.ValueDuplicator(value2) + self.assertEqual(one.sumValueUsingReference(other), value1 + value2) + + def testPassPointerThrough(self): + obj1 = Photon.ValueIdentity(123) + self.assertEqual(obj1, obj1.passPointerThrough(obj1)) + obj2 = Photon.ValueDuplicator(321) + self.assertEqual(obj2, obj2.passPointerThrough(obj2)) + self.assertRaises(TypeError, obj1.passPointerThrough, obj2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/time_test.py b/sources/shiboken6/tests/samplebinding/time_test.py new file mode 100644 index 000000000..6283a6744 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/time_test.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for constructor and method signature decisor on Time class.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +import datetime + +from sample import Time, ImplicitConv, ObjectType + + +class TimeTest(unittest.TestCase): + '''Test cases for constructor and method signature decisor on Time class. + The constructor and one method have these signatures: CTORMETHOD() and + CTORMETHOD(int h, int m, int s = 0, int ms = 0); there another method + with a more complex signature METH(int, int, ImplicitConv=DEFVALUE, ObjectType=0), + to produce an even worse scenario. + ''' + + def testConstructorWithoutParamers(self): + '''Constructor without parameters: Time()''' + time = Time() + self.assertTrue(time.isNull()) + + def testConstructorWithAllParamers(self): + '''Constructor with all parameters: Time(int h, int m, int s = 0, int ms = 0)''' + time = Time(1, 2, 3, 4) + self.assertTrue(time.toString(), '01:02:03.004') + + def testConstructorWithThreeParamers(self): + '''Constructor with 3 parameters: Time(int h, int m, int s = 0, int ms = 0)''' + time = Time(1, 2, 3) + self.assertTrue(time.toString(), '01:02:03.000') + + def testConstructorWithTwoParamers(self): + '''Constructor with 2 parameters: Time(int h, int m, int s = 0, int ms = 0)''' + time = Time(1, 2) + self.assertTrue(time.toString(), '01:02:00.000') + + def testSimpleMethodWithoutParamers(self): + '''Constructor without parameters: Time.setTime()''' + time = Time(1, 2, 3, 4) + time.setTime() + self.assertTrue(time.isNull()) + + def testSimpleMethodWithAllParamers(self): + '''Simple method with all parameters: Time.setTime(int h, int m, int s = 0, int ms = 0)''' + time = Time() + time.setTime(1, 2, 3, 4) + self.assertTrue(time.toString(), '01:02:03.004') + + def testSimpleMethodWithThreeParamers(self): + '''Simple method with 3 parameters: Time.setTime(int h, int m, int s = 0, int ms = 0)''' + time = Time() + time.setTime(1, 2, 3) + self.assertTrue(time.toString(), '01:02:03.000') + + def testSimpleMethodWithTwoParamers(self): + '''Simple method with 2 parameters: Time.setTime(int h, int m, int s = 0, int ms = 0)''' + time = Time() + time.setTime(1, 2) + self.assertTrue(time.toString(), '01:02:00.000') + + def testMethodWithoutParamers(self): + '''Method without parameters: Time.somethingCompletelyDifferent()''' + time = Time() + result = time.somethingCompletelyDifferent() + self.assertEqual(result, Time.ZeroArgs) + + def testMethodWithAllParamers(self): + '''Method with all parameters: + Time.somethingCompletelyDifferent( + int h, int m, ImplicitConv ic = ImplicitConv::CtorThree, ObjectType* type = 0 + ); + ''' + time = Time() + obj = ObjectType() + result = time.somethingCompletelyDifferent(1, 2, ImplicitConv(2), obj) + self.assertEqual(result, Time.FourArgs) + + def testMethodWithThreeParamers(self): + '''Method with 3 parameters: Time.somethingCompletelyDifferent(...)''' + time = Time() + result = time.somethingCompletelyDifferent(1, 2, ImplicitConv(ImplicitConv.CtorOne)) + self.assertEqual(result, Time.ThreeArgs) + + def testMethodWithTwoParamers(self): + '''Method with 2 parameters: Time.somethingCompletelyDifferent(...)''' + time = Time() + result = time.somethingCompletelyDifferent(1, 2) + self.assertEqual(result, Time.TwoArgs) + + def testMethodWithThreeParamersAndImplicitConversion(self): + '''Method with 3 parameters, the last one triggers an implicit conversion.''' + time = Time() + result = time.somethingCompletelyDifferent(1, 2, ImplicitConv.CtorOne) + self.assertEqual(result, Time.ThreeArgs) + + # PYSIDE-1436: These tests crash at shutdown due to `assert(Not)?Equal`. + def testCompareWithPythonTime(self): + time = Time(12, 32, 5) + py = datetime.time(12, 32, 5) + self.assertEqual(time, py) + + def testNotEqual(self): + time = Time(12, 32, 6) + py = datetime.time(12, 32, 5) + self.assertNotEqual(time, py) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/transform_test.py b/sources/shiboken6/tests/samplebinding/transform_test.py new file mode 100644 index 000000000..7dfd18a4a --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/transform_test.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for argument modification with more than nine arguments.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Point, applyHomogeneousTransform + + +class TransformTest(unittest.TestCase): + '''Test cases for modifying a function with > 9 arguments.''' + + def testTransform_ValidMatrix(self): + '''Transform applies successfully.''' + p = Point(3, 4) + r = applyHomogeneousTransform(p, 0, 1, 0, -1, 0, 0, 0, 0, 1) + self.assertTrue(type(r) is Point) + self.assertEqual(r.x(), 4) + self.assertEqual(r.y(), -3) + + def testTransform_InvalidMatrix(self): + '''Transform does not apply successfully.''' + p = Point(3, 4) + r = applyHomogeneousTransform(p, 1, 0, 0, 0, 1, 0, 0, 0, 0) + self.assertTrue(r is None) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/typeconverters_test.py b/sources/shiboken6/tests/samplebinding/typeconverters_test.py new file mode 100644 index 000000000..987ba6dfd --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/typeconverters_test.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Tests various usages of the type converters.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +import sample + + +class GetPythonTypeByNameTest(unittest.TestCase): + + '''Uses an added function with inject code that uses the libshiboken + function "Shiboken::Conversions::getPythonTypeObject(typeName)".''' + + def testGetObjectType(self): + pyType1 = sample.getPythonType('ObjectType') + self.assertEqual(pyType1, sample.ObjectType) + pyType2 = sample.getPythonType('ObjectType*') + self.assertEqual(pyType2, sample.ObjectType) + self.assertEqual(pyType1, pyType2) + + def testGetValueType(self): + pyType1 = sample.getPythonType('Point') + self.assertEqual(pyType1, sample.Point) + pyType2 = sample.getPythonType('Point*') + self.assertEqual(pyType2, sample.Point) + self.assertEqual(pyType1, pyType2) + + def testGetUsersPrimitiveType(self): + pyType = sample.getPythonType('OddBool') + self.assertEqual(pyType, bool) + + def testGetUsersPrimitiveTypeWithoutTargetLangApiName(self): + '''If the primitive type attribute "target-lang-api-name" is not set + there'll be no Python type associated with the C++ type.''' + pyType = sample.getPythonType('PStr') + self.assertEqual(pyType, None) + + def testPrimitiveTypeAndTypedef(self): + pyType = sample.getPythonType('double') + self.assertEqual(pyType, float) + pyTypedef = sample.getPythonType('real') + self.assertEqual(pyType, pyTypedef) + + def testPairContainerType(self): + pyType = sample.getPythonType('std::pair<Complex,int>') + self.assertEqual(pyType, list) + + def testListContainerType(self): + pyType = sample.getPythonType('std::list<int>') + self.assertEqual(pyType, list) + + def testMapContainerType(self): + pyType = sample.getPythonType('std::map<std::string,int>') + self.assertEqual(pyType, dict) + + def testGlobalEnumType(self): + pyType = sample.getPythonType('GlobalEnum') + self.assertEqual(pyType, sample.GlobalEnum) + + def testScopedEnumType(self): + pyType = sample.getPythonType('Abstract::Type') + self.assertEqual(pyType, sample.Abstract.Type) + + +class CheckValueAndObjectTypeByNameTest(unittest.TestCase): + + '''Uses an added function with inject code that uses the libshiboken + functions that check if a type is Object or Value, based on its converter.''' + + def testErrors(self): + '''not existent type''' + self.assertRaises(ValueError, sample.cppTypeIsValueType, 'NotExistentType') + self.assertRaises(ValueError, sample.cppTypeIsObjectType, 'NotExistentType') + + def testObjectType1(self): + self.assertTrue(sample.cppTypeIsObjectType('ObjectType')) + self.assertFalse(sample.cppTypeIsValueType('ObjectType')) + + def testObjectType2(self): + self.assertTrue(sample.cppTypeIsObjectType('ObjectType*')) + self.assertFalse(sample.cppTypeIsValueType('ObjectType*')) + + def testValueType1(self): + self.assertTrue(sample.cppTypeIsValueType('Point')) + self.assertFalse(sample.cppTypeIsObjectType('Point')) + + def testValueType2(self): + self.assertTrue(sample.cppTypeIsValueType('Point*')) + self.assertFalse(sample.cppTypeIsObjectType('Point*')) + + def testUsersPrimitiveType(self): + self.assertFalse(sample.cppTypeIsValueType('Complex')) + self.assertFalse(sample.cppTypeIsObjectType('Complex')) + + def testContainerType(self): + self.assertFalse(sample.cppTypeIsValueType('std::list<int>')) + self.assertFalse(sample.cppTypeIsObjectType('std::list<int>')) + + +class SpecificConverterTest(unittest.TestCase): + + '''Uses an added function with inject code that uses the libshiboken + adapter class "Shiboken::Conversions::SpecificConverter".''' + + def testNotExistentType(self): + conversion = sample.getConversionTypeString('NotExistentType') + self.assertEqual(conversion, 'Invalid conversion') + + def testObjectType(self): + conversion = sample.getConversionTypeString('ObjectType') + self.assertEqual(conversion, 'Pointer conversion') + conversion = sample.getConversionTypeString('ObjectType*') + self.assertEqual(conversion, 'Pointer conversion') + conversion = sample.getConversionTypeString('ObjectType&') + self.assertEqual(conversion, 'Reference conversion') + + def testValueType(self): + conversion = sample.getConversionTypeString('Point') + self.assertEqual(conversion, 'Copy conversion') + conversion = sample.getConversionTypeString('Point*') + self.assertEqual(conversion, 'Pointer conversion') + conversion = sample.getConversionTypeString('Point&') + self.assertEqual(conversion, 'Reference conversion') + + +class StringBasedConversionTest(unittest.TestCase): + + def testValueType(self): + pts = (sample.Point(1, 1), sample.Point(2, 2), sample.Point(3, 3)) + result = sample.convertValueTypeToCppAndThenToPython(pts[0], pts[1], pts[2]) + for orig, new in zip(pts, result): + self.assertEqual(orig, new) + self.assertFalse(pts[0] is result[0]) + self.assertTrue(pts[1] is result[1]) + self.assertTrue(pts[2] is result[2]) + + def testObjectType(self): + objs = (sample.ObjectType(), sample.ObjectType()) + objs[0].setObjectName('obj0') + objs[1].setObjectName('obj1') + result = sample.convertObjectTypeToCppAndThenToPython(objs[0], objs[1]) + for orig, new in zip(objs, result): + self.assertEqual(orig, new) + self.assertEqual(orig.objectName(), new.objectName()) + self.assertTrue(orig is new) + + def testContainerType(self): + lst = range(4) + result = sample.convertListOfIntegersToCppAndThenToPython(lst) + self.assertTrue(len(result), 1) + self.assertTrue(lst, result[0]) + + +class PrimitiveConversionTest(unittest.TestCase): + + def testCppPrimitiveType(self): + integers = (12, 34) + result = sample.convertIntegersToCppAndThenToPython(integers[0], integers[1]) + for orig, new in zip(integers, result): + self.assertEqual(orig, new) + + def testLargeIntAsFloat(self): + """PYSIDE-2417: When passing an int to a function taking float, + a 64bit conversion should be done.""" + point = sample.PointF(1, 2) + large_int = 2**31 + 2 + point.setX(large_int) + self.assertEqual(round(point.x()), large_int) + + def testUnsignedLongLongAsFloat(self): + """PYSIDE-2652: When passing an unsigned long long to a function taking float, + an unsigned 64bit conversion should be done.""" + point = sample.PointF(1, 2) + large_int = 2**63 + point.setX(large_int) + self.assertEqual(round(point.x()), large_int) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/typedealloc_test.py b/sources/shiboken6/tests/samplebinding/typedealloc_test.py new file mode 100644 index 000000000..ce881e802 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/typedealloc_test.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test deallocation of type extended in Python.''' + +import gc +import os +import sys +import unittest +import weakref + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Point + + +class TypeDeallocTest(unittest.TestCase): + + def setUp(self): + self.called = False + + def tearDown(self): + del self.called + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + def callback(self, *args): + self.called = True + + def testScopeEnd(self): + ref = None + + def scope(): + + class Ext(Point): + pass + + o = Ext() # noqa: F841 + global ref + ref = weakref.ref(Ext, self.callback) + + scope() + gc.collect() + self.assertTrue(self.called) + + def testDeleteType(self): + class Ext(Point): + pass + ref = weakref.ref(Ext, self.callback) # noqa: F841 + del Ext + gc.collect() + self.assertTrue(self.called) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/typedtordoublefree_test.py b/sources/shiboken6/tests/samplebinding/typedtordoublefree_test.py new file mode 100644 index 000000000..ab8e535b5 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/typedtordoublefree_test.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import ObjectType + + +class TestTypeDestructorDoubleFree(unittest.TestCase): + def testTypeDestructorDoubleFree(self): + '''Causes the type destructors of two derived classes to be called.''' + def scope(): + class ExtObj1(ObjectType): + def __init__(self): + ObjectType.__init__(self) + obj = ExtObj1() + child = ObjectType(parent=obj) + self.assertEqual(obj.takeChild(child), child) + + class ExtObj2(ObjectType): + def __init__(self): + ObjectType.__init__(self) + + obj = ExtObj2() + child = ObjectType(parent=obj) + self.assertEqual(obj.takeChild(child), child) + scope() + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/typesystem_sample.xml b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml new file mode 100644 index 000000000..e315e599e --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/typesystem_sample.xml @@ -0,0 +1,2457 @@ +<?xml version="1.0" encoding="UTF-8"?> +<typesystem package="sample"> + <primitive-type name="ObjectType::Identifier"/> + <primitive-type name="std::nullptr_t"/> + + <primitive-type name="Foo::SAMPLE_HANDLE" target-lang-api-name="PyLong"/> + + <primitive-type name="std::size_t" target-lang-api-name="PyLong"> + <conversion-rule> + <native-to-target> + return PyLong_FromSize_t(%in); + </native-to-target> + <target-to-native> + <add-conversion type="PyLong"> + %out = %OUTTYPE(PyLong_AsSsize_t(%in)); + </add-conversion> + </target-to-native> + </conversion-rule> + </primitive-type> + + <inject-code class="native" position="beginning"> + static bool Check2TupleOfNumbers(PyObject* pyIn) { + if (!PySequence_Check(pyIn) || !(PySequence_Size(pyIn) == 2)) + return false; + Shiboken::AutoDecRef pyReal(PySequence_GetItem(pyIn, 0)); + if (!PyNumber_Check(pyReal)) + return false; + Shiboken::AutoDecRef pyImag(PySequence_GetItem(pyIn, 1)); + if (!PyNumber_Check(pyImag)) + return false; + return true; + } + </inject-code> + <primitive-type name="Complex" target-lang-api-name="PyComplex"> + <include file-name="complex.h" location="global"/> + <conversion-rule> + <native-to-target> + return PyComplex_FromDoubles(%in.real(), %in.imag()); + </native-to-target> + <target-to-native> + <!-- The 'check' attribute can be derived from the 'type' attribute, + it is defined here to test the CHECKTYPE type system variable. --> + <add-conversion type="PyComplex" check="%CHECKTYPE[Complex](%in)"> + double real = PyComplex_RealAsDouble(%in); + double imag = PyComplex_ImagAsDouble(%in); + %out = %OUTTYPE(real, imag); + </add-conversion> + <add-conversion type="PySequence" check="Check2TupleOfNumbers(%in)"> + Shiboken::AutoDecRef pyReal(PySequence_GetItem(%in, 0)); + Shiboken::AutoDecRef pyImag(PySequence_GetItem(%in, 1)); + double real = %CONVERTTOCPP[double](pyReal); + double imag = %CONVERTTOCPP[double](pyImag); + %out = %OUTTYPE(real, imag); + </add-conversion> + </target-to-native> + </conversion-rule> + </primitive-type> + + <primitive-type name="Null"> + <include file-name="null.h" location="global"/> + <conversion-rule> + <native-to-target> + SBK_UNUSED(%in); + Py_RETURN_NONE; + </native-to-target> + <target-to-native> + <add-conversion type="PyObject" check="%in == 0 || %in == Py_None"> + %out = %OUTTYPE(%in == 0); + </add-conversion> + </target-to-native> + </conversion-rule> + </primitive-type> + + <primitive-type name="SAMPLE_HANDLE" target-lang-api-name="PyComplex"> + <include file-name="handle.h" location="local"/> + <conversion-rule> + <native-to-target> + if (!%in) + Py_RETURN_NONE; + return PyCapsule_New(%in, nullptr, nullptr); + </native-to-target> + <target-to-native> + <add-conversion type="PyNone"> + SBK_UNUSED(%in) + %out = 0; + </add-conversion> + <add-conversion check="checkPyCapsuleOrPyCObject(%in)" type="PyObject"> + void *ptr = PyCapsule_GetPointer(%in, nullptr); + %out = (%OUTTYPE)ptr; + </add-conversion> + </target-to-native> + </conversion-rule> + </primitive-type> + + <inject-code class="native" position="beginning"> + static bool checkPyCapsuleOrPyCObject(PyObject* pyObj) + { + return PyCapsule_CheckExact(pyObj); + } + </inject-code> + + <primitive-type name="PrimitiveStructPtr"> + <include file-name="handle.h" location="local"/> + <conversion-rule> + <native-to-target> + return PyCapsule_New(&%in, nullptr, nullptr); + </native-to-target> + <target-to-native> + <add-conversion check="checkPyCapsuleOrPyCObject(%in)" type="PyObject"> + void *ptr = PyCapsule_GetPointer(%in, nullptr); + %out = *reinterpret_cast<%OUTTYPE*>(ptr); + </add-conversion> + </target-to-native> + </conversion-rule> + </primitive-type> + + <primitive-type name="OddBool" target-lang-api-name="PyBool" default-constructor="OddBool(false)"> + <include file-name="oddbool.h" location="global"/> + <include file-name="complex.h" location="global"/> + <conversion-rule> + <native-to-target> + return PyBool_FromLong(%in.value()); + </native-to-target> + <target-to-native> + <add-conversion type="PyBool"> + // Tests CONVERTTOCPP macro with C++ primitive type. + bool b = %CONVERTTOCPP[bool](%in); + %out = %OUTTYPE(b); + </add-conversion> + <add-conversion type="PyComplex"> + // Tests CONVERTTOCPP macro with user's primitive type. + Complex cpx = %CONVERTTOCPP[Complex](%in); + %out = %OUTTYPE(cpx.real() != 0.0 || cpx.imag() != 0.0); + </add-conversion> + </target-to-native> + </conversion-rule> + </primitive-type> + + <!-- As of Qt 6, there is a trend of hiding bool returns of comparison + operators of container classes behind some template expression using + SFINAE depending on their value's traits, like: + template <typename U = T> + friend QTypeTraits::compare_eq_result<U> operator==(const QList &l, const QList &r) + which the clang parser cannot identify. Rich comparison of classes + inheriting QList (QPolygon, QItemSelection) will then not be generated. + To work around, the operators should be added manually without + injecting code. The code should just use the standard implementation. --> + <value-type name="ComparisonTester"> + <include file-name="oddbool.h" location="global"/> + <add-function signature="operator==(const ComparisonTester&)" return-type="bool"/> + <add-function signature="operator!=(const ComparisonTester&)" return-type="bool"/> + </value-type> + <value-type name="SpaceshipComparisonTester"> + <enum-type name="Enabled"/> + </value-type> + + <primitive-type name="PStr"> + <include file-name="str.h" location="global"/> + <conversion-rule> + <native-to-target> + return Shiboken::String::fromCString(%in.cstring(), %in.size()); + </native-to-target> + <target-to-native> + <add-conversion type="PyUnicode" check="Shiboken::String::check(%in)"> + const char* str = %CONVERTTOCPP[const char*](%in); + %out = %OUTTYPE(str); + </add-conversion> + <add-conversion type="Py_None"> + SBK_UNUSED(%in) + %out = %OUTTYPE(); + </add-conversion> + </target-to-native> + </conversion-rule> + </primitive-type> + + <function signature="changePStr(PStr*, const char*)"> + <!-- + Comment out these modifications and the Shiboken generator + will issue a fatal error, because it can't handle a pointer + to a primitive type (PStr*) without help from the binding + developer. + --> + <modify-function> + <modify-argument index="1"> + <replace-type modified-type="PStr"/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject"/> + </modify-argument> + <inject-code class="target" position="beginning"> + %FUNCTION_NAME(&%1, %2); + %PYARG_0 = %CONVERTTOPYTHON[PStr](%1); + </inject-code> + </modify-function> + </function> + + <function signature="duplicatePStr(PStr*)"> + <modify-function> + <modify-argument index="return"> + <replace-type modified-type="PyObject"/> + </modify-argument> + <modify-argument index="1"> + <replace-type modified-type="PStr"/> + <replace-default-expression with="PStr()"/> + </modify-argument> + <inject-code class="target" position="end"> + %FUNCTION_NAME(&%1); + %PYARG_0 = %CONVERTTOPYTHON[PStr](%1); + </inject-code> + </modify-function> + </function> + + <primitive-type name="PStrList"> + <include file-name="strlist.h" location="global"/> + <conversion-rule> + <native-to-target> + PyObject *%out = PyList_New(Py_ssize_t(%in.size())); + Py_ssize_t idx = 0; + for (const auto &s : %in) { + PStr cppItem(s); + PyList_SET_ITEM(%out, idx++, %CONVERTTOPYTHON[PStr](cppItem)); + } + return %out; + </native-to-target> + <target-to-native> + <add-conversion type="PySequence"> + %OUTTYPE& list = %out; + Shiboken::AutoDecRef seq(PySequence_Fast(%in, 0)); + for (int i = 0; i < PySequence_Fast_GET_SIZE(seq.object()); i++) { + PyObject* pyItem = PySequence_Fast_GET_ITEM(seq.object(), i); + PStr cppItem = %CONVERTTOCPP[PStr](pyItem); + list.push_back(cppItem); + } + </add-conversion> + </target-to-native> + </conversion-rule> + </primitive-type> + + <add-function signature="createPStrList(PStr, PStr)" return-type="PyObject"> + <inject-code class="target"> + PStrList %0; + %0.push_back(%1); + %0.push_back(%2); + %PYARG_0 = %CONVERTTOPYTHON[PStrList](%0); + </inject-code> + </add-function> + <add-function signature="createListOfPStr(PStr, PStr)" return-type="PyObject"> + <inject-code class="target"> + std::list<PStr> %0; + %0.push_back(%1); + %0.push_back(%2); + %PYARG_0 = %CONVERTTOPYTHON[std::list<PStr>](%0); + </inject-code> + </add-function> + + <add-function signature="getPythonType(const char*)" return-type="PyObject"> + <inject-code class="target" position="beginning"> + SBK_UNUSED(self) + %PYARG_0 = (PyObject*) Shiboken::Conversions::getPythonTypeObject(%1); + if (!%PYARG_0) + %PYARG_0 = Py_None; + Py_INCREF(%PYARG_0); + </inject-code> + </add-function> + + <template name="cpp_type_is_object_or_value_type"> + SbkConverter* converter = Shiboken::Conversions::getConverter(%1); + if (converter) { + if (Shiboken::Conversions::pythonTypeIs$TYPEType(converter)) + %PYARG_0 = Py_True; + else + %PYARG_0 = Py_False; + Py_INCREF(%PYARG_0); + } else { + PyErr_Format(PyExc_ValueError, "Type '%s' has no converter associated to it", %1); + } + </template> + <add-function signature="cppTypeIsObjectType(const char*)" return-type="bool"> + <inject-code class="target" position="beginning"> + <insert-template name="cpp_type_is_object_or_value_type"> + <replace from="$TYPE" to="Object" /> + </insert-template> + </inject-code> + </add-function> + <add-function signature="cppTypeIsValueType(const char*)" return-type="bool"> + <inject-code class="target" position="beginning"> + <insert-template name="cpp_type_is_object_or_value_type"> + <replace from="$TYPE" to="Value" /> + </insert-template> + </inject-code> + </add-function> + + <add-function signature="getConversionTypeString(const char*)" return-type="PyObject"> + <inject-code class="target" position="beginning"> + Shiboken::Conversions::SpecificConverter converter(%1); + const char* %0 = 0; + switch (converter.conversionType()) { + case Shiboken::Conversions::SpecificConverter::CopyConversion: + %0 = "Copy conversion"; + break; + case Shiboken::Conversions::SpecificConverter::PointerConversion: + %0 = "Pointer conversion"; + break; + case Shiboken::Conversions::SpecificConverter::ReferenceConversion: + %0 = "Reference conversion"; + break; + default: + %0 = "Invalid conversion"; + } + %PYARG_0 = %CONVERTTOPYTHON[const char*](%0); + </inject-code> + </add-function> + + <inject-code class="native" position="beginning"> + static PyObject* __convertCppValuesToPython(const char** typeName, void** values, int size) + { + PyObject* result = PyTuple_New(size); + for (int i = 0; i < size; ++i) { + Shiboken::Conversions::SpecificConverter converter(typeName[i]); + PyTuple_SET_ITEM(result, i, converter.toPython(values[i])); + } + return result; + } + </inject-code> + <add-function signature="convertValueTypeToCppAndThenToPython(Point,Point*,Point&)" return-type="PyObject"> + <inject-code class="target" position="beginning"> + const char* typeNames[] = { "Point", "Point*", "Point&" }; + void* values[] = { &%1, &%2, &(%3) }; + %PYARG_0 = __convertCppValuesToPython(typeNames, values, 3); + </inject-code> + </add-function> + <add-function signature="convertObjectTypeToCppAndThenToPython(ObjectType*,ObjectType&)" return-type="PyObject"> + <inject-code class="target" position="beginning"> + const char* typeNames[] = { "ObjectType*", "ObjectType&" }; + void* values[] = { &%1, &(%2) }; + %PYARG_0 = __convertCppValuesToPython(typeNames, values, 2); + </inject-code> + </add-function> + <add-function signature="convertListOfIntegersToCppAndThenToPython(std::list<int>)" return-type="PyObject"> + <inject-code class="target" position="beginning"> + const char* typeNames[] = { "std::list<int>" }; + void* values[] = { &%1 }; + %PYARG_0 = __convertCppValuesToPython(typeNames, values, 1); + </inject-code> + </add-function> + <add-function signature="convertIntegersToCppAndThenToPython(int,int)" return-type="PyObject"> + <inject-code class="target" position="beginning"> + const char* typeNames[] = { "int", "int" }; + void* values[] = { &%1, &%2 }; + %PYARG_0 = __convertCppValuesToPython(typeNames, values, 2); + </inject-code> + </add-function> + + <template name="cpp_indexed_list_to_pylist_conversion"> + PyObject *%out = PyList_New(Py_ssize_t(%in.size())); + Py_ssize_t idx = 0; + for (auto it = %in.cbegin(), end = %in.cend(); it != end; ++it, ++idx) { + %INTYPE_0 cppItem(*it); + PyList_SET_ITEM(%out, idx, %CONVERTTOPYTHON[%INTYPE_0](cppItem)); + } + return %out; + </template> + <container-type name="List" type="list"> + <include file-name="list" location="global"/> + <conversion-rule> + <native-to-target> + <insert-template name="cpp_indexed_list_to_pylist_conversion"/> + </native-to-target> + <target-to-native> + <add-conversion type="PySequence"> + <insert-template name="shiboken_conversion_pyiterable_to_cppsequentialcontainer"/> + </add-conversion> + </target-to-native> + </conversion-rule> + </container-type> + <add-function signature="cacheSize()" return-type="int"> + <inject-code class="target"> + %RETURN_TYPE %0 = Shiboken::BindingManager::instance().getAllPyObjects().size(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </add-function> + + <namespace-type name="sample"> + <value-type name="sample" /> + </namespace-type> + + <function signature="sumComplexPair(std::pair<Complex, Complex>)" /> + <function signature="gimmeComplexList()" /> + <function signature="transmuteComplexIntoPoint(const Complex&)" /> + <function signature="transmutePointIntoComplex(const Point&)" /> + <function signature="sumComplexPair(std::pair<Complex, Complex>)" /> + <function signature="doubleUnsignedInt(unsigned int)" /> + <function signature="doubleLongLong(long long)" /> + <function signature="doubleUnsignedLongLong(unsigned long long)" /> + <function signature="doubleShort(short)" /> + <function signature="returnNullPrimitivePointer()" /> + <function signature="returnNullValueTypePointer()" /> + <function signature="returnNullObjectTypePointer()" /> + <function signature="acceptInt(int)" /> + <function signature="acceptIntReturnPtr(int)"/> + <function signature="acceptUInt(unsigned int)" /> + <function signature="acceptLong(long)" /> + <function signature="acceptULong(unsigned long)" /> + <function signature="acceptDouble(double)" /> + <function signature="acceptIntReference(int&)" /> + <function signature="acceptOddBoolReference(OddBool&)" /> + <function signature="countCharacters(const char*)" /> + <function signature="gimmeInt()" /> + <function signature="gimmeDouble()" /> + <function signature="makeCString()" /> + <function signature="sumIntArray(int[4])"/> + <function signature="sumDoubleArray(double[4])"/> + <function signature="sumIntMatrix(int[2][3])"/> + <function signature="sumDoubleMatrix(double[2][3])"/> + <function signature="multiplyPair(std::pair<double, double>)" /> + <function signature="returnCString()" /> + <function signature="overloadedFunc(double)" /> + <function signature="overloadedFunc(int)" /> + <function signature="addStdStrings(const std::string&, const std::string&)"/> + <function signature="addStdWStrings(const std::wstring&, const std::wstring&)"/> + <function signature="testNullPtrT(std::nullptr_t)"/> + <function signature="takePolygon(Polygon&&)"/> + <function signature="takeObjectType(ObjectType&&)"/> + + <value-type name="ArrayModifyTest"> + <modify-function signature="sumIntArray(int, int*)"> + <modify-argument index="2"><array/></modify-argument> + </modify-function> + </value-type> + + <value-type name="ClassWithFunctionPointer"> + <suppress-warning text="^skipping public function 'void ClassWithFunctionPointer::callFunctionPointer.*$" /> + </value-type> + + <value-type name="IntArray" generate="no"/> + <value-type name="IntArray2"> + <modify-function signature="IntArray2(const int*)"> + <modify-argument index="1"><array/></modify-argument> + </modify-function> + </value-type> + + <value-type name="IntArray3"> + <modify-function signature="IntArray3(const int*)"> + <modify-argument index="1"><array/></modify-argument> + </modify-function> + </value-type> + + <enum-type name="OverloadedFuncEnum"/> + <!-- BUG: + renaming the ICOverloadedFuncEnum to the same name + of a global enum causes the generator to confuse the + two types. + --> + <enum-type name="GlobalEnum"/> + <enum-type name="GlobalOverloadFuncEnum"/> + + <enum-type identified-by-value="AnonymousGlobalEnum_Value0"/> + + <namespace-type name="SampleNamespace"> + <namespace-type name="InlineNamespace"> + <value-type name="ClassWithinInlineNamespace"/> + <enum-type name="EnumWithinInlineNamespace"/> + </namespace-type> + <enum-type name="Option"/> + <enum-type name="InValue"/> + <enum-type name="OutValue"/> + <enum-type identified-by-value="AnonymousClassEnum_Value1"/> + + <object-type name="DerivedFromNamespace"> + <enum-type name="SampleNamespace"/> + </object-type> + <value-type name="SomeClass"> + <enum-type name="PublicScopedEnum"/> + <value-type name="SomeInnerClass"> + <object-type name="OkThisIsRecursiveEnough"> + <enum-type name="NiceEnum" /> + <enum-type name="NiceEnumClass" /> + </object-type> + <enum-type name="ProtectedEnum"/> + </value-type> + <value-type name="SomeOtherInnerClass"/> + <enum-type name="ProtectedEnum"/> + </value-type> + + <modify-function signature="doSomethingWithArray(const unsigned char*, unsigned int, const char*)"> + <modify-argument index="1"> + <replace-type modified-type="const char*"/> + <conversion-rule> + <target-to-native> + <add-conversion> + const unsigned char* %out = reinterpret_cast<const unsigned char*>(Shiboken::String::toCString(%PYARG_1)); + </add-conversion> + </target-to-native> + </conversion-rule> + </modify-argument> + <modify-argument index="2"> + <remove-argument/> + <conversion-rule class="native"> + unsigned int %out = static_cast<unsigned int>(Shiboken::String::len(%PYARG_1)); + </conversion-rule> + </modify-argument> + </modify-function> + <add-function signature="ImInsideANamespace(int, int)" return-type="int"> + <inject-code class="target"> + %RETURN_TYPE %0 = %1 + %2; + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </add-function> + <add-function signature="passReferenceToValueType(Point&)" return-type="double"> + <inject-code> + %RETURN_TYPE %0 = %1.x() + %1.y(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </add-function> + + <!-- Do change the argument from pointer to reference to comply with the C++ overload + of this function. The generator must be able to deal with this for Object Types. --> + <add-function signature="passReferenceToObjectType(ObjectType*)" return-type="int"> + <inject-code> + // The dot in "%1." must be replaced with a "->" by the generator. + %RETURN_TYPE %0 = %1.objectName().size(); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </add-function> + + <object-type name="CtParam"/> + </namespace-type> + + <namespace-type name="RemovedNamespace1" visible='false'> + <enum-type name="RemovedNamespace1_Enum" /> + <function signature="mathSum(int,int)"/> + <value-type name="ObjectOnInvisibleNamespace" /> + <namespace-type name="RemovedNamespace2" visible='false'> + <enum-type name="RemovedNamespace2_Enum" /> + </namespace-type> + <enum-type identified-by-value="RemovedNamespace1_AnonymousEnum_Value0" /> + </namespace-type> + + <namespace-type name="UnremovedNamespace"> + <namespace-type name="RemovedNamespace3" visible='false'> + <enum-type name="RemovedNamespace3_Enum" /> + <enum-type identified-by-value="RemovedNamespace3_AnonymousEnum_Value0" /> + </namespace-type> + </namespace-type> + + <namespace-type name="Photon"> + <enum-type name="ClassType"/> + <value-type name="Base"/> + <value-type name="TemplateBase" generate="no"/> + <value-type name="ValueIdentity"/> + <value-type name="ValueDuplicator"/> + </namespace-type> + + <value-type name="CVValueType"/> + <value-type name="CVListUser"/> + + <value-type name="IntList"> + <enum-type name="CtorEnum"/> + </value-type> + <value-type name="PointValueList"> + <enum-type name="CtorEnum"/> + </value-type> + <value-type name="ObjectTypePtrList"> + <enum-type name="CtorEnum"/> + </value-type> + + <object-type name="Abstract"> + <enum-type name="Type"/> + <enum-type name="PrintFormat"/> + <modify-function signature="id()" rename="id_"/> + <modify-function signature="hideFunction(HideType*)" remove="all"/> + <modify-field name="toBeRenamedField" rename="renamedField"/> + <modify-field name="readOnlyField" write="false"/> + <modify-function signature="virtualWithOutParameter(int&)const"> + <inject-code class="shell" position="override"> + x = virtualWithOutParameterPyOverride(gil, pyOverride.object()); + return; + </inject-code> + </modify-function> + <add-function signature="virtualWithOutParameterPyOverride()" + return-type="int" python-override="true"/> + </object-type> + + <object-type name="Derived" polymorphic-id-expression="%1->type() == Derived::TpDerived"> + <enum-type name="OtherOverloadedFuncEnum"/> + <value-type name="SomeInnerClass" /> + </object-type> + + <object-type name="DerivedUsingCt"/> + + <object-type name="ModifiedConstructor"> + <modify-function signature="ModifiedConstructor(int)"> + <modify-argument index="1"> + <replace-type modified-type="str"/> + </modify-argument> + <inject-code class='target' position='beginning'> + const char* tmpArg = %CONVERTTOCPP[const char*](%PYARG_1); + %0 = new %FUNCTION_NAME(atoi(tmpArg)); + </inject-code> + </modify-function> + </object-type> + + <object-type name="ObjectType" hash-function="objectTypeHash" parent-management="yes"> + <modify-function signature="deprecatedFunction()" deprecated="yes" /> + <!-- rename function to avoid Python signature conflit --> + <modify-function signature="setObject(const Null&)" rename="setNullObject" /> + + <modify-function signature="getCppParent()"> + <modify-argument index="this"> + <parent index="return" action="add" /> + </modify-argument> + <modify-argument index="return"> + <define-ownership class="target" owner="default"/> + </modify-argument> + </modify-function> + + <modify-function signature="event(Event*)"> + <modify-argument index="1" invalidate-after-use="yes"/> + </modify-function> + <modify-function signature="invalidateEvent(Event*)"> + <modify-argument index="1" invalidate-after-use="yes"/> + </modify-function> + <modify-function signature="create()"> + <modify-argument index="return"> + <define-ownership owner="target"/> + </modify-argument> + </modify-function> + <modify-function signature="createWithChild()"> + <modify-argument index="return"> + <define-ownership owner="target"/> + </modify-argument> + </modify-function> + <modify-function signature="setParent(ObjectType*)"> + <modify-argument index="this"> + <parent index="1" action="add"/> + </modify-argument> + </modify-function> + <inject-code class="native" position="beginning"> + static void reparent_layout_items(PyObject* parent, PyObject* layout) + { + // CHECKTYPE and ISCONVERTIBLE are used here for test purposes, don't change them. + if (!%CHECKTYPE[ObjectTypeLayout*](layout) && !%ISCONVERTIBLE[ObjectTypeLayout*](layout)) + return; + /* %CHECKTYPE[ObjectTypeLayout*](layout) */ + /* %ISCONVERTIBLE[ObjectTypeLayout*](layout) */ + ObjectTypeLayout* var; + var = %CONVERTTOCPP[ObjectTypeLayout*](layout); + // TODO-CONVERTER: erase this + /* + ObjectTypeLayout* var2 = %CONVERTTOCPP[ObjectTypeLayout*](layout); + */ + const ObjectTypeList& objChildren = var->objects(); + ObjectTypeList::const_iterator it = objChildren.begin(); + for (; it != objChildren.end(); ++it) { + if ((*it)->isLayoutType()) { + ObjectTypeLayout* l = reinterpret_cast<ObjectTypeLayout*>(*it); + reparent_layout_items(parent, %CONVERTTOPYTHON[ObjectTypeLayout*](l)); + Shiboken::Object::setParent(layout, %CONVERTTOPYTHON[ObjectTypeLayout*](l)); + } else { + Shiboken::Object::setParent(parent, %CONVERTTOPYTHON[ObjectType*](*it)); + } + } + } + </inject-code> + <modify-function signature="setLayout(ObjectTypeLayout*)"> + <modify-argument index="1"> + <parent index="this" action="add"/> + </modify-argument> + <inject-code class="target" position="end"> + if (%PYARG_1 != Py_None) + reparent_layout_items(%PYSELF, %PYARG_1); + </inject-code> + </modify-function> + <modify-function signature="takeChild(ObjectType*)"> + <modify-argument index="return"> + <define-ownership owner="target"/> + <parent index="this" action="remove"/> + </modify-argument> + </modify-function> + <modify-function signature="takeChild(const Str&)"> + <modify-argument index="return"> + <define-ownership owner="target"/> + <parent index="this" action="remove"/> + </modify-argument> + </modify-function> + <modify-function signature="findChild(const Str&)"> + <modify-argument index="return"> + <parent index="this" action="add"/> + </modify-argument> + </modify-function> + <modify-function signature="children()const"> + <modify-argument index="return"> + <parent index="this" action="add"/> + </modify-argument> + </modify-function> + <modify-function signature="createChild(ObjectType*)"> + <modify-argument index="return"> + <define-ownership owner="c++" /> + </modify-argument> + </modify-function> + <modify-function signature="nextInFocusChain()"> + <modify-argument index="return"> + <parent index="this" action="add"/> + </modify-argument> + </modify-function> + </object-type> + + <object-type name="OtherBase" /> + <object-type name="ObjectTypeDerived" /> + + <object-type name="ObjectTypeLayout"> + <modify-function signature="create()"> + <modify-argument index="return"> + <define-ownership owner="target"/> + </modify-argument> + </modify-function> + </object-type> + + <object-type name="ObjectView"> + <modify-function signature="ObjectView(ObjectModel*, ObjectType*)"> + <modify-argument index="1"> + <reference-count action="set" variable-name="setModel(ObjectModel*)1"/> + </modify-argument> + </modify-function> + <modify-function signature="setModel(ObjectModel*)"> + <modify-argument index="1"> + <reference-count action="set"/> + </modify-argument> + </modify-function> + </object-type> + + <object-type name="ObjectTypeHolder"/> + <value-type name="OnlyCopy"/> + <value-type name="FriendOfOnlyCopy"/> + + <object-type name="ObjectModel"> + <enum-type name="MethodCalled" /> + <modify-function signature="data() const"> + <modify-argument index="return"> + <define-ownership class="native" owner="c++"/> + </modify-argument> + </modify-function> + </object-type> + + <value-type name="Event"> + <enum-type name="EventType"/> + <enum-type name="EventTypeClass"/> + </value-type> + + <value-type name="BlackBox"> + <modify-function signature="keepObjectType(ObjectType*)"> + <modify-argument index="1"> + <define-ownership owner="c++"/> + </modify-argument> + </modify-function> + <modify-function signature="retrieveObjectType(int)"> + <modify-argument index="return"> + <define-ownership owner="target"/> + </modify-argument> + </modify-function> + <modify-function signature="keepPoint(Point*)"> + <modify-argument index="1"> + <define-ownership owner="c++"/> + </modify-argument> + </modify-function> + <modify-function signature="retrievePoint(int)"> + <modify-argument index="return"> + <define-ownership owner="target"/> + </modify-argument> + </modify-function> + </value-type> + + <value-type name="ProtectedNonPolymorphic"> + <modify-function signature="create()"> + <modify-argument index="return"> + <define-ownership owner="target"/> + </modify-argument> + </modify-function> + <modify-function signature="modifiedProtectedSum(int, int)"> + <inject-code class="target" position="beginning"> + %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%1, %2) * 10; + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </modify-function> + <modify-function signature="dataTypeName(void*) const" remove="all"/> + <modify-function signature="dataTypeName(int) const"> + <modify-argument index="1"> + <replace-default-expression with="0"/> + </modify-argument> + </modify-function> + <add-function signature="dataTypeName(PyObject*)const" return-type="const char*"> + <inject-code class="target" position="beginning"> + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(%PYARG_1); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </add-function> + </value-type> + + <value-type name="ProtectedPolymorphic"> + <modify-function signature="create()"> + <modify-argument index="return"> + <define-ownership owner="target"/> + </modify-argument> + </modify-function> + </value-type> + + <value-type name="ProtectedPolymorphicDaughter"> + <modify-function signature="create()"> + <modify-argument index="return"> + <define-ownership owner="target"/> + </modify-argument> + </modify-function> + </value-type> + + <value-type name="ProtectedPolymorphicGrandDaughter"> + <modify-function signature="create()"> + <modify-argument index="return"> + <define-ownership owner="target"/> + </modify-argument> + </modify-function> + </value-type> + + <object-type name="ProtectedVirtualDestructor"> + <modify-function signature="create()"> + <modify-argument index="return"> + <define-ownership owner="target"/> + </modify-argument> + </modify-function> + </object-type> + + + <object-type name="ProtectedEnumClass"> + <enum-type name="ProtectedEnum" /> + <enum-type name="PublicEnum" /> + </object-type> + + <value-type name="ProtectedProperty" /> + + <function signature="createProtectedProperty()" /> + + <template name="boolptr_at_end_fix_beginning"> + bool __ok__; + %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%ARGUMENT_NAMES, &__ok__); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </template> + + <template name="boolptr_at_start_fix_beginning"> + bool __ok__; + %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(&__ok__, %ARGUMENT_NAMES); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </template> + + <template name="boolptr_at_start_and_one_arg_fix_beginning"> + bool __ok__; + %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(&__ok__, %2); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </template> + + <template name="boolptr_fix_end"> + PyObject* _tuple_ = PyTuple_New(2); + PyTuple_SET_ITEM(_tuple_, 0, %PYARG_0); + PyObject* _item_ = %CONVERTTOPYTHON[bool](__ok__); + PyTuple_SET_ITEM(_tuple_, 1, _item_); + %PYARG_0 = _tuple_; + </template> + + <template name="return_4_arguments_as_tuple"> + %PYARG_0 = PyTuple_New(4); + PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[%ARG1_TYPE](%1)); + PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[%ARG2_TYPE](%2)); + PyTuple_SET_ITEM(%PYARG_0, 2, %CONVERTTOPYTHON[%ARG3_TYPE](%3)); + PyTuple_SET_ITEM(%PYARG_0, 3, %CONVERTTOPYTHON[%ARG4_TYPE](%4)); + </template> + + <template name="return_5_arguments_as_tuple"> + %PYARG_0 = PyTuple_New(5); + PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[%ARG1_TYPE](%1)); + PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[%ARG2_TYPE](%2)); + PyTuple_SET_ITEM(%PYARG_0, 2, %CONVERTTOPYTHON[%ARG3_TYPE](%3)); + PyTuple_SET_ITEM(%PYARG_0, 3, %CONVERTTOPYTHON[%ARG4_TYPE](%4)); + PyTuple_SET_ITEM(%PYARG_0, 4, %CONVERTTOPYTHON[%ARG5_TYPE](%5)); + </template> + + <template name="return_none"> + %PYARG_0 = Py_None; + Py_INCREF(Py_None); + </template> + + <object-type name="Modifications"> + <enum-type name="OverloadedModFunc"/> + <enum-type name="TestEnum"/> + + <modify-function signature="overloaded(int, bool, int, double)"> + <modify-argument index="2"> + <remove-argument/> + </modify-argument> + <inject-code class="target" position="beginning"> + %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%1, true, %3, %4); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </modify-function> + + <modify-function signature="overloaded(int, bool, int, int)"> + <modify-argument index="3"> + <remove-argument/> + <replace-default-expression with="321"/> + </modify-argument> + <!-- + <modify-argument index="4"> + <remove-default-expression/> + </modify-argument> + --> + </modify-function> + + <modify-function signature="argRemoval0(int, bool, int, int)"> + <modify-argument index="3"> + <remove-argument/> + <replace-default-expression with="321"/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject*"/> + </modify-argument> + <inject-code class="target" position="end"> + <insert-template name="return_4_arguments_as_tuple"/> + </inject-code> + </modify-function> + + <modify-function signature="argRemoval1(int, bool, Point, Point, int)"> + <modify-argument index="3"> + <remove-argument/> + </modify-argument> + <modify-argument index="4"> + <remove-argument/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject*"/> + </modify-argument> + <inject-code class="target" position="end"> + <insert-template name="return_5_arguments_as_tuple"/> + </inject-code> + </modify-function> + + <modify-function signature="argRemoval1(int, bool, int, bool)"> + <inject-code class="target" position="end"> + <insert-template name="return_none"/> + </inject-code> + </modify-function> + + <modify-function signature="argRemoval2(int, bool, Point, Point, int)"> + <modify-argument index="3"> + <remove-argument/> + </modify-argument> + <modify-argument index="4"> + <remove-argument/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject*"/> + </modify-argument> + <inject-code class="target" position="end"> + <insert-template name="return_5_arguments_as_tuple"/> + </inject-code> + </modify-function> + + <modify-function signature="argRemoval3(int, Point, bool, Point, int)"> + <modify-argument index="2"> + <remove-argument/> + </modify-argument> + <modify-argument index="4"> + <remove-argument/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject*"/> + </modify-argument> + <inject-code class="target" position="end"> + <insert-template name="return_5_arguments_as_tuple"/> + </inject-code> + </modify-function> + + <modify-function signature="argRemoval4(int, Point, bool, Point, int)"> + <modify-argument index="2"> + <remove-argument/> + <replace-default-expression with="Point(6, 9)"/> + </modify-argument> + <modify-argument index="4"> + <remove-argument/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject*"/> + </modify-argument> + <inject-code class="target" position="end"> + <insert-template name="return_5_arguments_as_tuple"/> + </inject-code> + </modify-function> + + <modify-function signature="argRemoval5(int, bool, Point, Point, int)"> + <modify-argument index="1"> + <remove-argument/> + <replace-default-expression with="100"/> + </modify-argument> + <modify-argument index="3"> + <remove-argument/> + </modify-argument> + <modify-argument index="4"> + <remove-argument/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject*"/> + </modify-argument> + <inject-code class="target" position="end"> + <insert-template name="return_5_arguments_as_tuple"/> + </inject-code> + </modify-function> + + <modify-function signature="argRemoval5(int, bool, int, bool)"> + <modify-argument index="1"> + <remove-argument/> + <replace-default-expression with="200"/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject*"/> + </modify-argument> + <inject-code class="target" position="end"> + <insert-template name="return_4_arguments_as_tuple"/> + </inject-code> + </modify-function> + + <!-- + this alteration will trigger an interesting + compile time error on the binding + --> + <!-- + <modify-function signature="overloaded(int, bool, Point, Point)"> + <modify-argument index="3"> + <remove-argument/> + </modify-argument> + </modify-function> + --> + + <!-- + renaming this signature should remove it from the other + overloaded methods decision tree + --> + <modify-function signature="overloaded(int, bool, Point, Point)" rename="over"/> + + <!-- + 'ok' must be removed and the return value will be changed + to a tuple (PyObject*) containing the expected result plus + the 'ok' value as a Python boolean + --> + <modify-function signature="pointToPair(Point, bool*)"> + <modify-argument index="2"> + <remove-argument/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject*"/> + </modify-argument> + <inject-code class="target" position="beginning"> + <insert-template name="boolptr_at_end_fix_beginning"/> + </inject-code> + <inject-code class="target" position="end"> + <insert-template name="boolptr_fix_end"/> + </inject-code> + </modify-function> + + <!-- same as 'pointToPair' except that this time 'ok' is the first argument --> + <modify-function signature="multiplyPointCoordsPlusValue(bool*, Point, double)"> + <modify-argument index="1"> + <remove-argument/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject*"/> + </modify-argument> + <inject-code class="target" position="beginning"> + <insert-template name="boolptr_at_start_fix_beginning"/> + </inject-code> + <inject-code class="target" position="end"> + <insert-template name="boolptr_fix_end"/> + </inject-code> + </modify-function> + + <!-- completely remove 'plus' from the Python side --> + <modify-function signature="doublePlus(int, int)"> + <modify-argument index="2"> + <remove-argument/> + </modify-argument> + </modify-function> + + <!-- the default value for both arguments must be changed in Python --> + <modify-function signature="power(int, int)"> + <modify-argument index="1"> + <replace-default-expression with="2"/> + </modify-argument> + <modify-argument index="2"> + <replace-default-expression with="1"/> + </modify-argument> + </modify-function> + + <!-- in Python set argument default value to 10 --> + <modify-function signature="timesTen(int)"> + <modify-argument index="1"> + <replace-default-expression with="10"/> + </modify-argument> + </modify-function> + + <!-- in Python remove the argument default value --> + <modify-function signature="increment(int)"> + <modify-argument index="1"> + <remove-default-expression/> + </modify-argument> + </modify-function> + + <!-- don't export this method to Python --> + <modify-function signature="exclusiveCppStuff()" remove="all"/> + + <!-- change the name of this regular method --> + <modify-function signature="cppMultiply(int, int)" rename="calculateArea"/> + + <!-- change the name of this virtual method --> + <modify-function signature="className()" rename="name"/> + + <modify-function signature="sumPointArray(int, const Point[])"> + <modify-argument index="1"> + <remove-argument/> + <conversion-rule class="native"> + const auto %out = PySequence_Size(%PYARG_1); + </conversion-rule> + </modify-argument> + <modify-argument index="2"> + <replace-type modified-type="PySequence" /> + <conversion-rule class="native"> + Shiboken::AutoArrayPointer<Point> %out(%1); + for (Py_ssize_t i = 0; i < %1; ++i) + %out[i] = %CONVERTTOCPP[Point](PySequence_Fast_GET_ITEM(%PYARG_1, i)); + </conversion-rule> + </modify-argument> + </modify-function> + <modify-function signature="getSize(const void*,int)"> + <modify-argument index="1"> + <replace-type modified-type="ByteArray&"/> + </modify-argument> + <modify-argument index="2"> + <replace-default-expression with="-1"/> + </modify-argument> + <inject-code class="target" position="beginning"> + int size = (%2 < 0) ? %1.size() : %2; + %BEGIN_ALLOW_THREADS + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME((const void*) %1.data(), size); + %END_ALLOW_THREADS + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </modify-function> + <modify-function signature="sumPointCoordinates(const Point*)"> + <modify-argument index="1"> + <no-null-pointer/> + </modify-argument> + </modify-function> + <template name="differenceOfPointCoordinates_arg2"> + bool _status; + bool* %2 = &_status; + </template> + <template name="differenceOfPointCoordinates_returnTarget"> + %PYARG_0 = PyTuple_New(2); + PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[bool](*%2)); + PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[%RETURN_TYPE](%0)); + </template> + <modify-function signature="differenceOfPointCoordinates(const Point*, bool*)"> + <modify-argument index="2"> + <remove-argument/> + <conversion-rule class="native"> + <insert-template name="differenceOfPointCoordinates_arg2"/> + </conversion-rule> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PySequence"/> + <conversion-rule> + <target-to-native> + <add-conversion> + Shiboken::AutoDecRef _py_ok_(PySequence_GetItem(%PYARG_0, 0)); + Shiboken::AutoDecRef _py_ret_(PySequence_GetItem(%PYARG_0, 1)); + *%2 = %CONVERTTOCPP[bool](_py_ok_); + %RETURN_TYPE %out = %CONVERTTOCPP[%RETURN_TYPE](_py_ret_); + </add-conversion> + </target-to-native> + <native-to-target> + <insert-template name="differenceOfPointCoordinates_returnTarget"/> + </native-to-target> + </conversion-rule> + </modify-argument> + </modify-function> + <modify-function signature="callDifferenceOfPointCoordinates(const Point*, bool*)"> + <modify-argument index="2"> + <remove-argument/> + <conversion-rule class="native"> + <insert-template name="differenceOfPointCoordinates_arg2"/> + </conversion-rule> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PySequence"/> + <conversion-rule class="target"> + <insert-template name="differenceOfPointCoordinates_returnTarget"/> + </conversion-rule> + </modify-argument> + </modify-function> + <modify-function signature="nonConversionRuleForArgumentWithDefaultValue(ObjectType**)"> + <modify-argument index="1"> + <remove-argument/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="(status, object)"/> + </modify-argument> + <inject-code class="target" position="beginning"> + ObjectType* tmpObject = 0; + %BEGIN_ALLOW_THREADS + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(&tmpObject); + %END_ALLOW_THREADS + %PYARG_0 = PyTuple_New(2); + PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[%RETURN_TYPE](%0)); + PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[ObjectType*](tmpObject)); + </inject-code> + </modify-function> + <modify-function signature="passOddBool(OddBool)" rename="invertBoolean"> + <inject-code class="target" position="beginning"> + %RETURN_TYPE %0 = !%CPPSELF.%FUNCTION_NAME(%1); + %PYARG_0 = %CONVERTTOPYTHON[OddBool](%0); + </inject-code> + </modify-function> + <modify-function signature="setEnumValue(Modifications::TestEnum)"> + <modify-argument index="1"> + <replace-default-expression with="cppSelf->defaultEnumValue()"/> + </modify-argument> + </modify-function> + <add-function signature="__getattro__" return-type="PyObject *"> + <inject-code class="target" position="beginning"> + cppSelf->notifyGetAttroCalled(); + </inject-code> + </add-function> + <add-function signature="__setattro__" return-type="int"> + <inject-code class="target" position="beginning"> + cppSelf->notifySetAttroCalled(); + </inject-code> + </add-function> + </object-type> + + <object-type name="AbstractModifications"> + <!-- + completely removing the pure virtual method from this + class will generate an #error directive. + --> + <!-- + <modify-function signature="pointlessPureVirtualMethod()" remove="all"/> + --> + </object-type> + + <value-type name="Reference"> + <modify-function signature="returnMyFirstArg(Reference&)"> + <modify-argument index="return"> + <replace-default-expression with="%1"/> + </modify-argument> + </modify-function> + <modify-function signature="returnMySecondArg(int, Reference&)"> + <modify-argument index="return"> + <replace-default-expression with="%2"/> + </modify-argument> + </modify-function> + </value-type> + <object-type name="ObjTypeReference"> + <modify-function signature="returnMyFirstArg(ObjTypeReference&)"> + <modify-argument index="return"> + <replace-default-expression with="%1"/> + </modify-argument> + </modify-function> + <modify-function signature="returnMySecondArg(int, ObjTypeReference&)"> + <modify-argument index="return"> + <replace-default-expression with="%2"/> + </modify-argument> + </modify-function> + <modify-function signature="justAPureVirtualFunc(ObjTypeReference&)"> + <modify-argument index="return"> + <replace-default-expression with="%1"/> + </modify-argument> + </modify-function> + </object-type> + <value-type name="ImplicitConv"> + <enum-type name="CtorEnum"/> + <enum-type name="ICOverloadedFuncEnum"/> + </value-type> + + <value-type name="VirtualMethods"> + <modify-function signature="sum0(int, int, int)" rename="sumThree"/> + <modify-function signature="sum1(int, int, int)"> + <modify-argument index="3"> + <replace-default-expression with="1000"/> + </modify-argument> + </modify-function> + <modify-function signature="sum2(int, int, int)"> + <modify-argument index="3"> + <remove-argument/> + <replace-default-expression with="2000"/> + </modify-argument> + </modify-function> + <modify-function signature="sum3(int, int, int)"> + <modify-argument index="2"> + <remove-argument/> + </modify-argument> + <inject-code class="target" position="beginning"> + %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%1, %1+%3, %3); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </modify-function> + <modify-function signature="sum4(int, int, int)"> + <modify-argument index="2"> + <remove-argument/> + <replace-default-expression with="3000"/> + </modify-argument> + <inject-code class="native" position="beginning"> + PyObject* new_arg0 = PyLong_FromLong(PyLong_AS_LONG(%PYARG_1) - %2); + Py_DECREF(%PYARG_1); + %PYARG_1 = new_arg0; + </inject-code> + </modify-function> + <modify-function signature="name()"> + <inject-code class="native" position="end"> + %0.prepend(Str("Pimped")); + </inject-code> + </modify-function> + <modify-function signature="callMe()"> + <inject-code class="native" position="end"> + PyObject_Call(%PYTHON_METHOD_OVERRIDE, %PYTHON_ARGUMENTS, NULL); + </inject-code> + </modify-function> + <modify-function signature="createStr(const char*, Str*&)"> + <modify-argument index="2"> + <remove-argument/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PySequence"/> + <conversion-rule class="native"> + Shiboken::AutoDecRef _py_ok_(PySequence_GetItem(%PYARG_0, 0)); + Shiboken::AutoDecRef _py_ret_(PySequence_GetItem(%PYARG_0, 1)); + %RETURN_TYPE %out = %CONVERTTOCPP[%RETURN_TYPE](_py_ok_); + %2 = %CONVERTTOCPP[Str*](_py_ret_); + </conversion-rule> + </modify-argument> + <inject-code class="target" position="beginning"> + Str* _str_arg_ = 0; + %RETURN_TYPE %0 = %CPPSELF.%TYPE::%FUNCTION_NAME(%1, _str_arg_); + </inject-code> + <inject-code class="target" position="end"> + %PYARG_0 = PyTuple_New(2); + PyObject* _item_ = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + PyTuple_SET_ITEM(%PYARG_0, 0, _item_); + _item_ = %CONVERTTOPYTHON[Str*](_str_arg_); + PyTuple_SET_ITEM(%PYARG_0, 1, _item_); + </inject-code> + </modify-function> + <modify-function signature="callCreateStr(const char*, Str*&)"> + <modify-argument index="2"> + <remove-argument/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PySequence"/> + </modify-argument> + <inject-code class="target" position="beginning"> + Str* _str_arg_ = 0; + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(%1, _str_arg_); + </inject-code> + <inject-code class="target" position="end"> + %PYARG_0 = PyTuple_New(2); + PyObject* _item_ = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + PyTuple_SET_ITEM(%PYARG_0, 0, _item_); + _item_ = %CONVERTTOPYTHON[Str*](_str_arg_); + PyTuple_SET_ITEM(%PYARG_0, 1, _item_); + </inject-code> + </modify-function> + <template name="fix_int*,int*,int*,int*"> + int a0, a1, a2, a3; + %BEGIN_ALLOW_THREADS + %CPPSELF->::%TYPE::%FUNCTION_NAME(&a0, &a1, &a2, &a3); + %END_ALLOW_THREADS + %PYARG_0 = PyTuple_New(4); + PyTuple_SET_ITEM(%PYARG_0, 0, %CONVERTTOPYTHON[int](a0)); + PyTuple_SET_ITEM(%PYARG_0, 1, %CONVERTTOPYTHON[int](a1)); + PyTuple_SET_ITEM(%PYARG_0, 2, %CONVERTTOPYTHON[int](a2)); + PyTuple_SET_ITEM(%PYARG_0, 3, %CONVERTTOPYTHON[int](a3)); + </template> + <template name="fix_native_return_int*,int*,int*,int*"> + PyObject* _obj = %PYARG_0; + if (!PySequence_Check(_obj) + || PySequence_Fast_GET_SIZE(_obj) != 4 + || !PyNumber_Check(PySequence_Fast_GET_ITEM(_obj, 0)) + || !PyNumber_Check(PySequence_Fast_GET_ITEM(_obj, 1)) + || !PyNumber_Check(PySequence_Fast_GET_ITEM(_obj, 2)) + || !PyNumber_Check(PySequence_Fast_GET_ITEM(_obj, 3))) { + PyErr_SetString(PyExc_TypeError, "Sequence of 4 numbers expected"); + } else { + *%1 = %CONVERTTOCPP[int](PySequence_Fast_GET_ITEM(_obj, 0)); + *%2 = %CONVERTTOCPP[int](PySequence_Fast_GET_ITEM(_obj, 1)); + *%3 = %CONVERTTOCPP[int](PySequence_Fast_GET_ITEM(_obj, 2)); + *%4 = %CONVERTTOCPP[int](PySequence_Fast_GET_ITEM(_obj, 3)); + } + </template> + <modify-function signature="getMargins(int*,int*,int*,int*)const"> + <modify-argument index="return" pyi-type="Tuple[int, int, int, int]"> + <replace-type modified-type="PyObject" /> + </modify-argument> + <modify-argument index="1"> + <remove-argument/> + </modify-argument> + <modify-argument index="2"> + <remove-argument/> + </modify-argument> + <modify-argument index="3"> + <remove-argument/> + </modify-argument> + <modify-argument index="4"> + <remove-argument/> + <remove-default-expression/> + </modify-argument> + <inject-code class="target" position="beginning"> + <insert-template name="fix_int*,int*,int*,int*"/> + </inject-code> + <inject-code class="native" position="end"> + <insert-template name="fix_native_return_int*,int*,int*,int*"/> + </inject-code> + </modify-function> + <modify-function signature="callGetMargins(int*,int*,int*,int*)const"> + <modify-argument index="0"> + <replace-type modified-type="PyObject" /> + </modify-argument> + <modify-argument index="1"> + <remove-argument/> + </modify-argument> + <modify-argument index="2"> + <remove-argument/> + </modify-argument> + <modify-argument index="3"> + <remove-argument/> + </modify-argument> + <modify-argument index="4"> + <remove-argument/> + <remove-default-expression/> + </modify-argument> + <inject-code class="target" position="beginning"> + <insert-template name="fix_int*,int*,int*,int*"/> + </inject-code> + </modify-function> + <modify-function signature="recursionOnModifiedVirtual(Str)const"> + <inject-code class="target" position="beginning"> + %BEGIN_ALLOW_THREADS + // It's important for test purposes to use a constructor with parenthesis as argument. + %RETURN_TYPE %0 = %RETURN_TYPE(%CPPSELF.%FUNCTION_NAME(Str(%1))); + %END_ALLOW_THREADS + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </modify-function> + </value-type> + <value-type name="VirtualDaughter" /> + <object-type name="VirtualDaughter2" /> + <object-type name="VirtualFinalDaughter" /> + + <value-type name="VirtualDtor"> + <modify-function signature="create()"> + <modify-argument index="return"> + <define-ownership owner="target"/> + </modify-argument> + </modify-function> + </value-type> + + <value-type name="PointerHolder"> + <modify-function signature="PointerHolder(void*)" remove="all"/> + <add-function signature="PointerHolder(PyObject*)"> + <inject-code class="target" position="beginning"> + %0 = new %TYPE(%PYARG_1); + </inject-code> + </add-function> + <modify-function signature="pointer() const"> + <inject-code class="target" position="beginning"> + %PYARG_0 = reinterpret_cast<PyObject*>(%CPPSELF.%FUNCTION_NAME()); + if (!%PYARG_0) + %PYARG_0 = Py_None; + Py_INCREF(%PYARG_0); + </inject-code> + </modify-function> + </value-type> + + <function signature="applyHomogeneousTransform(Point,double,double,double,double,double,double,double,double,double,bool*)"> + <!-- + Tests handling of the '%#' substitution for # > 9. + --> + <modify-function signature="applyHomogeneousTransform(Point,double,double,double,double,double,double,double,double,double,bool*)"> + <modify-argument index="11"> + <remove-argument/> + </modify-argument> + <inject-code class="target" position="beginning"> + bool ok_; + %RETURN_TYPE retval_ = + %FUNCTION_NAME(%1, %2, %3, %4, %5, %6, %7, %8, %9, %10, &ok_); + if (!ok_) + %PYARG_0 = Py_None; + else + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](retval_); + </inject-code> + </modify-function> + </function> + + <!-- Tests add-function for nested template types --> + <add-function signature="sum2d(std::list<std::list<int> >)" return-type="int"> + <inject-code class="target" position="beginning"> + typedef std::list<int> Inner; + typedef std::list<Inner> Outer; + + int result = 0; + + Outer::const_iterator oiter, oend = %1.end(); + for (oiter = %1.begin(); oiter != oend; ++oiter) { + const Inner& inner = *oiter; + Inner::const_iterator iiter, iend = inner.end(); + for (iiter = inner.begin(); iiter != iend; ++iiter) + result += *iiter; + } + + %PYARG_0 = %CONVERTTOPYTHON[int](result); + </inject-code> + </add-function> + + <!-- Tests add-function for nested template types --> + <add-function signature="sumproduct(std::list<std::pair<int, int> >)" return-type="int"> + <inject-code class="target" position="beginning"> + typedef std::pair<int, int> Pair; + typedef std::list<Pair> List; + + int result = 0; + + List::const_iterator iter, end = %1.end(); + for (iter = %1.begin(); iter != end; ++iter) + result += iter->first * iter->second; + + %PYARG_0 = %CONVERTTOPYTHON[int](result); + </inject-code> + </add-function> + + + <value-type name="InjectCode"> + <!-- + Various tests for inject codes. + Note: Some uses of inject code here are used just for testing purposes, consider using the add-function tag. + --> + + <modify-function signature="sumArrayAndLength(int *) const"> + <modify-argument index="1"> + <replace-type modified-type="PyObject"/> + </modify-argument> + <inject-code class="target" position="beginning"> + int* array = NULL; + bool errorOccurred = false; + + if (PySequence_Check(%PYARG_1)) { + if((array = Shiboken::sequenceToIntArray(%PYARG_1, true)) == NULL && PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, "Should be a sequence of ints"); + errorOccurred = true; + } + } else { + PyErr_SetString(PyExc_TypeError, "Should be a sequence of ints"); + errorOccurred = true; + } + + if (!errorOccurred) { + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(array); + if (array) + delete[] array; + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + } + </inject-code> + </modify-function> + + <modify-function signature="arrayMethod(int, int*) const"> + <modify-argument index="1"> + <remove-argument/> + <conversion-rule class="native"> + const auto %out = PySequence_Size(%PYARG_1); + </conversion-rule> + </modify-argument> + <modify-argument index="2"> + <replace-type modified-type="PySequence"/> + <conversion-rule class="native"> + const auto numItems = PySequence_Size(%PYARG_1); + Shiboken::AutoArrayPointer<int> %out(numItems); + for (Py_ssize_t i = 0; i < numItems; ++i) { + if (%CHECKTYPE[int](PySequence_Fast_GET_ITEM(%PYARG_1, i))) + %out[i] = %CONVERTTOCPP[int](PySequence_Fast_GET_ITEM(%PYARG_1, i)); + else if (%ISCONVERTIBLE[int](PySequence_Fast_GET_ITEM(%PYARG_1, i))) + %out[i] = -1; + else + %out[i] = -2; + } + </conversion-rule> + <conversion-rule class="target"> + PyObject* %out = PyList_New(count); + for (int i = 0; i < count; ++i) + PyList_SET_ITEM(%out, i, %CONVERTTOPYTHON[int](%in[i])); + </conversion-rule> + </modify-argument> + </modify-function> + + <modify-function signature="callArrayMethod(int, int*) const"> + <modify-argument index="1"> + <remove-argument/> + </modify-argument> + <modify-argument index="2"> + <replace-type modified-type="PySequence"/> + </modify-argument> + <inject-code class="target" position="beginning"> + int numItems = PySequence_Size(%PYARG_1); + int *cppItems = new int[numItems]; + for (int i = 0; i < numItems; i++) + cppItems[i] = %CONVERTTOCPP[int](PySequence_GetItem(%PYARG_1, i)); + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(numItems, cppItems); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + delete[] cppItems; + </inject-code> + </modify-function> + + <!-- + Inject the tp_str method using this alternative way + Tested in InjectCodeTest.testTypeNativeBeginning_TypeTargetBeginning: + --> + <inject-code class="native" position="beginning"> + PyObject* InjectCode_tpstr(PyObject*) { return Shiboken::String::fromCString("Hi! I'm the inject code dummy class."); } + </inject-code> + <!-- + Register our tp_str class using another inject code + Tested in InjectCodeTest.testTypeNativeBeginning_TypeTargetBeginning: + --> + <inject-code class="target" position="beginning"> + %PYTHONTYPEOBJECT.tp_str = InjectCode_tpstr; + </inject-code> + + <!-- Tested in InjectCodeTest.testFunctionTargetBeginning_FunctionTargetEnd --> + <modify-function signature="simpleMethod1(int, int)"> + <inject-code class="target" position="beginning"> + %1 += 1; + </inject-code> + <inject-code class="target" position="end"> + PyObject* tmp = Shiboken::String::fromCString("end"); + Shiboken::String::concat(&%PYARG_0, tmp); + Py_DECREF(tmp); + </inject-code> + </modify-function> + + <!-- Tested in InjectCodeTest.testFunctionTargetBeginning --> + <modify-function signature="simpleMethod2()"> + <inject-code class="target" position="end"> + PyObject* tmp = Shiboken::String::fromCString("end"); + Shiboken::String::concat(&%PYARG_0, tmp); + Py_DECREF(tmp); + </inject-code> + </modify-function> + + <!-- Tested in InjectCodeTest.testArgsModification --> + <modify-function signature="overloadedMethod(int, char**)"> + <modify-argument index="1"> + <replace-type modified-type="PySequence" /> + </modify-argument> + <modify-argument index="2"> + <remove-argument /> + </modify-argument> + <inject-code class="target" position="beginning"> + int argc; + char** argv; + if (!Shiboken::listToArgcArgv(%PYARG_1, &argc, &argv)) { + PyErr_SetString(PyExc_TypeError, "error"); + return 0; + } + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(argc, argv); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + for (int i = 0; i < argc; ++i) + free(argv[i]); + delete[] argv; + </inject-code> + </modify-function> + + <!-- Tested in InjectCodeTest.testArgsModification2 --> + <modify-function signature="simpleMethod3(int, char**)"> + <modify-argument index="1"> + <replace-type modified-type="PySequence" /> + </modify-argument> + <modify-argument index="2"> + <remove-argument /> + </modify-argument> + <inject-code class="target" position="beginning"> + int argc; + char** argv; + if (!Shiboken::listToArgcArgv(%PYARG_1, &argc, &argv)) { + PyErr_SetString(PyExc_TypeError, "error"); + return 0; + } + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(argc, argv); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + for (int i = 0; i < argc; ++i) + free(argv[i]); + delete[] argv; + </inject-code> + </modify-function> + </value-type> + + <value-type name="ImplicitBase"/> + <value-type name="SortedOverload"> + <add-function signature="overload(PyObject *)" return-type="const char *"> + <inject-code class="target" position="beginning"> + return Shiboken::String::fromCString("PyObject"); + </inject-code> + </add-function> + + <add-function signature="overloadDeep(int, PyObject *)" return-type="const char *"> + <inject-code class="target" position="beginning"> + return Shiboken::String::fromCString("PyObject"); + </inject-code> + </add-function> + <modify-function signature="pyObjOverload(unsigned char*, int)"> + <modify-argument index="1"> + <replace-type modified-type="PyObject" /> + <conversion-rule class="native"> + unsigned char* %out = 0; + </conversion-rule> + </modify-argument> + </modify-function> + </value-type> + <value-type name="ImplicitTarget"/> + + <object-type name="CustomOverloadSequence"> + <modify-function signature="overload(int) const" overload-number="0"/> + <modify-function signature="overload(short) const" overload-number="1"/> + </object-type> + + <value-type name="Point"> + <add-function signature="__str__" return-type="PyObject*"> + <inject-code class="target" position="beginning"> + int x1 = (int) %CPPSELF.x(); + int x2 = ((int) (%CPPSELF.x() * 100)) - (x1 * 100); + int y1 = (int) %CPPSELF.y(); + int y2 = ((int) (%CPPSELF.y() * 100)) - (y1 * 100); + %PYARG_0 = Shiboken::String::fromFormat("Point(%d.%d, %d.%d)", x1, x2, y1, y2); + </inject-code> + </add-function> + <add-function signature="__repr__" return-type="PyObject*"> + <inject-code class="target" position="beginning"> + int x1 = (int) %CPPSELF.x(); + int x2 = ((int) (%CPPSELF.x() * 10)) - (x1 * 10); + int y1 = (int) %CPPSELF.y(); + int y2 = ((int) (%CPPSELF.y() * 10)) - (y1 * 10); + %PYARG_0 = Shiboken::String::fromFormat("<Point object at %p: (%d.%d, %d.%d)>", %CPPSELF, x1, x2, y1, y2); + </inject-code> + </add-function> + + <add-function signature="__reduce__" return-type="PyObject*"> + <inject-code class="target" position="beginning"> + PyObject* type = PyObject_Type(%PYSELF); + PyObject* args = NULL; + + args = Py_BuildValue("(dd)", %CPPSELF.x(), %CPPSELF.y()); + + %PYARG_0 = Py_BuildValue("(OO)", type, args); + </inject-code> + </add-function> + + <modify-function signature="midpoint(const Point&, Point*)const"> + <modify-argument index="2"> + <remove-argument /> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="Point" /> + </modify-argument> + <inject-code class="target" position="beginning"> + Point _midpoint; + // The test consists in *NOT* using the ARGUMENT_NAMES type system variable. + %CPPSELF.%FUNCTION_NAME(%1, &_midpoint); + %PYARG_0 = %CONVERTTOPYTHON[Point](_midpoint); + </inject-code> + </modify-function> + + <template name="return_self"> + %PYARG_0 = %PYARG_1; + Py_INCREF(%PYARG_1); + </template> + <add-function signature="operator-(PyUnicode)"> + <inject-code> + <insert-template name="return_self" /> + </inject-code> + </add-function> + <!-- A reverse operator --> + <add-function signature="operator-(PyUnicode, Point)"> + <inject-code> + <insert-template name="return_self" /> + </inject-code> + </add-function> + </value-type> + + <value-type name="PointF"> + <add-function signature="__str__" return-type="PyObject*"> + <inject-code class="target" position="beginning"> + int x1 = (int) %CPPSELF.x(); + int x2 = ((int) (%CPPSELF.x() * 100)) - (x1 * 100); + int y1 = (int) %CPPSELF.y(); + int y2 = ((int) (%CPPSELF.y() * 100)) - (y1 * 100); + %PYARG_0 = Shiboken::String::fromFormat("PointF(%d.%d, %d.%d)", x1, x2, y1, y2); + </inject-code> + </add-function> + <add-function signature="__repr__" return-type="PyObject*"> + <inject-code class="target" position="beginning"> + int x1 = (int) %CPPSELF.x(); + int x2 = ((int) (%CPPSELF.x() * 10)) - (x1 * 10); + int y1 = (int) %CPPSELF.y(); + int y2 = ((int) (%CPPSELF.y() * 10)) - (y1 * 10); + %PYARG_0 = Shiboken::String::fromFormat("<PointF object at %p: (%d.%d, %d.%d)>", %CPPSELF, x1, x2, y1, y2); + </inject-code> + </add-function> + + <add-function signature="__reduce__" return-type="PyObject*"> + <inject-code class="target" position="beginning"> + PyObject *type = PyObject_Type(%PYSELF); + PyObject *args = NULL; + + args = Py_BuildValue("(dd)", %CPPSELF.x(), %CPPSELF.y()); + + %PYARG_0 = Py_BuildValue("(OO)", type, args); + </inject-code> + </add-function> + + <modify-function signature="midpoint(const PointF&, PointF*)const"> + <modify-argument index="2"> + <remove-argument /> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PointF" /> + </modify-argument> + <inject-code class="target" position="beginning"> + PointF _midpoint; + // The test consists in using the ARGUMENT_NAMES type system variable. + %CPPSELF.%FUNCTION_NAME(%ARGUMENT_NAMES, &_midpoint); + %PYARG_0 = %CONVERTTOPYTHON[PointF](_midpoint); + </inject-code> + </modify-function> + </value-type> + + <value-type name="Rect" /> + <value-type name="RectF" /> + + <value-type name="Polygon"> + <modify-function signature="stealOwnershipFromPython(Point*)"> + <modify-argument index="1"> + <define-ownership owner="c++"/> + </modify-argument> + </modify-function> + <modify-function signature="stealOwnershipFromPython(Polygon*)"> + <modify-argument index="1"> + <define-ownership owner="c++"/> + </modify-argument> + </modify-function> + </value-type> + + <value-type name="Time"> + <extra-includes> + <include file-name="datetime.h" location="global"/> + </extra-includes> + <enum-type name="NumArgs"/> + <add-function signature="operator!=(const PyObject*)" return-type="PyObject"> + <inject-code> + if (!PyDateTimeAPI) + PyDateTime_IMPORT; + if (PyTime_Check(%1)) { + int pyH = PyDateTime_TIME_GET_HOUR(%1); + int pyM = PyDateTime_TIME_GET_MINUTE(%1); + int pyS = PyDateTime_TIME_GET_SECOND(%1); + if ((pyH == %CPPSELF.hour()) && + (pyM == %CPPSELF.minute()) && + (pyS == %CPPSELF.second())) + %PYARG_0 = Py_False; + else + %PYARG_0 = Py_True; + Py_INCREF(%PYARG_0); + } + </inject-code> + </add-function> + <add-function signature="operator==(const PyObject*)" return-type="PyObject"> + <inject-code> + if (!PyDateTimeAPI) + PyDateTime_IMPORT; + if (PyTime_Check(%1)) { + int pyH = PyDateTime_TIME_GET_HOUR(%1); + int pyM = PyDateTime_TIME_GET_MINUTE(%1); + int pyS = PyDateTime_TIME_GET_SECOND(%1); + if ((pyH == %CPPSELF.hour()) && + (pyM == %CPPSELF.minute()) && + (pyS == %CPPSELF.second())) + %PYARG_0 = Py_True; + else + %PYARG_0 = Py_False; + Py_INCREF(%PYARG_0); + } + </inject-code> + </add-function> + + </value-type> + <value-type name="Size"> + <extra-includes> + <include file-name="string" location="global"/> + <include file-name="sstream" location="global"/> + </extra-includes> + <add-function signature="Size(const char*)"> + <inject-code class="target" position="beginning" + file="samplesnippets.cpp" snippet="size_char_ct"/> + </add-function> + </value-type> + <value-type name="SizeF"/> + <function signature="SnakeCaseGlobalFunction()" snake-case="yes"/> + <object-type name="SnakeCaseTest" snake-case="yes"> + <modify-function signature="testFunctionDisabled()const" snake-case="no"/> + <modify-function signature="testFunctionBoth()const" snake-case="both"/> + <modify-field name="testFieldDisabled" snake-case="no"/> + <modify-field name="testFieldBoth" snake-case="both"/> + </object-type> + <object-type name="SnakeCaseDerivedTest" snake-case="yes"/> + <value-type name="MapUser"/> + <value-type name="PairUser"/> + <value-type name="ListUser"> + <enum-type name="ListOfSomething"/> + </value-type> + <value-type name="NoImplicitConversion" /> + <value-type name="NonDefaultCtor" /> + <value-type name="OddBoolUser" /> + <object-type name="Overload"> + <enum-type name="FunctionEnum"/> + <enum-type name="ParamEnum"/> + <modify-function signature="intOverloads(int, int, double)"> + <modify-argument index="2"> + <remove-argument /> + </modify-argument> + <inject-code class="target"> + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(%1, 2, %3); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </modify-function> + <modify-function signature="singleOverload(Point*)"> + <modify-argument index="1"> + <define-ownership owner="c++"/> + </modify-argument> + </modify-function> + <modify-function signature="acceptSequence(const char*const[])"> + <modify-argument index="1"> + <replace-type modified-type="PySequence" /> + <conversion-rule class="native"> + { + Shiboken::AutoDecRef strList(PySequence_Fast(%PYARG_1, "The argument must be a sequence.")); + int lineCount = PySequence_Fast_GET_SIZE(strList.object()); + for (int line = 0; line < lineCount; ++line) { + if (!Shiboken::String::check(PySequence_Fast_GET_ITEM(strList.object(), line))) { + PyErr_SetString(PyExc_TypeError, "The argument must be a sequence of strings."); + break; + } + } + } + // PySIDE-1735: Enums are now implemented in Python, so we need to avoid asserts. + if (PyErr_Occurred()) + break; + const char** %out = 0; + </conversion-rule> + </modify-argument> + </modify-function> + <modify-function signature="acceptSequence(void*)"> + <modify-argument index="1"> + <replace-type modified-type="PyObject" /> + <conversion-rule class="native"> + void* %out = 0; + </conversion-rule> + </modify-argument> + </modify-function> + + <template name="buffer_argument"> + unsigned char* %out = (unsigned char*) Shiboken::Buffer::getPointer(%PYARG_1); + </template> + + <modify-function signature="strBufferOverloads(unsigned char*,int)"> + <modify-argument index="1"> + <replace-type modified-type="PyBuffer"/> + <conversion-rule class="native"> + <insert-template name="buffer_argument" /> + </conversion-rule> + </modify-argument> + </modify-function> + <!-- + This added function simulates the solution given to PySide's QImage + constructor problem, as seen in PySide/bbba1cc4, and described in + bug #489 [http://bugs.pyside.org/show_bug.cgi?id=489]. + This is not the best solution, just one that works. The proper way + to handle it would be to fix the overload decisor. + --> + <add-function signature="strBufferOverloads(Str&,int)" return-type="Overload::FunctionEnum"> + <inject-code class="target" position="beginning"> + <insert-template name="buffer_argument"> + <replace from="%out" to="argOut" /> + </insert-template> + %BEGIN_ALLOW_THREADS + %RETURN_TYPE %0 = %CPPSELF.%FUNCTION_NAME(argOut, %2); + %END_ALLOW_THREADS + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </add-function> + </object-type> + <object-type name="Overload2" /> + + <object-type name="Collector" stream="yes"/> + + <value-type name="IntWrapper"> + <inject-code class="native" position="beginning" + file="samplesnippets.cpp" snippet="intwrapper_add_ints"/> + <add-pymethoddef name="add_ints" function="Sbk_IntWrapper_add_ints" + flags="METH_VARARGS"/> + </value-type> + + <value-type name="Str" hash-function="strHash"> + <add-function signature="__str__" return-type="PyObject*"> + <inject-code class="target" position="beginning"> + %PYARG_0 = Shiboken::String::fromCString(%CPPSELF.cstring()); + </inject-code> + </add-function> + <add-function signature="__len__" > + <inject-code class="target" position="end"> + return %CPPSELF.size(); + </inject-code> + </add-function> + <add-function signature="__getitem__" > + <inject-code class="target" position="beginning"> + if (_i < 0 || _i >= %CPPSELF.size()) { + PyErr_BadArgument(); + return 0; + } else { + char res[2]; + res[0] = %CPPSELF.get_char(_i); + res[1] = 0; + return Shiboken::String::fromCString(res); + } + </inject-code> + </add-function> + <add-function signature="__setitem__" > + <inject-code class="target" position="beginning"> + PyObject* args = Py_BuildValue("(iO)", _i, _value); + PyObject* result = Sbk_StrFunc_set_char(self, args); + Py_DECREF(args); + int ok = result == Py_True; + if (result) { + Py_DECREF(result); + } + return !ok ? -1 : 0; + </inject-code> + </add-function> + <modify-function signature="toInt(bool*, int)const"> + <modify-argument index="1"> + <remove-argument/> + </modify-argument> + <modify-argument index="return"> + <replace-type modified-type="PyObject*"/> + </modify-argument> + <inject-code class="target" position="beginning"> + <insert-template name="boolptr_at_start_and_one_arg_fix_beginning"/> + </inject-code> + <inject-code class="target" position="end"> + <insert-template name="boolptr_fix_end"/> + </inject-code> + </modify-function> + </value-type> + + <value-type name="ByteArray" hash-function="ByteArray::hash"> + <conversion-rule> + <target-to-native> + <add-conversion type="Py_None"> + SBK_UNUSED(%in) + %out = %OUTTYPE(); + </add-conversion> + <add-conversion type="PyObject" check="Shiboken::String::check(%in) || PyBytes_Check(%in)"> + Py_ssize_t len; + const char* str = Shiboken::String::toCString(%in, &len); + %out = %OUTTYPE(str, len); + </add-conversion> + </target-to-native> + </conversion-rule> + + <modify-function signature="ByteArray(const char*,int)" remove="all" /> + <modify-function signature="ByteArray(const char*)" remove="all" > + <!-- Keep \x00 bytes passed in Python strings. --> + <modify-argument index="1"> + <replace-type modified-type="PyBytes"/> + </modify-argument> + <inject-code class="target" position="beginning"> + PyObject* data = 0; + if (PyUnicode_CheckExact(%PYARG_1)) { + data = PyUnicode_AsASCIIString(%PYARG_1); + } else { + data = %PYARG_1; + Py_INCREF(data); + } + + %0 = new %TYPE(PyBytes_AsString(data), PyBytes_GET_SIZE(data)); + Py_DECREF(data); + </inject-code> + </modify-function> + + <!-- buffer protocol --> + <inject-code class="target" position="end"> + </inject-code> + + <modify-function signature="data() const"> + <inject-code class="target" position="beginning"> + %PYARG_0 = PyBytes_FromStringAndSize(%CPPSELF.%FUNCTION_NAME(), %CPPSELF.size()); + </inject-code> + </modify-function> + + <modify-function signature="hash(const ByteArray&)" remove="all" /> + <!-- Functions removed to proper deal with strings containing zeroes --> + <modify-function signature="append(const char*)" remove="all" /> + <modify-function signature="append(const char*,int)" remove="all" /> + <modify-function signature="operator==(const char*,ByteArray)" remove="all" /> + <modify-function signature="operator==(ByteArray,const char*)" remove="all" /> + <modify-function signature="operator!=(const char*,ByteArray)" remove="all" /> + <modify-function signature="operator!=(ByteArray,const char*)" remove="all" /> + <modify-function signature="operator+(ByteArray,const char*)" remove="all" /> + <modify-function signature="operator+(const char*,ByteArray)" remove="all" /> + <modify-function signature="operator+=(const char*)" remove="all" /> + <modify-function signature="operator[](int)const" remove="all"/> + + <add-function signature="operator+(PyUnicode)" return-type="ByteArray"> + <inject-code> + Shiboken::AutoDecRef data(PyUnicode_AsASCIIString(%PYARG_1)); + if (!data.isNull()) { + ByteArray ba(*%CPPSELF); + ba.append(PyBytes_AsString(data.object()), PyBytes_GET_SIZE(data.object())); + %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba); + } + </inject-code> + </add-function> + <add-function signature="operator+(PyUnicode,ByteArray)" return-type="ByteArray"> + <inject-code> + Shiboken::AutoDecRef data(PyUnicode_AsASCIIString(%PYARG_1)); + if (!data.isNull()) { + ByteArray ba(PyBytes_AsString(data.object()), PyBytes_GET_SIZE(data.object())); + ba.append(*%CPPSELF); + %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba); + } + </inject-code> + </add-function> + <add-function signature="operator+(PyBytes,ByteArray)"> + <inject-code> + ByteArray ba(PyBytes_AsString(%PYARG_1), PyBytes_GET_SIZE(%PYARG_1)); + ba = ba + *%CPPSELF; + %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba); + </inject-code> + </add-function> + <add-function signature="operator+(PyBytes)"> + <inject-code> + ByteArray ba(PyBytes_AsString(%PYARG_1), PyBytes_GET_SIZE(%PYARG_1)); + ba.append(*%CPPSELF); + %PYARG_0 = %CONVERTTOPYTHON[ByteArray](ba); + </inject-code> + </add-function> + <add-function signature="__repr__" return-type="PyObject*"> + <inject-code class="target" position="beginning"> + ByteArray b(Py_TYPE(%PYSELF)->tp_name); + PyObject* aux = Shiboken::String::fromStringAndSize(%CPPSELF.data(), %CPPSELF.size()); + if (PyUnicode_CheckExact(aux)) { + PyObject* tmp = PyUnicode_AsASCIIString(aux); + Py_DECREF(aux); + aux = tmp; + } + b += "('"; + b += ByteArray(PyBytes_AS_STRING(aux), PyBytes_GET_SIZE(aux)); + b += "')"; + %PYARG_0 = Shiboken::String::fromStringAndSize(b.data(), b.size()); + </inject-code> + </add-function> + + <add-function signature="__str__" return-type="str"> + <inject-code class="target" position="beginning"> + %PYARG_0 = Shiboken::String::fromStringAndSize(%CPPSELF.data(), %CPPSELF.size()); + </inject-code> + </add-function> + + <add-function signature="__len__"> + <inject-code class="target" position="beginning"> + return %CPPSELF.size(); + </inject-code> + </add-function> + <add-function signature="__getitem__"> + <inject-code class="target" position="beginning"> + if (_i < 0 || _i >= %CPPSELF.size()) { + PyErr_SetString(PyExc_IndexError, "index out of bounds"); + return 0; + } else { + char res[2]; + res[0] = %CPPSELF.at(_i); + res[1] = 0; + return PyBytes_FromStringAndSize(res, 1); + } + </inject-code> + </add-function> + </value-type> + + <value-type name="StrList"> + <enum-type name="CtorEnum"/> + <add-function signature="__len__" > + <inject-code class="target" position="end"> + return %CPPSELF.size(); + </inject-code> + </add-function> + <add-function signature="__getitem__" > + <inject-code class="target" position="beginning"> + if (_i < 0 || _i >= static_cast<Py_ssize_t>(%CPPSELF.size())) { + PyErr_BadArgument(); + return 0; + } else { + %TYPE::const_iterator it = %CPPSELF.begin(); + for (Py_ssize_t i = 1; i <= _i; i++) + ++it; + return %CONVERTTOPYTHON[Str](*it); + } + </inject-code> + </add-function> + </value-type> + + <object-type name="SimpleFile"> + <modify-function signature="open()"> + <modify-argument index="return"> + <remove-argument/> + </modify-argument> + <inject-code class="target" position="end" file="simplefile_glue.cpp"/> + </modify-function> + </object-type> + + <value-type name="VoidHolder" /> + + <object-type name="PrivateCtor" /> + <object-type name="PrivateDtor" /> + <value-type name="DeletedDefaultCtor"/> + + <object-type name="Base1"/> + <object-type name="Base2"/> + <object-type name="Base3"/> + <object-type name="Base4"/> + <object-type name="Base5"/> + <object-type name="Base6"/> + <object-type name="MDerived1"/> + <object-type name="MDerived2"/> + <object-type name="MDerived3"/> + <object-type name="MDerived4"/> + <object-type name="MDerived5"/> + <object-type name="SonOfMDerived1"/> + + <object-type name="Bucket" private="true"> + <modify-function signature="lock()" allow-thread="yes" /> + <modify-function signature="virtualBlockerMethod()" allow-thread="yes"/> + <modify-function signature="callVirtualBlockerMethodButYouDontKnowThis()" allow-thread="yes"/> + </object-type> + + <value-type name="Echo"> + <add-function signature="echo(const char *)" return-type="PyObject*"> + <inject-code class="target" position="beginning"> + %PYARG_0 = Shiboken::String::fromCString(%1); + </inject-code> + </add-function> + <add-function signature="operator>(int)"> + <inject-code> + // This should test if code injections works inside rich comparison operators + Py_INCREF(Py_True); + %PYARG_0 = Py_True; + </inject-code> + </add-function> + </value-type> + + <value-type name="Color" /> + <value-type name="Brush" operator-bool="true"> + <enum-type name="Style"/> + </value-type> + <value-type name="Pen"> + <enum-type identified-by-value="EnumCtor"/> + <enum-type name="RenderHints"/> + <property type="RenderHints" name="renderHints" get="getRenderHints" set="setRenderHints"/> + </value-type> + + <value-type name="CtorConvRule" private="true"> + <modify-function signature="CtorConvRule(long)"> + <modify-argument index="1"> + <!--<replace-type modified-type="long"/>--> + <conversion-rule class="native"> + // Does nothing really, just test the code generation + // of constructors whose arguments where + long %out = PyLong_AS_LONG(%PYARG_1) + 1; + </conversion-rule> + </modify-argument> + </modify-function> + </value-type> + + <add-function signature="multiplyString(str, unsigned int)" return-type="const char*"> + <inject-code class="target" position="beginning"> + %PYARG_0 = Shiboken::String::fromCString(""); + for (unsigned int i = 0; i < %2; ++i) + Shiboken::String::concat(&%PYARG_0, %PYARG_1); + </inject-code> + </add-function> + + <add-function signature="countVarargs(int, ...)" return-type="int"> + <inject-code class="target" position="beginning"> + %RETURN_TYPE %0 = PyTuple_GET_SIZE(%PYARG_2); + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </add-function> + + <value-type name="SbkDate"> + <extra-includes> + <include file-name="datetime.h" location="global"/> + </extra-includes> + <inject-code class="native" position="beginning"> + static bool PyDate_ImportAndCheck(PyObject* pyIn) { + if (!PyDateTimeAPI) + PyDateTime_IMPORT; + return PyDate_Check(pyIn); + } + </inject-code> + <conversion-rule> + <target-to-native> + <add-conversion type="PyDate" check="PyDate_ImportAndCheck(%in)"> + int day = PyDateTime_GET_DAY(%in); + int month = PyDateTime_GET_MONTH(%in); + int year = PyDateTime_GET_YEAR(%in); + %out = %OUTTYPE(day, month, year); + </add-conversion> + </target-to-native> + </conversion-rule> + <add-function signature="toPython()" return-type="PyDate"> + <inject-code class="target"> + if (!PyDateTimeAPI) + PyDateTime_IMPORT; + %PYARG_0 = PyDate_FromDate(%CPPSELF.day(), %CPPSELF.month(), %CPPSELF.year()); + </inject-code> + </add-function> + </value-type> + + <object-type name="HandleHolder" /> + <value-type name="PrimitiveStructPointerHolder" /> + + <object-type name="ObjectTypeOperators"> + <add-function signature="operator!=(std::string)" return-type="bool"> + <inject-code class="target"> + %RETURN_TYPE %0 = %CPPSELF.key() != %1; + %PYARG_0 = %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </add-function> + </object-type> + + <value-type name="Filter" /> + <value-type name="Data"> + <enum-type name="Field" /> + <add-function signature="operator&(const Union&)" return-type="Intersection"> + <inject-code class="target"> + %RETURN_TYPE %0 = *%CPPSELF & %1; + return %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </add-function> + </value-type> + <value-type name="Union"> + <add-function signature="operator&(const Data&)" return-type="Intersection"> + <inject-code class="target"> + %RETURN_TYPE %0 = *%CPPSELF & %1; + return %CONVERTTOPYTHON[%RETURN_TYPE](%0); + </inject-code> + </add-function> + </value-type> + <value-type name="Intersection" /> + + <!-- type used in abstract method --> + <object-type name="HideType" generate="no" /> + + <value-type name="Expression" /> + + <object-type name="ExceptionTest" exception-handling="auto-on"> + <modify-function signature="create(bool)"> + <modify-argument index="return"> + <define-ownership owner="c++"/> + </modify-argument> + <inject-code class="target" position="end"> + // Test comment + </inject-code> + </modify-function> + </object-type> + + <value-type name="ModelIndex" /> + <value-type name="ReferentModelIndex"> + <modify-function signature="operator const ModelIndex&()const"> + <modify-argument index="return"> + <define-ownership owner="c++"/> + </modify-argument> + </modify-function> + </value-type> + <value-type name="PersistentModelIndex" /> + + <!-- test rejections using full signatures; this method is a template and + cannot be wrapped, but is otherwise recognized by shiboken and will + result in a compile error if the rejection is not matched --> + <rejection class="Photon::Base" function-name="isType()"/> + + <value-type name="ValueAndVirtual" /> + + <object-type name="ObjectTypeByValue" /> + + <value-type name="StdComplex"> + <extra-includes> + <include file-name="cmath" location="global"/> + </extra-includes> + <!-- PYSIDE-2446: number protocols without a Py_nb_ constant. --> + <add-function signature="__floor__()" return-type="double"> + <inject-code class="target" position="end" + file="samplesnippets.cpp" snippet="stdcomplex_floor"/> + </add-function> + <add-function signature="__ceil__()" return-type="double"> + <inject-code class="target" position="end" + file="samplesnippets.cpp" snippet="stdcomplex_ceil"/> + </add-function> + <!-- PYSIDE-2446: number protocols with Py_nb_ constants. --> + <add-function signature="__abs__()" return-type="double"> + <inject-code class="target" position="end" + file="samplesnippets.cpp" snippet="stdcomplex_abs"/> + </add-function> + <add-function signature="__pow__(StdComplex@exp@)" return-type="StdComplex"> + <inject-code class="target" position="end" + file="samplesnippets.cpp" snippet="stdcomplex_pow"/> + </add-function> + + </value-type> + + <object-type name="TemplatePtr"> + <modify-function signature="dummy(std::list<std::pair<BlackBox *, BlackBox *> > &)" rename="dummy_method" /> + </object-type> + + <value-type name="ToBeRenamedValue" target-lang-name="RenamedValue"/> + <value-type name="RenamedUser"/> + + <enum-type name="LengthUnit"/> + <value-type name="ValueWithUnit" generate="no"/> + <typedef-type name="ValueWithUnitDoubleInch" source="ValueWithUnit<double,LengthUnit::Inch>"/> + <typedef-type name="ValueWithUnitDoubleMillimeter" source="ValueWithUnit<double,LengthUnit::Millimeter>"/> + <value-type name="ValueWithUnitUser"/> + + <suppress-warning text="horribly broken type '__off64_t'" /> + <suppress-warning text="enum '__codecvt_result' does not have a type entry or is not an enum" /> + <suppress-warning text="Pure virtual method 'Abstract::hideFunction(HideType*)' must be implemented but was completely removed on type system." /> + <suppress-warning text="Shadowing: MDerived2::castToBase3() and MDerived3::castToBase3()" /> + <suppress-warning text="Visibility of function 'publicMethod' modified in class 'MDerived1'" /> + + <suppress-warning text="^skipping public function 'std::enable_if.*ComparisonTester::operator[!=]=.*ComparisonTester.*$"/> +</typesystem> diff --git a/sources/shiboken6/tests/samplebinding/typesystypedef_test.py b/sources/shiboken6/tests/samplebinding/typesystypedef_test.py new file mode 100644 index 000000000..f7f5342ee --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/typesystypedef_test.py @@ -0,0 +1,29 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test case for a class that holds a void pointer.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ValueWithUnitUser, ValueWithUnitDoubleInch + + +class TypeSysTypeDefTest(unittest.TestCase): + '''Test case type system typedefs.''' + + def test(self): + inch_value = ValueWithUnitDoubleInch(10) + mm_value = ValueWithUnitUser.doubleInchToMillimeter(inch_value) + self.assertEqual(int(mm_value.value()), 2540) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/unsafe_parent_test.py b/sources/shiboken6/tests/samplebinding/unsafe_parent_test.py new file mode 100644 index 000000000..2a7e5cac7 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/unsafe_parent_test.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for ...''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType + + +class DerivedObjectType(ObjectType): + def isPython(self): + return True + + def createChild(self, parent): + return DerivedObjectType(parent) + + +class ParentTest(unittest.TestCase): + + def testUunsafeParent(self): + o = DerivedObjectType() + o.callVirtualCreateChild() + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/useraddedctor_test.py b/sources/shiboken6/tests/samplebinding/useraddedctor_test.py new file mode 100644 index 000000000..45d4095b6 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/useraddedctor_test.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for user added constructors''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from sample import Size + + +class PointTest(unittest.TestCase): + def testUsingSelfOnCtor(self): + # This is a user added ctor and no errors should happen! + s = Size("3x2") + self.assertEqual(s.height(), 2) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/virtualdtor_test.py b/sources/shiboken6/tests/samplebinding/virtualdtor_test.py new file mode 100644 index 000000000..6be870269 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/virtualdtor_test.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for virtual destructor.''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import VirtualDtor + + +class ExtendedVirtualDtor(VirtualDtor): + def __init__(self): + VirtualDtor.__init__(self) + + +class VirtualDtorTest(unittest.TestCase): + '''Test case for virtual destructor.''' + + def setUp(self): + VirtualDtor.resetDtorCounter() + + def testVirtualDtor(self): + '''Original virtual destructor is being called.''' + dtor_called = VirtualDtor.dtorCalled() + for i in range(1, 10): + vd = VirtualDtor() + del vd + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(VirtualDtor.dtorCalled(), dtor_called + i) + + def testVirtualDtorOnCppCreatedObject(self): + '''Original virtual destructor is being called for a C++ created object.''' + dtor_called = VirtualDtor.dtorCalled() + for i in range(1, 10): + vd = VirtualDtor.create() + del vd + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(VirtualDtor.dtorCalled(), dtor_called + i) + + def testDtorOnDerivedClass(self): + '''Original virtual destructor is being called for a derived class.''' + dtor_called = ExtendedVirtualDtor.dtorCalled() + for i in range(1, 10): + evd = ExtendedVirtualDtor() + del evd + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(ExtendedVirtualDtor.dtorCalled(), dtor_called + i) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/virtualmethods_test.py b/sources/shiboken6/tests/samplebinding/virtualmethods_test.py new file mode 100644 index 000000000..52dc66c90 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/virtualmethods_test.py @@ -0,0 +1,130 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test cases for virtual methods.''' + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Point, Str, StrList, VirtualDaughter, VirtualMethods + +import warnings + + +class ExtendedVirtualMethods(VirtualMethods): + def __init__(self): + VirtualMethods.__init__(self) + self.virtual_method0_called = False + + def virtualMethod0(self, pt, val, cpx, b): + self.virtual_method0_called = True + return VirtualMethods.virtualMethod0(self, pt, val, cpx, b) * -1.0 + + def strListToStdList(self, arg): + warnings.simplefilter('error') + # returning wrong type for test purposes. + return True + + def recursionOnModifiedVirtual(self, arg): + # check if recursion is caused by injected code that calls C++. + return VirtualMethods.recursionOnModifiedVirtual(self, arg) + 10 + + +class ExtendedVirtualDaughter(VirtualDaughter): + def __init__(self, name): + VirtualDaughter.__init__(self, name) + self.grand_daughter_name_called = False + + def name(self): + self.grand_daughter_name_called = True + return VirtualDaughter.name(self).prepend('Extended') + + +class ExtendedExtendedVirtualDaughter(ExtendedVirtualDaughter): + def __init__(self, name): + ExtendedVirtualDaughter.__init__(self, name) + self.grand_grand_daughter_name_called = False + + def name(self): + self.grand_grand_daughter_name_called = True + return ExtendedVirtualDaughter.name(self).prepend('Extended') + + +class VirtualMethodsTest(unittest.TestCase): + '''Test case for virtual methods''' + + def setUp(self): + self.prefix_from_codeinjection = Str('Pimped') + + def tearDown(self): + del self.prefix_from_codeinjection + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + + def testReimplementedVirtualMethod0(self): + '''Test Python override of a virtual method with various different parameters + is correctly called from C++.''' + vm = VirtualMethods() + evm = ExtendedVirtualMethods() + pt = Point(1.1, 2.2) + val = 4 + cpx = complex(3.3, 4.4) + b = True + result0 = vm.callVirtualMethod0(pt, val, cpx, b) + result1 = evm.callVirtualMethod0(pt, val, cpx, b) + self.assertEqual(result0 * -1.0, result1) + + def testRecursionOnModifiedVirtual(self): + evm = ExtendedVirtualMethods() + self.assertEqual(evm.recursionOnModifiedVirtual(''), 10) + self.assertEqual(evm.callRecursionOnModifiedVirtual(''), 10) + + def testReimplementedVirtualMethodInheritedFromGrandParent(self): + '''Test Python override of a virtual method inherited from a grand parent.''' + original_name = 'Foo' + evd = ExtendedVirtualDaughter(original_name) + + self.assertEqual(VirtualDaughter.name(evd), original_name) + self.assertEqual(VirtualMethods.name(evd), original_name) + self.assertFalse(evd.grand_daughter_name_called) + + name = evd.callName() + self.assertTrue(evd.grand_daughter_name_called) + self.assertEqual(evd.name().prepend(self.prefix_from_codeinjection), name) + + def testReimplementedVirtualMethodInheritedFromGrandGrandParent(self): + '''Test Python override of a virtual method inherited from a grand grand parent.''' + original_name = 'Foo' + eevd = ExtendedExtendedVirtualDaughter(original_name) + + self.assertEqual(VirtualDaughter.name(eevd), original_name) + self.assertEqual(VirtualMethods.name(eevd), original_name) + self.assertFalse(eevd.grand_daughter_name_called) + self.assertFalse(eevd.grand_grand_daughter_name_called) + + name = eevd.callName() + self.assertTrue(eevd.grand_daughter_name_called) + self.assertTrue(eevd.grand_grand_daughter_name_called) + self.assertEqual(eevd.name().prepend(self.prefix_from_codeinjection), name) + + def testStringView(self): + virtual_methods = VirtualMethods() + self.assertEqual(virtual_methods.stringViewLength('bla'), 3) + + +class PrettyErrorMessageTest(unittest.TestCase): + def testIt(self): + obj = ExtendedVirtualMethods() + self.assertRaises(RuntimeWarning, obj.callStrListToStdList, StrList()) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/visibilitychange_test.py b/sources/shiboken6/tests/samplebinding/visibilitychange_test.py new file mode 100644 index 000000000..becdf7423 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/visibilitychange_test.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Base1, MDerived1 + + +class VisibilityChangeTest(unittest.TestCase): + + def testVisibilityChange(self): + b1 = Base1() + b1.publicMethod() # ok... + d1 = MDerived1() + self.assertRaises(TypeError, d1.publicMethod) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/voidholder_test.py b/sources/shiboken6/tests/samplebinding/voidholder_test.py new file mode 100644 index 000000000..186cb473e --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/voidholder_test.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test case for a class that holds a void pointer.''' + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import VoidHolder, Point +from shiboken6 import Shiboken + + +class VoidHolderTest(unittest.TestCase): + '''Test case for void pointer manipulation.''' + + def testGetVoidPointerFromCppAndPutsOnVoidHolder(self): + '''Passes a void pointer created in C++ to be kept by VoidHolder.''' + voidptr = VoidHolder.gimmeMeSomeVoidPointer() + voidholder = VoidHolder(voidptr) + self.assertEqual(voidptr, voidholder.voidPointer()) + + def testPassVoidPointerAsArgument(self): + '''Passes a void pointer created in C++ as an argument to a function.''' + voidptr = VoidHolder.gimmeMeSomeVoidPointer() + voidHolder = VoidHolder() + returnValue = voidHolder.takeVoidPointer(voidptr) + self.assertEqual(returnValue, voidptr) + + def testPutRandomObjectInsideVoidHolder(self): + '''Passes a C++ pointer for an object created in Python to be kept by VoidHolder.''' + obj = Point(1, 2) + voidholder = VoidHolder(obj) + self.assertEqual(Shiboken.getCppPointer(obj)[0], int(voidholder.voidPointer())) + + def testGetNoneObjectFromVoidHolder(self): + '''A VoidHolder created without parameters returns a NULL pointer + that should be converted to a Python None.''' + voidholder = VoidHolder() + self.assertEqual(voidholder.voidPointer(), None) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/weakref_test.py b/sources/shiboken6/tests/samplebinding/weakref_test.py new file mode 100644 index 000000000..01c6d58d5 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/weakref_test.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +'''Test weakref support''' + +import gc +import os +import sys +import unittest +import weakref + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import ObjectType, PrivateDtor + + +class WeakrefBasicTest(unittest.TestCase): + '''Simple test case of using a weakref''' + + def setUp(self): + self.called = False + + def cb(self, *args): + self.called = True + + def testBasic(self): + '''ObjectType weakref''' + obj = ObjectType() + ref = weakref.ref(obj, self.cb) # noqa: F841 + del obj + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertTrue(self.called) + + def testPrivateDtor(self): + '''PrivateDtor weakref''' + obj = PrivateDtor.instance() + ref = weakref.ref(obj, self.cb) # noqa: F841 + del obj + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertTrue(self.called) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/samplebinding/writableclassdict_test.py b/sources/shiboken6/tests/samplebinding/writableclassdict_test.py new file mode 100644 index 000000000..dfc962db9 --- /dev/null +++ b/sources/shiboken6/tests/samplebinding/writableclassdict_test.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() + +from sample import Point + + +class ExtPoint(Point): + pass + + +class TestWritableClassDict(unittest.TestCase): + def testSetattrOnClass(self): + setattr(Point, 'foo', 123) + self.assertEqual(Point.foo, 123) + pt = Point() + self.assertEqual(pt.foo, 123) + + def testSetattrOnInheritingClass(self): + setattr(Point, 'bar', 321) + self.assertEqual(Point.bar, 321) + self.assertEqual(ExtPoint.bar, 321) + pt = ExtPoint() + self.assertEqual(pt.bar, 321) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/shiboken_paths.py b/sources/shiboken6/tests/shiboken_paths.py new file mode 100644 index 000000000..3ec940f2e --- /dev/null +++ b/sources/shiboken6/tests/shiboken_paths.py @@ -0,0 +1,109 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + + +import os +import sys +from pathlib import Path + + +def get_dir_env_var(var_name): + """Return a directory set by an environment variable""" + result = os.environ.get(var_name) + if not result: + raise ValueError(f'{var_name} is not set!') + if not Path(result).is_dir(): + raise ValueError(f'{result} is not a directory!') + return result + + +def get_build_dir(): + """ + Return the env var `BUILD_DIR`. + If not set (interactive mode), take the last build history entry. + """ + try: + return get_dir_env_var('BUILD_DIR') + except ValueError: + look_for = Path("testing") + here = Path(__file__).resolve().parent + while here / look_for not in here.iterdir(): + import pprint + parent = here.parent + if parent == here: + raise SystemError(look_for + " not found!") + here = parent + try: + sys.path.insert(0, os.fspath(here)) + from testing.buildlog import builds + if not builds.history: + raise + return builds.history[-1].build_dir + finally: + del sys.path[0] + + +def _prepend_path_var(var_name, paths): + """Prepend additional paths to a path environment variable + like PATH, LD_LIBRARY_PATH""" + old_paths = os.environ.get(var_name) + new_paths = os.pathsep.join(paths) + if old_paths: + new_paths += f'{os.pathsep}{old_paths}' + os.environ[var_name] = new_paths + + +def add_python_dirs(python_dirs): + """Add directories to the Python path unless present. + Care is taken that the added directories come before + site-packages.""" + new_paths = [] + for python_dir in python_dirs: + new_paths.append(python_dir) + if python_dir in sys.path: + sys.path.remove(python_dir) + sys.path[:0] = new_paths + + +def add_lib_dirs(lib_dirs): + """Add directories to the platform's library path.""" + if sys.platform == 'win32': + if sys.version_info >= (3, 8, 0): + for lib_dir in lib_dirs: + os.add_dll_directory(lib_dir) + else: + _prepend_path_var('PATH', lib_dirs) + else: + _prepend_path_var('LD_LIBRARY_PATH', lib_dirs) + + +def shiboken_paths(include_shiboken_tests=False): + """Return a tuple of python directories/lib directories to be set for + using the shiboken6 module from the build directory or running the + shiboken tests depending on a single environment variable BUILD_DIR + pointing to the build directory.""" + src_dir = Path(__file__).resolve().parent + python_dirs = [] + if include_shiboken_tests: + python_dirs.append(os.fspath(src_dir)) # For shiboken_test_helper + python_dirs.append(get_build_dir()) # for toplevel shiboken6 import + shiboken_dir = Path(get_build_dir()) / 'shiboken6' + lib_dirs = [os.fspath(shiboken_dir / 'libshiboken')] + if include_shiboken_tests: + shiboken_test_dir = shiboken_dir /'tests' + for module in ['minimal', 'sample', 'smart', 'other']: + module_dir = shiboken_test_dir / f"{module}binding" + python_dirs.append(os.fspath(module_dir)) + lib_dir = shiboken_test_dir / f"lib{module}" + lib_dirs.append(os.fspath(lib_dir)) + return (python_dirs, lib_dirs) + + +def init_paths(): + """Sets the correct import paths (Python modules and C++ library + paths) for testing shiboken depending on a single + environment variable BUILD_DIR pointing to the build + directory.""" + paths = shiboken_paths(True) + add_python_dirs(paths[0]) + add_lib_dirs(paths[1]) diff --git a/sources/shiboken6/tests/shiboken_test_helper.py b/sources/shiboken6/tests/shiboken_test_helper.py new file mode 100644 index 000000000..14fe6a2d1 --- /dev/null +++ b/sources/shiboken6/tests/shiboken_test_helper.py @@ -0,0 +1,13 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + + +def objectFullname(t): + # '__qualname__' for Python 2 does exist for PySide types, only. + name = getattr(t, "__qualname__", t.__name__) + module = t.__module__ + if module is None or module == str.__class__.__module__: + return name + else: + return module + '.' + name diff --git a/sources/shiboken6/tests/shibokenmodule/module_test.py b/sources/shiboken6/tests/shibokenmodule/module_test.py new file mode 100644 index 000000000..9f9f8f5a4 --- /dev/null +++ b/sources/shiboken6/tests/shibokenmodule/module_test.py @@ -0,0 +1,112 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths # noqa: E402 +init_paths() + +from shiboken6 import Shiboken # noqa: E402 +from sample import BlackBox, ObjectType, ObjectModel, ObjectView, Point # noqa: E402 + + +class MultipleInherited (ObjectType, Point): + def __init__(self): + ObjectType.__init__(self) + Point.__init__(self) + + +class TestShiboken(unittest.TestCase): + def testIsValid(self): + self.assertTrue(Shiboken.isValid(object())) + self.assertTrue(Shiboken.isValid(None)) + + bb = BlackBox() + item = ObjectType() + ticket = bb.keepObjectType(item) + bb.disposeObjectType(ticket) + self.assertFalse(Shiboken.isValid(item)) + + def testWrapInstance(self): + addr = ObjectType.createObjectType() + obj = Shiboken.wrapInstance(addr, ObjectType) + self.assertFalse(Shiboken.createdByPython(obj)) + obj.setObjectName("obj") + self.assertEqual(obj.objectName(), "obj") + self.assertEqual(addr, obj.identifier()) + self.assertFalse(Shiboken.createdByPython(obj)) + + # avoid mem leak =] + bb = BlackBox() + self.assertTrue(Shiboken.createdByPython(bb)) + bb.disposeObjectType(bb.keepObjectType(obj)) + + def testWrapInstancePreserveId(self): + """PYSIDE-31: Verify that wrapInstance() returns the existing wrapper + even if a base class type is specified.""" + v = ObjectView() # inherits ObjectType + addresses = Shiboken.getCppPointer(v) + self.assertTrue(addresses) + address = addresses[0] + wrapped = Shiboken.wrapInstance(address, ObjectType) + self.assertEqual(id(wrapped), id(v)) + + def testIsOwnedByPython(self): + obj = ObjectType() + self.assertTrue(Shiboken.ownedByPython(obj)) + p = ObjectType() + obj.setParent(p) + self.assertFalse(Shiboken.ownedByPython(obj)) + + def testDump(self): + """Just check if dump doesn't crash on certain use cases""" + p = ObjectType() + obj = ObjectType(p) + obj2 = ObjectType(obj) + obj3 = ObjectType(obj) # noqa: F841 + self.assertEqual(Shiboken.dump(None), "Ordinary Python type.") + Shiboken.dump(obj) + + model = ObjectModel(p) + v = ObjectView(model, p) + Shiboken.dump(v) + + m = MultipleInherited() + Shiboken.dump(m) + self.assertEqual(len(Shiboken.getCppPointer(m)), 2) + + # Don't crash even after deleting an object + Shiboken.invalidate(obj) + Shiboken.dump(obj) # deleted + Shiboken.dump(p) # child deleted + Shiboken.dump(obj2) # parent deleted + + def testDelete(self): + obj = ObjectType() + child = ObjectType(obj) + self.assertTrue(Shiboken.isValid(obj)) + self.assertTrue(Shiboken.isValid(child)) + # Note: this test doesn't assure that the object dtor was really called + Shiboken.delete(obj) + self.assertFalse(Shiboken.isValid(obj)) + self.assertFalse(Shiboken.isValid(child)) + + def testVersionAttr(self): + self.assertEqual(type(Shiboken.__version__), str) + self.assertTrue(len(Shiboken.__version__) >= 5) + self.assertEqual(type(Shiboken.__version_info__), tuple) + self.assertEqual(len(Shiboken.__version_info__), 5) + + def testAllWrappers(self): + obj = ObjectType() + self.assertTrue(obj in Shiboken.getAllValidWrappers()) + Shiboken.delete(obj) + self.assertFalse(obj in Shiboken.getAllValidWrappers()) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/smartbinding/CMakeLists.txt b/sources/shiboken6/tests/smartbinding/CMakeLists.txt new file mode 100644 index 000000000..594744840 --- /dev/null +++ b/sources/shiboken6/tests/smartbinding/CMakeLists.txt @@ -0,0 +1,65 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +project(smart) + +set(smart_TYPESYSTEM +${CMAKE_CURRENT_SOURCE_DIR}/typesystem_smart.xml +) + +set(smart_SRC +${CMAKE_CURRENT_BINARY_DIR}/smart/smart_module_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/obj_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/integer_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/sharedptr_obj_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/sharedptr_integer_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/registry_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/smart_integer2_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/sharedptr_integer2_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/stdsharedptrtestbench_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/stdsharedptrvirtualmethodtester_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/std_shared_ptr_double_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/std_shared_ptr_integer_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/std_shared_ptr_int_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/std_shared_ptr_std_string_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/std_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/std_optional_int_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/std_optional_integer_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/std_unique_ptr_integer_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/std_unique_ptr_integer2_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/std_unique_ptr_int_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/stdoptionaltestbench_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/stduniqueptrtestbench_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/stduniqueptrvirtualmethodtester_wrapper.cpp +${CMAKE_CURRENT_BINARY_DIR}/smart/test_wrapper.cpp +) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/smart-binding.txt.in" + "${CMAKE_CURRENT_BINARY_DIR}/smart-binding.txt" @ONLY) + +shiboken_get_tool_shell_wrapper(shiboken tool_wrapper) + +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/mjb_rejected_classes.log" + BYPRODUCTS ${smart_SRC} + COMMAND + ${tool_wrapper} + $<TARGET_FILE:Shiboken6::shiboken6> + --project-file=${CMAKE_CURRENT_BINARY_DIR}/smart-binding.txt + ${GENERATOR_EXTRA_FLAGS} + DEPENDS ${smart_TYPESYSTEM} ${CMAKE_CURRENT_SOURCE_DIR}/global.h Shiboken6::shiboken6 + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + COMMENT "Running generator for 'smart' test binding..." +) + +add_library(smart MODULE ${smart_SRC}) +target_include_directories(smart PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) +target_link_libraries(smart PUBLIC libsmart libshiboken) +set_property(TARGET smart PROPERTY PREFIX "") +set_property(TARGET smart PROPERTY OUTPUT_NAME "smart${PYTHON_EXTENSION_SUFFIX}") + +if(WIN32) + set_property(TARGET smart PROPERTY SUFFIX ".pyd") +endif() + +create_generator_target(smart) diff --git a/sources/shiboken6/tests/smartbinding/global.h b/sources/shiboken6/tests/smartbinding/global.h new file mode 100644 index 000000000..5bec15063 --- /dev/null +++ b/sources/shiboken6/tests/smartbinding/global.h @@ -0,0 +1,4 @@ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#include "smart.h" diff --git a/sources/shiboken6/tests/smartbinding/smart-binding.txt.in b/sources/shiboken6/tests/smartbinding/smart-binding.txt.in new file mode 100644 index 000000000..a2c73c6bf --- /dev/null +++ b/sources/shiboken6/tests/smartbinding/smart-binding.txt.in @@ -0,0 +1,16 @@ +[generator-project] + +generator-set = shiboken + +header-file = @CMAKE_CURRENT_SOURCE_DIR@/global.h +typesystem-file = @smart_TYPESYSTEM@ + +output-directory = @CMAKE_CURRENT_BINARY_DIR@ + +include-path = @libsmart_SOURCE_DIR@ + +typesystem-path = @CMAKE_CURRENT_SOURCE_DIR@ + +enable-parent-ctor-heuristic +use-isnull-as-nb_nonzero +lean-headers diff --git a/sources/shiboken6/tests/smartbinding/smart_pointer_test.py b/sources/shiboken6/tests/smartbinding/smart_pointer_test.py new file mode 100644 index 000000000..8d4272558 --- /dev/null +++ b/sources/shiboken6/tests/smartbinding/smart_pointer_test.py @@ -0,0 +1,302 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import gc +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from copy import copy +from smart import (Obj, Registry, Integer, SharedPtr_Integer, std) + + +def objCount(): + return Registry.getInstance().countObjects() + + +def integerCount(): + return Registry.getInstance().countIntegers() + + +def integerFromValue(v): + result = Integer() + result.setValue(v) + return result + + +class SmartPointerTests(unittest.TestCase): + + def setUp(self): + super().setUp() + if os.environ.get("VERBOSE"): + Registry.getInstance().setVerbose(True) + + def testObjSmartPointer(self): + # Create Obj. + o = Obj() + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(objCount(), 1) + + # Create a shared pointer to an Obj together with an Obj. + ptrToObj = o.createSharedPtrObj() + self.assertEqual(objCount(), 2) + + # Delete the old Obj. + o = None + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(objCount(), 1) + + # Get a wrapper to the Obj inside of the shared pointer, object count + # should not change. + obj = ptrToObj.data() + self.assertEqual(objCount(), 1) + obj.m_integer = 50 + self.assertEqual(obj.m_integer, 50) + + # Set and get a member value via shared pointer (like operator->). + ptrToObj.m_integer = 100 + self.assertEqual(ptrToObj.m_integer, 100) + + # Get inner PyObject via shared pointer (like operator->) and set + # value in it. + ptrToObj.m_internalInteger.m_int = 200 + self.assertEqual(ptrToObj.m_internalInteger.m_int, 200) + + # Pass smart pointer as argument to a method, return value is the value + # of m_integer of passed Obj inside the smart pointer. + result = ptrToObj.takeSharedPtrToObj(ptrToObj) + self.assertEqual(result, 100) + + # Pass an Integer as an argument that returns itself. + result = ptrToObj.takeInteger(ptrToObj.m_internalInteger) + self.assertEqual(integerCount(), 2) + result = None + if integerCount() > 1: + gc.collect() + print('Running garbage collector for reference test', + file=sys.stderr) + self.assertEqual(integerCount(), 1) + + # Make a copy of the shared pointer, object count should not change. + ptrToObj2 = copy(ptrToObj) + self.assertEqual(objCount(), 1) + + # Delete the first shared pointer, object count should not change + # because the second one still has a reference. + del ptrToObj + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(objCount(), 1) + + # Delete the second smart pointer, object should be deleted. + del ptrToObj2 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(objCount(), 0) + self.assertEqual(integerCount(), 0) + + def testIntegerSmartPointer(self): + # Create Obj. + o = Obj() + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(objCount(), 1) + + # Create a shared pointer to an Integer together with an Integer. + ptrToInteger = o.createSharedPtrInteger() + self.assertEqual(objCount(), 1) + self.assertEqual(integerCount(), 2) + + # Get a wrapper to the Integer inside of the shared pointer, integer + # count should not change. + integer = ptrToInteger.data() + self.assertEqual(integerCount(), 2) + integer.m_int = 50 + self.assertEqual(integer.m_int, 50) + + # Set and get a member value via shared pointer (like operator->). + ptrToInteger.setValue(150) + self.assertEqual(ptrToInteger.value(), 150) + + # Set and get a member field via shared pointer (like operator->). + ptrToInteger.m_int = 100 + self.assertEqual(ptrToInteger.m_int, 100) + + # Pass smart pointer as argument to a method, return value is the + # value of m_int of passed Integer inside the smart pointer. + result = o.takeSharedPtrToInteger(ptrToInteger) + self.assertEqual(result, 100) + + # Make a copy of the shared pointer, integer count should not change. + ptrToInteger2 = copy(ptrToInteger) + self.assertEqual(integerCount(), 2) + + # Delete the first shared pointer, integer count should not change + # because the second one still has a reference. + del ptrToInteger + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(integerCount(), 2) + + # Delete the second smart pointer, integer should be deleted. + del ptrToInteger2 + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(objCount(), 1) + self.assertEqual(integerCount(), 1) + + # Delete the original object which was used to create the integer. + del o + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(objCount(), 0) + self.assertEqual(integerCount(), 0) + + def testConstIntegerSmartPointer(self): + # Create Obj. + o = Obj() + ptrToConstInteger = o.createSharedPtrConstInteger() + self.assertEqual(ptrToConstInteger.m_int, 456) + result = o.takeSharedPtrToConstInteger(ptrToConstInteger) + self.assertEqual(result, 456) + self.assertEqual(ptrToConstInteger.value(), 456) + + def testSmartPointersWithNamespace(self): + # Create the main object + o = Obj() + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(objCount(), 1) + + # Create a shared pointer to an Integer together with an Integer. + ptrToInteger = o.createSharedPtrInteger2() + self.assertEqual(objCount(), 1) + self.assertEqual(integerCount(), 2) + + integer = ptrToInteger.data() + self.assertTrue(integer) + + def testListOfSmartPointers(self): + # Create the main object + o = Obj() + + # Create a list of shared objects + ptrToObjList = o.createSharedPtrObjList(10) + self.assertEqual(len(ptrToObjList), 10) + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(objCount(), 11) + + # Remove one from the list + ptrToObjList.pop() + self.assertEqual(len(ptrToObjList), 9) + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + # PYSIDE-535: Why do I need to do it twice, here? + gc.collect() + self.assertEqual(objCount(), 10) + + # clear and delete all objects in the list + del ptrToObjList[:] # Python 2.7 lists have no clear method + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(len(ptrToObjList), 0) + self.assertEqual(objCount(), 1) + + def testInvalidParameter(self): + # Create Obj. + o = Obj() + # Create a shared pointer to an Obj together with an Obj. + ptrToObj = o.createSharedPtrObj() + try: + ptrToObj.typo + self.assertFail() + except AttributeError as error: + self.assertEqual(error.args[0], "'smart.SharedPtr_Obj' object has no attribute 'typo'") + + def testSmartPointerConversions(self): + # Create Obj. + o = Obj() + # PYSIDE-535: Need to collect garbage in PyPy to trigger deletion + gc.collect() + self.assertEqual(objCount(), 1) + self.assertEqual(integerCount(), 1) + + # Create a shared pointer to an Integer2 + integer2 = o.createSharedPtrInteger2() + # User defined name + self.assertEqual(type(integer2).__name__, "SmartInteger2Ptr") + self.assertTrue("smart.Test.SmartInteger2Ptr" in repr(type(integer2))) + self.assertEqual(integer2.value(), 456) + + # pass Smart<Integer2> to a function that accepts Smart<Integer> + r = o.takeSharedPtrToInteger(integer2) + self.assertEqual(r, integer2.value()) + + def testSmartPointerValueComparison(self): + """Test a pointee class with comparison operators.""" + four = Obj.createSharedPtrInteger(4) + four2 = Obj.createSharedPtrInteger(4) + five = Obj.createSharedPtrInteger(5) + self.assertTrue(four == four) + self.assertTrue(four == four2) + self.assertFalse(four != four) + self.assertFalse(four != four2) + self.assertFalse(four < four) + self.assertTrue(four <= four) + self.assertFalse(four > four) + self.assertTrue(four >= four) + self.assertFalse(four == five) + self.assertTrue(four != five) + self.assertTrue(four < five) + self.assertTrue(four <= five) + self.assertFalse(four > five) + self.assertFalse(four >= five) + self.assertTrue(five > four) + + self.assertRaises(NotImplementedError, + lambda: Obj.createNullSharedPtrInteger() == four) + + def testSmartPointerObjectComparison(self): + """Test a pointee class without comparison operators.""" + o1 = Obj.createSharedPtrObj() + o2 = Obj.createSharedPtrObj() + self.assertTrue(o1 == o1) + self.assertFalse(o1 != o1) + self.assertFalse(o1 == o2) + self.assertTrue(o1 != o2) + + def testOperatorNbBool(self): + null_ptr = Obj.createNullSharedPtrInteger() + self.assertFalse(null_ptr) + zero = Obj.createSharedPtrInteger(0) + self.assertTrue(zero) + + def testParameterNone(self): + o = Obj() + null_ptr = Obj.createNullSharedPtrInteger() + o.takeSharedPtrToInteger(null_ptr) + o.takeSharedPtrToIntegerByConstRef(null_ptr) + o.takeSharedPtrToInteger(None) + o.takeSharedPtrToIntegerByConstRef(None) + + def testConstruction(self): + p1 = SharedPtr_Integer(integerFromValue(42)) + self.assertEqual(p1.value(), 42) + + p2 = std.shared_ptr_Integer(integerFromValue(42)) + self.assertEqual(p2.value(), 42) + p2.reset(integerFromValue(43)) + self.assertEqual(p2.value(), 43) + gc.collect() + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/smartbinding/smartbinding.pyproject b/sources/shiboken6/tests/smartbinding/smartbinding.pyproject new file mode 100644 index 000000000..d0855ef82 --- /dev/null +++ b/sources/shiboken6/tests/smartbinding/smartbinding.pyproject @@ -0,0 +1,7 @@ +{ + "files": ["smart_pointer_test.py", + "std_optional_test.py", + "std_shared_ptr_test.py", + "std_unique_ptr_test.py", + "typesystem_smart.xml"] +} diff --git a/sources/shiboken6/tests/smartbinding/std_optional_test.py b/sources/shiboken6/tests/smartbinding/std_optional_test.py new file mode 100644 index 000000000..bee573548 --- /dev/null +++ b/sources/shiboken6/tests/smartbinding/std_optional_test.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from smart import Integer, StdOptionalTestBench, std + + +def call_func_on_optional(o): + o.printInteger() + + +def integer_from_value(v): + result = Integer() + result.setValue(v) + return result + + +class StdOptionalTests(unittest.TestCase): + + def testCInt(self): + b = StdOptionalTestBench() + ci = b.optionalInt() + self.assertFalse(ci.has_value()) + b.setOptionalIntValue(42) + ci = b.optionalInt() + self.assertTrue(ci.has_value()) + self.assertEqual(ci.value(), 42) + b.setOptionalInt(ci) + ci = b.optionalInt() + self.assertTrue(ci.has_value()) + self.assertEqual(ci.value(), 42) + + ci = std.optional_int(43) + self.assertEqual(ci.value(), 43) + + def testInteger(self): + b = StdOptionalTestBench() + i = b.optionalInteger() + self.assertFalse(i.has_value()) + self.assertFalse(i) + # Must not throw a C++ exception + self.assertRaises(AttributeError, call_func_on_optional, i) + + b.setOptionalIntegerValue(integer_from_value(42)) + i = b.optionalInteger() + self.assertTrue(i.has_value()) + self.assertEqual(i.value().value(), 42) + i.printInteger() + print(i) + b.setOptionalInteger(i) + i = b.optionalInteger() + self.assertTrue(i.has_value()) + self.assertEqual(i.value().value(), 42) + call_func_on_optional(i) + + i = std.optional_Integer(integer_from_value(43)) + self.assertEqual(i.value().value(), 43) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py b/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py new file mode 100644 index 000000000..a37a307a5 --- /dev/null +++ b/sources/shiboken6/tests/smartbinding/std_shared_ptr_test.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from smart import Integer, StdDoublePtr, StdSharedPtrTestBench, StdSharedPtrVirtualMethodTester, std + + +def call_func_on_ptr(ptr): + ptr.printInteger() + + +class VirtualTester(StdSharedPtrVirtualMethodTester): + + def doModifyInteger(self, p): + p.setValue(p.value() * 2) + return p + + +class StdSharedPtrTests(unittest.TestCase): + def testInteger(self): + p = StdSharedPtrTestBench.createInteger() + # PYSIDE-2462: Ensure Integer's __dir__ entries in the pointer's + self.assertTrue("printInteger" in dir(p)) + StdSharedPtrTestBench.printInteger(p) + self.assertTrue(p) + call_func_on_ptr(p) + + np = StdSharedPtrTestBench.createNullInteger() + StdSharedPtrTestBench.printInteger(np) + self.assertFalse(np) + self.assertRaises(AttributeError, call_func_on_ptr, np) + + iv = Integer() + iv.setValue(42) + np = std.shared_ptr_Integer(iv) + self.assertEqual(np.value(), 42) + + def testInt(self): + np = StdSharedPtrTestBench.createNullInt() + StdSharedPtrTestBench.printInt(np) + self.assertFalse(np) + p = StdSharedPtrTestBench.createInt() + StdSharedPtrTestBench.printInt(p) + ip = std.StdIntPtr(42) + StdSharedPtrTestBench.printInt(ip) + + def testDouble(self): + np = StdSharedPtrTestBench.createNullDouble() + StdSharedPtrTestBench.printDouble(np) + self.assertFalse(np) + p = StdSharedPtrTestBench.createDouble(67) + StdSharedPtrTestBench.printDouble(p) + dp = StdDoublePtr(42) + StdSharedPtrTestBench.printDouble(dp) + + def testString(self): + np = StdSharedPtrTestBench.createNullString() + StdSharedPtrTestBench.printString(np) + self.assertFalse(np) + p = StdSharedPtrTestBench.createString("bla") + StdSharedPtrTestBench.printString(p) + + def testVirtuals(self): + """Test whether code generating virtual function overrides is generated + correctly.""" + p = StdSharedPtrTestBench.createInteger() + p.setValue(42) + v = StdSharedPtrVirtualMethodTester() + r = v.callModifyInteger(p) # Base implementation increments + self.assertEqual(r.value(), 43) + + p.setValue(42) + v = VirtualTester() + r = v.callModifyInteger(p) # Derived implementation doubles + self.assertEqual(r.value(), 84) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/smartbinding/std_unique_ptr_test.py b/sources/shiboken6/tests/smartbinding/std_unique_ptr_test.py new file mode 100644 index 000000000..9c7ef2f01 --- /dev/null +++ b/sources/shiboken6/tests/smartbinding/std_unique_ptr_test.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +import os +import sys +import unittest + +from pathlib import Path +sys.path.append(os.fspath(Path(__file__).resolve().parents[1])) +from shiboken_paths import init_paths +init_paths() +from smart import Integer, Integer2, StdUniquePtrTestBench, StdUniquePtrVirtualMethodTester, std + + +def call_func_on_ptr(ptr): + ptr.printInteger() + + +class VirtualTester(StdUniquePtrVirtualMethodTester): + + def doCreateInteger(self, v): + iv = Integer() # Construct from pointee + iv.setValue(2 * v) + return std.unique_ptr_Integer(iv) + + def doModifyIntegerByRef(self, p): + return 2 * p.value() + + def doModifyIntegerByValue(self, p): + return 2 * p.value() + + +class StdUniquePtrTests(unittest.TestCase): + def testInteger(self): + p = StdUniquePtrTestBench.createInteger() + StdUniquePtrTestBench.printInteger(p) # unique_ptr by ref + self.assertTrue(p) + + call_func_on_ptr(p) + self.assertTrue(p) + + StdUniquePtrTestBench.takeInteger(p) # unique_ptr by value, takes pointee + self.assertFalse(p) + + np = StdUniquePtrTestBench.createNullInteger() + StdUniquePtrTestBench.printInteger(np) + self.assertFalse(np) + self.assertRaises(AttributeError, call_func_on_ptr, np) + + iv = Integer() # Construct from pointee + iv.setValue(42) + np = std.unique_ptr_Integer(iv) + self.assertEqual(np.value(), 42) + + def test_derived(self): + iv2 = Integer2() # Construct from pointee + iv2.setValue(42) + p = std.unique_ptr_Smart_Integer2(iv2) + self.assertEqual(p.value(), 42) + StdUniquePtrTestBench.printInteger2(p) # unique_ptr by ref + self.assertTrue(p) + StdUniquePtrTestBench.printInteger(p) # conversion + # FIXME: This fails, pointer is moved in value conversion + # self.assertTrue(p) + + def testInt(self): + p = StdUniquePtrTestBench.createInt() # unique_ptr by ref + StdUniquePtrTestBench.printInt(p) + StdUniquePtrTestBench.takeInt(p) # unique_ptr by value, takes pointee + self.assertFalse(p) + + np = StdUniquePtrTestBench.createNullInt() + StdUniquePtrTestBench.printInt(np) + self.assertFalse(np) + + def testVirtuals(self): + """Test whether code generating virtual function overrides is generated + correctly.""" + p = StdUniquePtrTestBench.createInteger() + p.setValue(42) + v = StdUniquePtrVirtualMethodTester() + self.assertTrue(v.testCreateInteger(42, 42)) + self.assertTrue(v.testModifyIntegerByRef(42, 43)) # Default implementation increments + self.assertTrue(v.testModifyIntegerValue(42, 43)) + + v = VirtualTester() # Reimplemented methods double values + self.assertTrue(v.testCreateInteger(42, 84)) + self.assertTrue(v.testModifyIntegerByRef(42, 84)) + self.assertTrue(v.testModifyIntegerValue(42, 84)) + + +if __name__ == '__main__': + unittest.main() diff --git a/sources/shiboken6/tests/smartbinding/typesystem_smart.xml b/sources/shiboken6/tests/smartbinding/typesystem_smart.xml new file mode 100644 index 000000000..e479e4ddf --- /dev/null +++ b/sources/shiboken6/tests/smartbinding/typesystem_smart.xml @@ -0,0 +1,81 @@ +<?xml version="1.0" encoding="UTF-8"?> +<typesystem package="smart"> + <rejection class="*" argument-type="^std::nullptr_t&?$"/> + + <template name="cpplist_to_pylist_convertion"> + PyObject *%out = PyList_New(int(%in.size())); + int idx = 0; + for (const auto &cppItem : %in) + PyList_SET_ITEM(%out, idx++, %CONVERTTOPYTHON[%INTYPE_0](cppItem)); + return %out; + </template> + <template name="pyseq_to_cpplist_convertion"> + Shiboken::AutoDecRef seq(PySequence_Fast(%in, 0)); + for (int i = 0, size = PySequence_Fast_GET_SIZE(seq.object()); i < size; ++i) { + PyObject* pyItem = PySequence_Fast_GET_ITEM(seq.object(), i); + %OUTTYPE_0 cppItem = %CONVERTTOCPP[%OUTTYPE_0](pyItem); + %out.push_back(cppItem); + } + </template> + + <!-- Used in tests to check what C++ objects are allocated. --> + <object-type name="Registry" /> + + <!-- Current limitation: shared pointer python objects can only be instantiated from API usage, + like when they are returned as a result of a method, or passed as arguments. It is not + possible to explicitly instantiate a new shared pointer in python e.g. o = SharedPtr_Foo() + won't work. + --> + <smart-pointer-type name="SharedPtr" type="shared" getter="data" ref-count-method="useCount" + null-check-method="isNull" + instantiations="Integer,Smart::Integer2=Test::SmartInteger2Ptr,Obj"/> + + <object-type name="Obj" /> + <value-type name="Integer" /> + <namespace-type name="Smart" generate="no"> + <value-type name="Integer2" /> + </namespace-type> + <!-- Just used to silence the warnings that shiboken doens't know what to do with this type --> + <custom-type name="RefData" /> + + <value-type name="StdOptionalTestBench"/> + + <system-include file-name="memory"/> + + <namespace-type name="std"> + <include file-name="memory" location="global"/> + <modify-function signature="^.*$" remove="all"/> + <enum-type name="pointer_safety"/> + <smart-pointer-type name="shared_ptr" type="shared" getter="get" + value-check-method="operator bool" + ref-count-method="use_count" + reset-method="reset" + instantiations="Integer,int=StdIntPtr,double=::StdDoublePtr,std::string"> + <include file-name="memory" location="global"/> + </smart-pointer-type> + + <smart-pointer-type name="unique_ptr" type="unique" getter="get" + value-check-method="operator bool" + reset-method="reset" + instantiations="Integer,Smart::Integer2,int"> + <include file-name="memory" location="global"/> + </smart-pointer-type> + + <smart-pointer-type name="optional" type="value-handle" getter="value" + value-check-method="has_value" + instantiations="Integer,int"> + <include file-name="optional" location="global"/> + </smart-pointer-type> + + </namespace-type> + <object-type name="StdSharedPtrTestBench"/> + <object-type name="StdSharedPtrVirtualMethodTester"/> + + <object-type name="StdUniquePtrTestBench"/> + <object-type name="StdUniquePtrVirtualMethodTester"/> + + <namespace-type name="Test"> + <enum-type name="DummyEnum"/> + </namespace-type> + +</typesystem> diff --git a/sources/shiboken6/tests/test_generator/CMakeLists.txt b/sources/shiboken6/tests/test_generator/CMakeLists.txt new file mode 100644 index 000000000..e1d078894 --- /dev/null +++ b/sources/shiboken6/tests/test_generator/CMakeLists.txt @@ -0,0 +1,65 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.18) +project(test_generator) + +set(dummy_generator_SRC dummygenerator.cpp) +add_library(dummy_generator SHARED ${dummy_generator_SRC}) +target_link_libraries(dummy_generator ${APIEXTRACTOR_LIBRARY} ${QT_QTCORE_LIBRARY} genrunner) +set_property(TARGET dummy_generator PROPERTY PREFIX "") + +add_executable(dummygenerator main.cpp) +set(DUMMYGENERATOR_EXECUTABLE dummygenerator${generator_SUFFIX}) +set_target_properties(dummygenerator PROPERTIES OUTPUT_NAME ${DUMMYGENERATOR_EXECUTABLE}) +target_link_libraries(dummygenerator ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES}) + +configure_file(dummygentestconfig.h.in "${CMAKE_CURRENT_BINARY_DIR}/dummygentestconfig.h" @ONLY) + +get_filename_component(APIEXTRACTOR_LIBRARY_DIRS ${APIEXTRACTOR_LIBRARY} PATH) +if(WIN32) + set(PATH_SEP ";") + find_program(APIEXTRACTOR_BINARY apiextractor.dll HINTS ${APIEXTRACTOR_LIBRARY_DIRS}) + get_filename_component(APIEXTRACTOR_BINARY_DIR ${APIEXTRACTOR_BINARY} PATH) + set(APIEXTRACTOR_LIBRARY_DIRS "${APIEXTRACTOR_LIBRARY_DIRS}${PATH_SEP}${APIEXTRACTOR_BINARY_DIR}") +else() + set(PATH_SEP ":") +endif() + +set(ENV_PATH "${generatorrunner_BINARY_DIR}${PATH_SEP}${CMAKE_CURRENT_BINARY_DIR}${PATH_SEP}$ENV{PATH}${PATH_SEP}${APIEXTRACTOR_LIBRARY_DIRS}") +set(ENV_QT_PLUGIN_PATH "${CMAKE_CURRENT_BINARY_DIR}${PATH_SEP}$ENV{QT_PLUGIN_PATH}") +if(WIN32) + string(REPLACE "\\;" ";" ENV_PATH "${ENV_PATH}") + string(REPLACE ";" "\\;" ENV_PATH "${ENV_PATH}") + string(REPLACE "\\;" ";" ENV_QT_PLUGIN_PATH "${ENV_QT_PLUGIN_PATH}") + string(REPLACE ";" "\\;" ENV_QT_PLUGIN_PATH "${ENV_QT_PLUGIN_PATH}") +endif() + +macro(m_add_test testname) + add_test(${testname} ${testname}) + set_property(TEST ${testname} PROPERTY ENVIRONMENT "PATH=${ENV_PATH}" "QT_PLUGIN_PATH=${ENV_QT_PLUGIN_PATH}") +endmacro() + +macro(declare_test testname) + qt4_automoc("${testname}.cpp") + add_executable(${testname} "${testname}.cpp") + include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) + target_link_libraries(${testname} + ${QT_QTTEST_LIBRARY} + ${QT_QTCORE_LIBRARY} + ${Qt${QT_MAJOR_VERSION}Test_LIBRARIES} + ${Qt${QT_MAJOR_VERSION}Core_LIBRARIES} + ) + m_add_test(${testname}) +endmacro(declare_test testname) + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/test_global.h" + "${CMAKE_CURRENT_BINARY_DIR}/test_global.h" COPYONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/test_typesystem.xml" + "${CMAKE_CURRENT_BINARY_DIR}/test_typesystem.xml" COPYONLY) +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/dummygentest-project.txt.in" + "${CMAKE_CURRENT_BINARY_DIR}/dummygentest-project.txt" @ONLY) +declare_test(dummygentest) + +add_dependencies(dummygenerator generatorrunner) + diff --git a/sources/shiboken6/tests/test_generator/dummygenerator.cpp b/sources/shiboken6/tests/test_generator/dummygenerator.cpp new file mode 100644 index 000000000..8a5079820 --- /dev/null +++ b/sources/shiboken6/tests/test_generator/dummygenerator.cpp @@ -0,0 +1,45 @@ +// 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 <iostream> +#include "dummygenerator.h" + +EXPORT_GENERATOR_PLUGIN(new DummyGenerator) + +using namespace std; + +QString +DummyGenerator::fileNameForClass(const AbstractMetaClass* metaClass) const +{ + return metaClass->name().toLower() + u"_generated.txt"_qs; +} + +void +DummyGenerator::generateClass(QTextStream& s, const AbstractMetaClass* metaClass) +{ + s << "// Generated code for class: " << qPrintable(metaClass->name()) << endl; +} + +bool +DummyGenerator::doSetup(const QMap<QString, QString>& args) +{ + if (args.contains("dump-arguments") && !args["dump-arguments"].isEmpty()) { + QFile logFile(args["dump-arguments"]); + logFile.open(QIODevice::WriteOnly | QIODevice::Text); + QTextStream out(&logFile); + for (QMap<QString, QString>::const_iterator it = args.cbegin(), end = args.cend(); it != end; ++it) { + const QString& key = it.key(); + if (key == "arg-1") + out << "header-file"; + else if (key == "arg-2") + out << "typesystem-file"; + else + out << key; + if (!args[key].isEmpty()) + out << " = " << args[key]; + out << endl; + } + } + return true; +} + diff --git a/sources/shiboken6/tests/test_generator/dummygenerator.h b/sources/shiboken6/tests/test_generator/dummygenerator.h new file mode 100644 index 000000000..d17206809 --- /dev/null +++ b/sources/shiboken6/tests/test_generator/dummygenerator.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 DUMMYGENERATOR_H +#define DUMMYGENERATOR_H + +#include "generator.h" + +class GENRUNNER_API DummyGenerator : public Generator +{ +public: + DummyGenerator() {} + ~DummyGenerator() {} + bool doSetup(const QMap<QString, QString>& args); + const char* name() const { return "DummyGenerator"; } + +protected: + void writeFunctionArguments(QTextStream&, const AbstractMetaFunction*, Options) const {} + void writeArgumentNames(QTextStream&, const AbstractMetaFunction*, Options) const {} + QString fileNameForClass(const AbstractMetaClass* metaClass) const; + void generateClass(QTextStream& s, const AbstractMetaClass* metaClass); + void finishGeneration() {} +}; + +#endif // DUMMYGENERATOR_H diff --git a/sources/shiboken6/tests/test_generator/dummygentest-project.txt.in b/sources/shiboken6/tests/test_generator/dummygentest-project.txt.in new file mode 100644 index 000000000..0a076d8bd --- /dev/null +++ b/sources/shiboken6/tests/test_generator/dummygentest-project.txt.in @@ -0,0 +1,20 @@ +[generator-project] + +generator-set = dummy +header-file = @CMAKE_CURRENT_BINARY_DIR@/test_global.h +typesystem-file = @CMAKE_CURRENT_BINARY_DIR@/test_typesystem.xml +output-directory = /tmp/output + +dump-arguments = @CMAKE_CURRENT_BINARY_DIR@/dummygen-args.log + +include-path = /include/path/location1 +include-path = /include/path/location2 + +typesystem-path = /typesystem/path/location1 +typesystem-path = /typesystem/path/location2 + +api-version = 1.2.3 +debug = sparse + +no-suppress-warnings + diff --git a/sources/shiboken6/tests/test_generator/dummygentest.cpp b/sources/shiboken6/tests/test_generator/dummygentest.cpp new file mode 100644 index 000000000..d439e3d8c --- /dev/null +++ b/sources/shiboken6/tests/test_generator/dummygentest.cpp @@ -0,0 +1,114 @@ +// 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 "dummygentest.h" +#include "dummygenerator.h" +#include "dummygentestconfig.h" + +#include <QtCore/QProcess> +#include <QtCore/QTemporaryFile> +#include <QtTest/QTest> + +#define GENERATED_CONTENTS "// Generated code for class: Dummy" + +void DummyGenTest::initTestCase() +{ + int argc = 0; + char* argv[] = {NULL}; + QCoreApplication app(argc, argv); + workDir = QDir::currentPath(); + + headerFilePath = workDir + "/test_global.h"; + typesystemFilePath = workDir + "/test_typesystem.xml"; + projectFilePath = workDir + "/dummygentest-project.txt"; + generatedFilePath = QDir::tempPath() + u"/dummy/dummy_generated.txt"_qs; +} + +void DummyGenTest::testCallGenRunnerWithFullPathToDummyGenModule() +{ + QStringList args; + args.append("--generator-set=" DUMMYGENERATOR_BINARY_DIR "/dummy_generator" MODULE_EXTENSION); + args.append(u"--output-directory="_qs + QDir::tempPath()); + args.append(headerFilePath); + args.append(typesystemFilePath); + int result = QProcess::execute("generatorrunner", args); + QCOMPARE(result, 0); + + QFile generatedFile(generatedFilePath); + generatedFile.open(QIODevice::ReadOnly); + QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed()); + generatedFile.close(); + + QVERIFY(generatedFile.remove()); +} + +void DummyGenTest::testCallGenRunnerWithNameOfDummyGenModule() +{ + QStringList args; + args.append("--generator-set=dummy"); + args.append(u"--output-directory="_qs + QDir::tempPath()); + args.append(headerFilePath); + args.append(typesystemFilePath); + int result = QProcess::execute("generatorrunner", args); + QCOMPARE(result, 0); + + QFile generatedFile(generatedFilePath); + generatedFile.open(QIODevice::ReadOnly); + QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed()); + generatedFile.close(); + + QVERIFY(generatedFile.remove()); +} + +void DummyGenTest::testCallDummyGeneratorExecutable() +{ + QStringList args; + args.append(u"--output-directory="_qs + QDir::tempPath()); + args.append(headerFilePath); + args.append(typesystemFilePath); + int result = QProcess::execute(DUMMYGENERATOR_BINARY, args); + QCOMPARE(result, 0); + + QFile generatedFile(generatedFilePath); + generatedFile.open(QIODevice::ReadOnly); + QCOMPARE(generatedFile.readAll().trimmed(), QByteArray(GENERATED_CONTENTS).trimmed()); + generatedFile.close(); + + QVERIFY(generatedFile.remove()); +} + +void DummyGenTest::testProjectFileArgumentsReading() +{ + QStringList args(u"--project-file="_qs + workDir + u"/dummygentest-project.txt"_qs); + int result = QProcess::execute("generatorrunner", args); + QCOMPARE(result, 0); + + QFile logFile(workDir + "/dummygen-args.log"); + logFile.open(QIODevice::ReadOnly); + QStringList logContents; + while (!logFile.atEnd()) + logContents << logFile.readLine().trimmed(); + logContents.sort(); + QCOMPARE(logContents[0], QString("api-version = 1.2.3")); + QCOMPARE(logContents[1], QString("debug = sparse")); + QVERIFY(logContents[2].startsWith("dump-arguments = ")); + QVERIFY(logContents[2].endsWith("dummygen-args.log")); + QCOMPARE(logContents[3], QString("generator-set = dummy")); + QVERIFY(logContents[4].startsWith("header-file = ")); + QVERIFY(logContents[4].endsWith("test_global.h")); + QCOMPARE(logContents[5], + QDir::toNativeSeparators(QString("include-paths = /include/path/location1%1/include/path/location2").arg(PATH_SPLITTER))); + QCOMPARE(logContents[6], QString("no-suppress-warnings")); + QCOMPARE(logContents[7], QString("output-directory = /tmp/output")); + QVERIFY(logContents[8].startsWith("project-file = ")); + QVERIFY(logContents[8].endsWith("dummygentest-project.txt")); + QVERIFY(logContents[9].startsWith("typesystem-file = ")); + QVERIFY(logContents[9].endsWith("test_typesystem.xml")); + QCOMPARE(logContents[10], + QDir::toNativeSeparators(QString("typesystem-paths = /typesystem/path/location1%1/typesystem/path/location2").arg(PATH_SPLITTER))); +} + +QTEST_APPLESS_MAIN(DummyGenTest) + +#include "dummygentest.moc" + diff --git a/sources/shiboken6/tests/test_generator/dummygentest.h b/sources/shiboken6/tests/test_generator/dummygentest.h new file mode 100644 index 000000000..1b1143b0a --- /dev/null +++ b/sources/shiboken6/tests/test_generator/dummygentest.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 DUMMYGENTABLETEST_H +#define DUMMYGENTABLETEST_H + +#include <QObject> + +class DummyGenerator; + +class DummyGenTest : public QObject +{ + Q_OBJECT + +private: + QString workDir; + QString headerFilePath; + QString typesystemFilePath; + QString generatedFilePath; + QString projectFilePath; + +private slots: + void initTestCase(); + void testCallGenRunnerWithFullPathToDummyGenModule(); + void testCallGenRunnerWithNameOfDummyGenModule(); + void testCallDummyGeneratorExecutable(); + void testProjectFileArgumentsReading(); +}; + +#endif + diff --git a/sources/shiboken6/tests/test_generator/dummygentestconfig.h.in b/sources/shiboken6/tests/test_generator/dummygentestconfig.h.in new file mode 100644 index 000000000..9da17dcd3 --- /dev/null +++ b/sources/shiboken6/tests/test_generator/dummygentestconfig.h.in @@ -0,0 +1,15 @@ +#ifndef DUMMYGENTESTCONFIG_H +#define DUMMYGENTESTCONFIG_H + +#define MODULE_EXTENSION "@CMAKE_SHARED_LIBRARY_SUFFIX@" +#define DUMMYGENERATOR_BINARY "@DUMMYGENERATOR_EXECUTABLE@" +#define DUMMYGENERATOR_BINARY_DIR "@CMAKE_CURRENT_BINARY_DIR@" + +#ifdef _WINDOWS + #define PATH_SPLITTER ";" +#else + #define PATH_SPLITTER ":" +#endif + +#endif // DUMMYGENTESTCONFIG_H + diff --git a/sources/shiboken6/tests/test_generator/main.cpp b/sources/shiboken6/tests/test_generator/main.cpp new file mode 100644 index 000000000..ba4440b2f --- /dev/null +++ b/sources/shiboken6/tests/test_generator/main.cpp @@ -0,0 +1,14 @@ +// 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 <QtCore> + +int main(int argc, char *argv[]) +{ + QStringList args; + args.append("--generator-set=dummy"); + for (int i = 1; i < argc; i++) + args.append(argv[i]); + return QProcess::execute("generatorrunner", args); +} + diff --git a/sources/shiboken6/tests/test_generator/run_test.cmake b/sources/shiboken6/tests/test_generator/run_test.cmake new file mode 100644 index 000000000..37e40b993 --- /dev/null +++ b/sources/shiboken6/tests/test_generator/run_test.cmake @@ -0,0 +1,14 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +# The tests are run through this script due to a limitation +# on versions of CMake lesser than 2.8, that prevent setting +# environment variables for tests from working. + +set(ENV{PATH} "${ENV_PATH}") +set(ENV{QT_PLUGIN_PATH} "${ENV_QT_PLUGIN_PATH}") +execute_process(COMMAND ${TEST} WORKING_DIRECTORY "${WORKDIR}" RESULT_VARIABLE OK) + +if(NOT OK EQUAL 0) + message(SEND_ERROR "${TEST} failed!") +endif() diff --git a/sources/shiboken6/tests/test_generator/test_global.h b/sources/shiboken6/tests/test_generator/test_global.h new file mode 100644 index 000000000..6a95200cf --- /dev/null +++ b/sources/shiboken6/tests/test_generator/test_global.h @@ -0,0 +1 @@ +struct Dummy {}; diff --git a/sources/shiboken6/tests/test_generator/test_typesystem.xml b/sources/shiboken6/tests/test_generator/test_typesystem.xml new file mode 100644 index 000000000..c19a4e95e --- /dev/null +++ b/sources/shiboken6/tests/test_generator/test_typesystem.xml @@ -0,0 +1,3 @@ +<typesystem package='dummy'> + <value-type name='Dummy'/> +</typesystem> |