diff options
Diffstat (limited to 'tests/auto/corelib/plugin')
97 files changed, 2476 insertions, 1594 deletions
diff --git a/tests/auto/corelib/plugin/CMakeLists.txt b/tests/auto/corelib/plugin/CMakeLists.txt new file mode 100644 index 0000000000..5518231ace --- /dev/null +++ b/tests/auto/corelib/plugin/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(QT_BUILD_SHARED_LIBS) + add_subdirectory(qfactoryloader) +endif() +add_subdirectory(quuid) +if(QT_FEATURE_library) + add_subdirectory(qpluginloader) + add_subdirectory(qlibrary) +endif() +if(QT_BUILD_SHARED_LIBS AND QT_FEATURE_library) + add_subdirectory(qplugin) +endif() diff --git a/tests/auto/corelib/plugin/plugin.pro b/tests/auto/corelib/plugin/plugin.pro deleted file mode 100644 index 240608fddf..0000000000 --- a/tests/auto/corelib/plugin/plugin.pro +++ /dev/null @@ -1,15 +0,0 @@ -TEMPLATE=subdirs -SUBDIRS=\ - qfactoryloader \ - quuid - -qtConfig(library): SUBDIRS += \ - qpluginloader \ - qplugin \ - qlibrary - -contains(CONFIG, static) { - message(Disabling tests requiring shared build of Qt) - SUBDIRS -= qfactoryloader \ - qplugin -} diff --git a/tests/auto/corelib/plugin/qfactoryloader/CMakeLists.txt b/tests/auto/corelib/plugin/qfactoryloader/CMakeLists.txt new file mode 100644 index 0000000000..14174da173 --- /dev/null +++ b/tests/auto/corelib/plugin/qfactoryloader/CMakeLists.txt @@ -0,0 +1,13 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qfactoryloader LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +add_subdirectory(plugin1) +add_subdirectory(plugin2) +add_subdirectory(staticplugin) +add_subdirectory(test) diff --git a/tests/auto/corelib/plugin/qfactoryloader/plugin1/CMakeLists.txt b/tests/auto/corelib/plugin/qfactoryloader/plugin1/CMakeLists.txt new file mode 100644 index 0000000000..c7cedd7e0c --- /dev/null +++ b/tests/auto/corelib/plugin/qfactoryloader/plugin1/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## plugin1 Generic Library: +##################################################################### + +qt_internal_add_cmake_library(tst_qfactoryloader_plugin1 + MODULE + INSTALL_DIRECTORY "${INSTALL_TESTSDIR}/tst_qfactoryloader/bin" + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../bin" + SOURCES + plugin1.cpp plugin1.h + LIBRARIES + Qt::Core +) + +if(ANDROID) + # On Android the plugins must match the following mask: + # "libplugins_{suffix}_*.so" + # and the testcase uses "bin" as a suffix + set_target_properties(tst_qfactoryloader_plugin1 PROPERTIES + OUTPUT_NAME "plugins_bin_tst_qfactoryloader_plugin1") +endif() + +qt_internal_extend_target(tst_qfactoryloader_plugin1 CONDITION NOT QT_FEATURE_library + DEFINES + QT_STATICPLUGIN +) + +qt_autogen_tools_initial_setup(tst_qfactoryloader_plugin1) diff --git a/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.cpp b/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.cpp index bfa49dc34e..6731d560a7 100644 --- a/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.cpp +++ b/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtCore/qstring.h> #include "plugin1.h" @@ -32,3 +7,5 @@ QString Plugin1::pluginName() const { return QLatin1String("Plugin1 ok"); } + +#include "moc_plugin1.cpp" diff --git a/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.h b/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.h index ca2ceed7a9..aba0b5c2f5 100644 --- a/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.h +++ b/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef THEPLUGIN_H #define THEPLUGIN_H @@ -35,11 +10,11 @@ class Plugin1 : public QObject, public PluginInterface1 { Q_OBJECT - Q_PLUGIN_METADATA(IID "org.qt-project.Qt.autotests.plugininterface1") + Q_PLUGIN_METADATA(IID "org.qt-project.Qt.autotests.plugininterface1" FILE "plugin1.json") Q_INTERFACES(PluginInterface1) public: - virtual QString pluginName() const; + virtual QString pluginName() const override; }; #endif // THEPLUGIN_H diff --git a/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.json b/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.json new file mode 100644 index 0000000000..ce67846d48 --- /dev/null +++ b/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.json @@ -0,0 +1,5 @@ +{ + "Keys": [ + "plugin1" + ] +} diff --git a/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.pro b/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.pro deleted file mode 100644 index 44ef12db29..0000000000 --- a/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugin1.pro +++ /dev/null @@ -1,14 +0,0 @@ -TEMPLATE = lib -QT = core -CONFIG += plugin -HEADERS = plugin1.h -SOURCES = plugin1.cpp -TARGET = $$qtLibraryTarget(plugin1) -DESTDIR = ../bin -winrt:include(../winrt.pri) - -!qtConfig(library): DEFINES += QT_STATICPLUGIN - -# This is testdata for the tst_qpluginloader test. -target.path = $$[QT_INSTALL_TESTS]/tst_qfactoryloader/bin -INSTALLS += target diff --git a/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugininterface1.h b/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugininterface1.h index 408e963adf..a652273eb5 100644 --- a/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugininterface1.h +++ b/tests/auto/corelib/plugin/qfactoryloader/plugin1/plugininterface1.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef PLUGININTERFACE1_H #define PLUGININTERFACE1_H diff --git a/tests/auto/corelib/plugin/qfactoryloader/plugin2/CMakeLists.txt b/tests/auto/corelib/plugin/qfactoryloader/plugin2/CMakeLists.txt new file mode 100644 index 0000000000..259d6fb739 --- /dev/null +++ b/tests/auto/corelib/plugin/qfactoryloader/plugin2/CMakeLists.txt @@ -0,0 +1,31 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## plugin2 Generic Library: +##################################################################### + +qt_internal_add_cmake_library(tst_qfactoryloader_plugin2 + MODULE + INSTALL_DIRECTORY "${INSTALL_TESTSDIR}/tst_qfactoryloader/bin" + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../bin" + SOURCES + plugin2.cpp plugin2.h + LIBRARIES + Qt::Core +) + +if(ANDROID) + # On Android the plugins must match the following mask: + # "libplugins_{suffix}_*.so" + # and the testcase uses "bin" as a suffix + set_target_properties(tst_qfactoryloader_plugin2 PROPERTIES + OUTPUT_NAME "plugins_bin_tst_qfactoryloader_plugin2") +endif() + +qt_internal_extend_target(tst_qfactoryloader_plugin2 CONDITION NOT QT_FEATURE_library + DEFINES + QT_STATICPLUGIN +) + +qt_autogen_tools_initial_setup(tst_qfactoryloader_plugin2) diff --git a/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugin2.cpp b/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugin2.cpp index 34a7207f10..c2ac873317 100644 --- a/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugin2.cpp +++ b/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugin2.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtCore/qstring.h> #include "plugin2.h" @@ -32,3 +7,5 @@ QString Plugin2::pluginName() const { return QLatin1String("Plugin2 ok"); } + +#include "moc_plugin2.cpp" diff --git a/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugin2.h b/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugin2.h index 130bf66561..02ef062b77 100644 --- a/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugin2.h +++ b/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugin2.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef THEPLUGIN_H #define THEPLUGIN_H @@ -39,7 +14,7 @@ class Plugin2 : public QObject, public PluginInterface2 Q_INTERFACES(PluginInterface2) public: - virtual QString pluginName() const; + virtual QString pluginName() const override; }; #endif // THEPLUGIN_H diff --git a/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugin2.pro b/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugin2.pro deleted file mode 100644 index 5689919108..0000000000 --- a/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugin2.pro +++ /dev/null @@ -1,14 +0,0 @@ -TEMPLATE = lib -QT = core -CONFIG += plugin -HEADERS = plugin2.h -SOURCES = plugin2.cpp -TARGET = $$qtLibraryTarget(plugin2) -DESTDIR = ../bin -winrt:include(../winrt.pri) - -!qtConfig(library): DEFINES += QT_STATICPLUGIN - -# This is testdata for the tst_qpluginloader test. -target.path = $$[QT_INSTALL_TESTS]/tst_qfactoryloader/bin -INSTALLS += target diff --git a/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugininterface2.h b/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugininterface2.h index e9b7e14048..df30f2ffd3 100644 --- a/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugininterface2.h +++ b/tests/auto/corelib/plugin/qfactoryloader/plugin2/plugininterface2.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef PLUGININTERFACE2_H #define PLUGININTERFACE2_H diff --git a/tests/auto/corelib/plugin/qfactoryloader/qfactoryloader.pro b/tests/auto/corelib/plugin/qfactoryloader/qfactoryloader.pro deleted file mode 100644 index f0430d55e6..0000000000 --- a/tests/auto/corelib/plugin/qfactoryloader/qfactoryloader.pro +++ /dev/null @@ -1,15 +0,0 @@ -QT = core-private -TEMPLATE = subdirs - -test.depends = plugin1 plugin2 -SUBDIRS = \ - plugin1 \ - plugin2 \ - test - -TARGET = tst_qpluginloader - -# no special install rule for subdir -INSTALLS = - - diff --git a/tests/auto/corelib/plugin/qfactoryloader/staticplugin/CMakeLists.txt b/tests/auto/corelib/plugin/qfactoryloader/staticplugin/CMakeLists.txt new file mode 100644 index 0000000000..c43a69c707 --- /dev/null +++ b/tests/auto/corelib/plugin/qfactoryloader/staticplugin/CMakeLists.txt @@ -0,0 +1,14 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_cmake_library(tst_qfactoryloader_staticplugin + STATIC + SOURCES + main.cpp + LIBRARIES + Qt::Core +) + +qt_autogen_tools_initial_setup(tst_qfactoryloader_staticplugin) + +target_compile_definitions(tst_qfactoryloader_staticplugin PRIVATE QT_STATICPLUGIN) diff --git a/tests/auto/corelib/plugin/qfactoryloader/staticplugin/main.cpp b/tests/auto/corelib/plugin/qfactoryloader/staticplugin/main.cpp new file mode 100644 index 0000000000..6506f9cf9b --- /dev/null +++ b/tests/auto/corelib/plugin/qfactoryloader/staticplugin/main.cpp @@ -0,0 +1,22 @@ +// Copyright (C) 2018 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#include <QtPlugin> +#include <QObject> + +class StaticPlugin1 : public QObject +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "StaticPlugin1" FILE "plugin.json") +public: + StaticPlugin1() {} +}; + +class StaticPlugin2 : public QObject +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "StaticPlugin2" FILE "plugin.json") +public: + StaticPlugin2() {} +}; + +#include "main.moc" diff --git a/tests/auto/corelib/plugin/qfactoryloader/staticplugin/plugin.json b/tests/auto/corelib/plugin/qfactoryloader/staticplugin/plugin.json new file mode 100644 index 0000000000..7321080fb4 --- /dev/null +++ b/tests/auto/corelib/plugin/qfactoryloader/staticplugin/plugin.json @@ -0,0 +1,3 @@ +{ + "Keys": [ "Value" ] +} diff --git a/tests/auto/corelib/plugin/qfactoryloader/test/CMakeLists.txt b/tests/auto/corelib/plugin/qfactoryloader/test/CMakeLists.txt new file mode 100644 index 0000000000..fb3b6f5acb --- /dev/null +++ b/tests/auto/corelib/plugin/qfactoryloader/test/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## tst_qfactoryloader Test: +##################################################################### + +qt_internal_add_test(tst_qfactoryloader + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" + SOURCES + ../plugin1/plugininterface1.h + ../plugin2/plugininterface2.h + ../tst_qfactoryloader.cpp + LIBRARIES + Qt::CorePrivate + tst_qfactoryloader_staticplugin +) + +qt_internal_extend_target(tst_qfactoryloader CONDITION NOT QT_FEATURE_library + LIBRARIES + tst_qfactoryloader_plugin1 + tst_qfactoryloader_plugin2 +) + +add_dependencies(tst_qfactoryloader tst_qfactoryloader_plugin1 tst_qfactoryloader_plugin2) + +if(ANDROID) + # QT_ANDROID_EXTRA_PLUGINS requires a list of directories, not files! + set_target_properties(tst_qfactoryloader PROPERTIES + QT_ANDROID_EXTRA_PLUGINS "${CMAKE_CURRENT_BINARY_DIR}/../bin" + ) +endif() diff --git a/tests/auto/corelib/plugin/qfactoryloader/test/test.pro b/tests/auto/corelib/plugin/qfactoryloader/test/test.pro deleted file mode 100644 index 5e4d65a49f..0000000000 --- a/tests/auto/corelib/plugin/qfactoryloader/test/test.pro +++ /dev/null @@ -1,30 +0,0 @@ -CONFIG += testcase -TARGET = ../tst_qfactoryloader -QT = core-private testlib - -SOURCES = \ - ../tst_qfactoryloader.cpp - -HEADERS = \ - ../plugin1/plugininterface1.h \ - ../plugin2/plugininterface2.h - -win32 { - CONFIG(debug, debug|release) { - TARGET = ../../debug/tst_qfactoryloader - } else { - TARGET = ../../release/tst_qfactoryloader - } -} - -!qtConfig(library) { - LIBS += -L ../bin/ -lplugin1 -lplugin2 -} - -android { - libs.prefix = android_test_data - libs.base = $$OUT_PWD/.. - libs.files += $$OUT_PWD/../bin - - RESOURCES += libs -} diff --git a/tests/auto/corelib/plugin/qfactoryloader/tst_qfactoryloader.cpp b/tests/auto/corelib/plugin/qfactoryloader/tst_qfactoryloader.cpp index 9fa61804b3..faec311f2d 100644 --- a/tests/auto/corelib/plugin/qfactoryloader/tst_qfactoryloader.cpp +++ b/tests/auto/corelib/plugin/qfactoryloader/tst_qfactoryloader.cpp @@ -1,36 +1,13 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtTest/qtest.h> #include <QtCore/qdir.h> #include <QtCore/qfileinfo.h> #include <QtCore/qplugin.h> +#include <QtCore/qversionnumber.h> #include <private/qfactoryloader_p.h> +#include <private/qlibrary_p.h> #include "plugin1/plugininterface1.h" #include "plugin2/plugininterface2.h" @@ -43,54 +20,202 @@ class tst_QFactoryLoader : public QObject { Q_OBJECT -#ifdef Q_OS_ANDROID - QSharedPointer<QTemporaryDir> directory; -#endif - + QString binFolder; public slots: void initTestCase(); private slots: void usingTwoFactoriesFromSameDir(); + void extraSearchPath(); + void multiplePaths(); + void staticPlugin_data(); + void staticPlugin(); }; static const char binFolderC[] = "bin"; void tst_QFactoryLoader::initTestCase() { -#ifdef Q_OS_ANDROID - directory = QEXTRACTTESTDATA("android_test_data"); - QVERIFY(directory); - QVERIFY(directory->isValid()); - QVERIFY2(QDir::setCurrent(directory->path()), qPrintable("Could not chdir to " + directory->path())); -#endif - const QString binFolder = QFINDTESTDATA(binFolderC); + // On Android the plugins are bundled into APK's libs subdir +#ifndef Q_OS_ANDROID + binFolder = QFINDTESTDATA(binFolderC); QVERIFY2(!binFolder.isEmpty(), "Unable to locate 'bin' folder"); -#if QT_CONFIG(library) - QCoreApplication::setLibraryPaths(QStringList(QFileInfo(binFolder).absolutePath())); #endif } void tst_QFactoryLoader::usingTwoFactoriesFromSameDir() { +#if QT_CONFIG(library) && !defined(Q_OS_ANDROID) + // set the library path to contain the directory where the 'bin' dir is located + QCoreApplication::setLibraryPaths( { QFileInfo(binFolder).absolutePath() }); +#endif + auto versionNumber = [](const QCborValue &value) { + // Qt plugins only store major & minor versions in the metadata, so + // the low 8 bits are always zero. + qint64 v = value.toInteger(); + return QVersionNumber(v >> 16, uchar(v >> 8)); + }; + QVersionNumber qtVersion(QT_VERSION_MAJOR, 0); + const QString suffix = QLatin1Char('/') + QLatin1String(binFolderC); QFactoryLoader loader1(PluginInterface1_iid, suffix); + const QFactoryLoader::MetaDataList list1 = loader1.metaData(); + const QList<QCborArray> keys1 = loader1.metaDataKeys(); + QCOMPARE(list1.size(), 1); + QCOMPARE(keys1.size(), 1); + QCOMPARE_GE(versionNumber(list1[0].value(QtPluginMetaDataKeys::QtVersion)), qtVersion); + QCOMPARE(list1[0].value(QtPluginMetaDataKeys::IID), PluginInterface1_iid); + QCOMPARE(list1[0].value(QtPluginMetaDataKeys::ClassName), "Plugin1"); - PluginInterface1 *plugin1 = qobject_cast<PluginInterface1 *>(loader1.instance(0)); + // plugin1's Q_PLUGIN_METADATA has FILE "plugin1.json" + QCborValue metadata1 = list1[0].value(QtPluginMetaDataKeys::MetaData); + QCOMPARE(metadata1.type(), QCborValue::Map); + QCOMPARE(metadata1["Keys"], QCborArray{ "plugin1" }); + QCOMPARE(keys1[0], QCborArray{ "plugin1" }); + QCOMPARE(loader1.indexOf("Plugin1"), 0); + QCOMPARE(loader1.indexOf("PLUGIN1"), 0); + QCOMPARE(loader1.indexOf("Plugin2"), -1); + + QFactoryLoader loader2(PluginInterface2_iid, suffix); + const QFactoryLoader::MetaDataList list2 = loader2.metaData(); + const QList<QCborArray> keys2 = loader2.metaDataKeys(); + QCOMPARE(list2.size(), 1); + QCOMPARE(keys2.size(), 1); + QCOMPARE_GE(versionNumber(list2[0].value(QtPluginMetaDataKeys::QtVersion)), qtVersion); + QCOMPARE(list2[0].value(QtPluginMetaDataKeys::IID), PluginInterface2_iid); + QCOMPARE(list2[0].value(QtPluginMetaDataKeys::ClassName), "Plugin2"); + + // plugin2's Q_PLUGIN_METADATA does not have FILE + QCOMPARE(list2[0].value(QtPluginMetaDataKeys::MetaData), QCborValue()); + QCOMPARE(keys2[0], QCborArray()); + QCOMPARE(loader2.indexOf("Plugin1"), -1); + QCOMPARE(loader2.indexOf("Plugin2"), -1); + + QObject *obj1 = loader1.instance(0); + PluginInterface1 *plugin1 = qobject_cast<PluginInterface1 *>(obj1); QVERIFY2(plugin1, qPrintable(QString::fromLatin1("Cannot load plugin '%1'") .arg(QLatin1String(PluginInterface1_iid)))); + QCOMPARE(obj1->metaObject()->className(), "Plugin1"); - QFactoryLoader loader2(PluginInterface2_iid, suffix); - - PluginInterface2 *plugin2 = qobject_cast<PluginInterface2 *>(loader2.instance(0)); + QObject *obj2 = loader2.instance(0); + PluginInterface2 *plugin2 = qobject_cast<PluginInterface2 *>(obj2); QVERIFY2(plugin2, qPrintable(QString::fromLatin1("Cannot load plugin '%1'") .arg(QLatin1String(PluginInterface2_iid)))); + QCOMPARE(obj2->metaObject()->className(), "Plugin2"); QCOMPARE(plugin1->pluginName(), QLatin1String("Plugin1 ok")); QCOMPARE(plugin2->pluginName(), QLatin1String("Plugin2 ok")); } +void tst_QFactoryLoader::extraSearchPath() +{ +#if defined(Q_OS_ANDROID) && !QT_CONFIG(library) + QSKIP("Test not applicable in this configuration."); +#else +#ifdef Q_OS_ANDROID + // On Android the libs are not stored in binFolder, but bundled into + // APK's libs subdir + const QStringList androidLibsPaths = QCoreApplication::libraryPaths(); + QCOMPARE(androidLibsPaths.size(), 1); +#endif + QCoreApplication::setLibraryPaths(QStringList()); + +#ifndef Q_OS_ANDROID + QString pluginsPath = QFileInfo(binFolder).absoluteFilePath(); + QFactoryLoader loader1(PluginInterface1_iid, "/nonexistent"); +#else + QString pluginsPath = androidLibsPaths.first(); + // On Android we still need to specify a valid suffix, because it's a part + // of a file name, not directory structure + const QString suffix = QLatin1Char('/') + QLatin1String(binFolderC); + QFactoryLoader loader1(PluginInterface1_iid, suffix); +#endif + + // it shouldn't have scanned anything because we haven't given it a path yet + QVERIFY(loader1.metaData().isEmpty()); + + loader1.setExtraSearchPath(pluginsPath); + PluginInterface1 *plugin1 = qobject_cast<PluginInterface1 *>(loader1.instance(0)); + QVERIFY2(plugin1, + qPrintable(QString::fromLatin1("Cannot load plugin '%1'") + .arg(QLatin1String(PluginInterface1_iid)))); + + QCOMPARE(plugin1->pluginName(), QLatin1String("Plugin1 ok")); + + // check that it forgets that plugin + loader1.setExtraSearchPath(QString()); + QVERIFY(loader1.metaData().isEmpty()); +#endif +} + +void tst_QFactoryLoader::multiplePaths() +{ +#if !QT_CONFIG(library) || !(defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN)) || defined(Q_OS_ANDROID) + QSKIP("Test not applicable in this configuration."); +#else + QTemporaryDir dir; + QVERIFY(dir.isValid()); + + QString pluginsPath = QFileInfo(binFolder, binFolderC).absolutePath(); + QString linkPath = dir.filePath(binFolderC); + QVERIFY(QFile::link(pluginsPath, linkPath)); + + QCoreApplication::setLibraryPaths({ QFileInfo(binFolder).absolutePath(), dir.path() }); + + const QString suffix = QLatin1Char('/') + QLatin1String(binFolderC); + QFactoryLoader loader1(PluginInterface1_iid, suffix); + + QLibraryPrivate *library1 = loader1.library("plugin1"); + QVERIFY(library1); + QCOMPARE(library1->loadHints(), QLibrary::PreventUnloadHint); +#endif +} + +Q_IMPORT_PLUGIN(StaticPlugin1) +Q_IMPORT_PLUGIN(StaticPlugin2) +constexpr bool IsDebug = +#ifdef QT_NO_DEBUG + false && +#endif + true; + +void tst_QFactoryLoader::staticPlugin_data() +{ + QTest::addColumn<QString>("iid"); + auto addRow = [](const char *iid) { + QTest::addRow("%s", iid) << QString(iid); + }; + addRow("StaticPlugin1"); + addRow("StaticPlugin2"); +} + +void tst_QFactoryLoader::staticPlugin() +{ + QFETCH(QString, iid); + QFactoryLoader loader(iid.toLatin1(), "/irrelevant"); + QFactoryLoader::MetaDataList list = loader.metaData(); + QCOMPARE(list.size(), 1); + + QCborMap map = list.at(0).toCbor(); + QCOMPARE(map[int(QtPluginMetaDataKeys::QtVersion)], + QT_VERSION_CHECK(QT_VERSION_MAJOR, QT_VERSION_MINOR, 0)); + QCOMPARE(map[int(QtPluginMetaDataKeys::IID)], iid); + QCOMPARE(map[int(QtPluginMetaDataKeys::ClassName)], iid); + QCOMPARE(map[int(QtPluginMetaDataKeys::IsDebug)], IsDebug); + + QCborValue metaData = map[int(QtPluginMetaDataKeys::MetaData)]; + QVERIFY(metaData.isMap()); + QCOMPARE(metaData["Keys"], QCborArray{ "Value" }); + QCOMPARE(loader.metaDataKeys(), QList{ QCborArray{ "Value" } }); + QCOMPARE(loader.indexOf("Value"), 0); + + // instantiate + QObject *instance = loader.instance(0); + QVERIFY(instance); + QCOMPARE(instance->metaObject()->className(), iid); +} + QTEST_MAIN(tst_QFactoryLoader) #include "tst_qfactoryloader.moc" diff --git a/tests/auto/corelib/plugin/qfactoryloader/winrt.pri b/tests/auto/corelib/plugin/qfactoryloader/winrt.pri deleted file mode 100644 index 31602634b2..0000000000 --- a/tests/auto/corelib/plugin/qfactoryloader/winrt.pri +++ /dev/null @@ -1,9 +0,0 @@ -# We cannot use TESTDATA as plugins have to reside physically -# inside the package directory -winrt { - CONFIG(debug, debug|release) { - DESTDIR = ../debug/bin - } else { - DESTDIR = ../release/bin - } -} diff --git a/tests/auto/corelib/plugin/qlibrary/CMakeLists.txt b/tests/auto/corelib/plugin/qlibrary/CMakeLists.txt new file mode 100644 index 0000000000..b8f4af5aa8 --- /dev/null +++ b/tests/auto/corelib/plugin/qlibrary/CMakeLists.txt @@ -0,0 +1,12 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qlibrary LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +add_subdirectory(lib) +add_subdirectory(lib2) +add_subdirectory(tst) diff --git a/tests/auto/corelib/plugin/qlibrary/lib/CMakeLists.txt b/tests/auto/corelib/plugin/qlibrary/lib/CMakeLists.txt new file mode 100644 index 0000000000..1a318e1483 --- /dev/null +++ b/tests/auto/corelib/plugin/qlibrary/lib/CMakeLists.txt @@ -0,0 +1,75 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## mylib Generic Library: +##################################################################### + +qt_internal_add_cmake_library(mylib + SHARED + INSTALL_DIRECTORY "${INSTALL_TESTSDIR}/tst_qlibrary" + SOURCES + mylib.c + LIBRARIES + Qt::Core +) + +set_target_properties(mylib PROPERTIES + VERSION 1.0.0 + SOVERSION 1 + C_VISIBILITY_PRESET "default" + CXX_VISIBILITY_PRESET "default" +) + +if(WIN32) + # CMake sets for Windows-GNU platforms the suffix "lib" + set_property(TARGET mylib PROPERTY PREFIX "") +endif() + +if(UNIX) + if(APPLE) + add_custom_command(TARGET mylib POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $<TARGET_FILE:mylib> + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.1.0.0.dylib" + COMMAND ${CMAKE_COMMAND} -E create_symlink + "libmylib.1.0.0.dylib" + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.1.dylib" + VERBATIM) + elseif(NOT ANDROID) + add_custom_command(TARGET mylib POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $<TARGET_FILE:mylib> + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.so.1.0.0" + COMMAND ${CMAKE_COMMAND} -E create_symlink + "libmylib.so.1.0.0" + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.so.1" + COMMAND ${CMAKE_COMMAND} -E create_symlink + "libmylib.so.1.0.0" + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.so1" + VERBATIM) + else() + # Android does not use symlinks. Also, according to our conventions, + # libraries on Android MUST be named in the following pattern: + # lib*.so + add_custom_command(TARGET mylib POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $<TARGET_FILE:mylib> + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.so" + VERBATIM) + endif() +else() #Win32 + add_custom_command(TARGET mylib POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $<TARGET_FILE:mylib> + "${CMAKE_CURRENT_BINARY_DIR}/../mylib.dll" + VERBATIM) +endif() + +## Scopes: +##################################################################### + +qt_internal_extend_target(mylib CONDITION MSVC + DEFINES + WIN32_MSVC +) diff --git a/tests/auto/corelib/plugin/qlibrary/lib/lib.pro b/tests/auto/corelib/plugin/qlibrary/lib/lib.pro deleted file mode 100644 index c44cd46597..0000000000 --- a/tests/auto/corelib/plugin/qlibrary/lib/lib.pro +++ /dev/null @@ -1,21 +0,0 @@ -TEMPLATE = lib -CONFIG += dll -CONFIG -= staticlib -SOURCES = mylib.c -TARGET = mylib -DESTDIR = ../ -QT = core - -msvc: DEFINES += WIN32_MSVC - -# This project is testdata for tst_qlibrary -target.path = $$[QT_INSTALL_TESTS]/tst_qlibrary -INSTALLS += target - -win32 { - CONFIG(debug, debug|release) { - DESTDIR = ../debug/ - } else { - DESTDIR = ../release/ - } -} diff --git a/tests/auto/corelib/plugin/qlibrary/lib/mylib.c b/tests/auto/corelib/plugin/qlibrary/lib/mylib.c index 419c22a446..61fe52d182 100644 --- a/tests/auto/corelib/plugin/qlibrary/lib/mylib.c +++ b/tests/auto/corelib/plugin/qlibrary/lib/mylib.c @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qglobal.h> diff --git a/tests/auto/corelib/plugin/qlibrary/lib2/CMakeLists.txt b/tests/auto/corelib/plugin/qlibrary/lib2/CMakeLists.txt new file mode 100644 index 0000000000..f6bdeb453a --- /dev/null +++ b/tests/auto/corelib/plugin/qlibrary/lib2/CMakeLists.txt @@ -0,0 +1,110 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## mylib Generic Library: +##################################################################### + +qt_internal_add_cmake_library(mylib2 + SHARED + INSTALL_DIRECTORY "${INSTALL_TESTSDIR}tst_qlibrary" + #OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" + SOURCES + mylib.c + LIBRARIES + Qt::Core +) + +# This test is very "annoying" to get working with CMake as it involves having +# two targets with the same name on the parent scope, which is not possible with +# CMake. Furthermore, on UNIX, this version of the library should override the +# root symlink (libmylib.so) to point to version 2. +# Since we can't build two targets with the same name and in the same directory, +# we build mylib2 in it's own directory and manually copy and create the +# symlinks in the parent directory. +# Finally we also need to create a libmylib.so2 file in the parent directory. +# +set_target_properties(mylib2 PROPERTIES + OUTPUT_NAME mylib +) +set_target_properties(mylib2 PROPERTIES + VERSION 2.0.0 + SOVERSION 2 + C_VISIBILITY_PRESET "default" + CXX_VISIBILITY_PRESET "default" +) + +if(WIN32) + # CMake sets for Windows-GNU platforms the suffix "lib" + set_property(TARGET mylib2 PROPERTY PREFIX "") +endif() + +if(UNIX) + if(APPLE) + add_custom_command(TARGET mylib2 POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $<TARGET_FILE:mylib2> + "${CMAKE_CURRENT_BINARY_DIR}/../system.qt.test.mylib.so.dylib" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $<TARGET_FILE:mylib2> + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.2.0.0.dylib" + COMMAND ${CMAKE_COMMAND} -E create_symlink + "libmylib.2.0.0.dylib" + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.2.dylib" + COMMAND ${CMAKE_COMMAND} -E remove + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.dylib" + COMMAND ${CMAKE_COMMAND} -E create_symlink + "libmylib.2.0.0.dylib" + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.dylib" + COMMAND ${CMAKE_COMMAND} -E create_symlink + "libmylib.2.0.0.dylib" + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.so2.dylib" + VERBATIM) + elseif(NOT ANDROID) + add_custom_command(TARGET mylib2 POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $<TARGET_FILE:mylib2> + "${CMAKE_CURRENT_BINARY_DIR}/../system.qt.test.mylib.so" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $<TARGET_FILE:mylib2> + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.so.2.0.0" + COMMAND ${CMAKE_COMMAND} -E create_symlink + "libmylib.so.2.0.0" + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.so.2" + COMMAND ${CMAKE_COMMAND} -E remove + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.so" + COMMAND ${CMAKE_COMMAND} -E create_symlink + "libmylib.so.2.0.0" + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.so" + COMMAND ${CMAKE_COMMAND} -E create_symlink + "libmylib.so.2.0.0" + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.so2" + VERBATIM) + else() + # Android does not use symlinks. Also, according to our conventions, + # libraries on Android MUST be named in the following pattern: + # lib*.so + add_custom_command(TARGET mylib2 POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $<TARGET_FILE:mylib2> + "${CMAKE_CURRENT_BINARY_DIR}/../libsystem.qt.test.mylib.so" + VERBATIM) + endif() +else() #Win32 + add_custom_command(TARGET mylib2 POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $<TARGET_FILE:mylib2> + "${CMAKE_CURRENT_BINARY_DIR}/../system.qt.test.mylib.dll" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + $<TARGET_FILE:mylib2> + "${CMAKE_CURRENT_BINARY_DIR}/../mylib.dl2" + VERBATIM) +endif() + +## Scopes: +##################################################################### + +qt_internal_extend_target(mylib2 CONDITION MSVC + DEFINES + WIN32_MSVC +) diff --git a/tests/auto/corelib/plugin/qlibrary/lib2/lib2.pro b/tests/auto/corelib/plugin/qlibrary/lib2/lib2.pro deleted file mode 100644 index bfda0e0194..0000000000 --- a/tests/auto/corelib/plugin/qlibrary/lib2/lib2.pro +++ /dev/null @@ -1,47 +0,0 @@ -TEMPLATE = lib -CONFIG += dll -CONFIG -= staticlib -SOURCES = mylib.c -TARGET = mylib -DESTDIR = ../ -VERSION = 2 -QT = core - -msvc: DEFINES += WIN32_MSVC - -# Force a copy of the library to have an extension that is non-standard. -# We want to test if we can load a shared library with *any* filename... - -win32 { - CONFIG(debug, debug|release) { - BUILD_FOLDER = debug - } else { - BUILD_FOLDER = release - } - DESTDIR = ../$$BUILD_FOLDER/ - - # vcproj and Makefile generators refer to target differently - contains(TEMPLATE,vc.*) { - src = $(TargetPath) - } else { - src = $(DESTDIR_TARGET) - } - files = $$BUILD_FOLDER$${QMAKE_DIR_SEP}mylib.dl2 $$BUILD_FOLDER$${QMAKE_DIR_SEP}system.qt.test.mylib.dll -} else { - src = $(DESTDIR)$(TARGET) - files = libmylib.so2 system.qt.test.mylib.so -} - -# This project is testdata for tst_qlibrary -target.path = $$[QT_INSTALL_TESTS]$${QMAKE_DIR_SEP}tst_qlibrary -renamed_target.path = $$target.path - -for(file, files) { - QMAKE_POST_LINK += $$QMAKE_COPY $$src ..$$QMAKE_DIR_SEP$$file && - renamed_target.extra += $$QMAKE_COPY $$src $(INSTALL_ROOT)$${target.path}$$QMAKE_DIR_SEP$$file && - CLEAN_FILES += ..$$QMAKE_DIR_SEP$$file -} -renamed_target.extra = $$member(renamed_target.extra, 0, -2) -QMAKE_POST_LINK = $$member(QMAKE_POST_LINK, 0, -2) - -INSTALLS += target renamed_target diff --git a/tests/auto/corelib/plugin/qlibrary/lib2/mylib.c b/tests/auto/corelib/plugin/qlibrary/lib2/mylib.c index 74eb68b2ac..5312a9355b 100644 --- a/tests/auto/corelib/plugin/qlibrary/lib2/mylib.c +++ b/tests/auto/corelib/plugin/qlibrary/lib2/mylib.c @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qglobal.h> diff --git a/tests/auto/corelib/plugin/qlibrary/qlibrary.pro b/tests/auto/corelib/plugin/qlibrary/qlibrary.pro deleted file mode 100644 index ec230601c4..0000000000 --- a/tests/auto/corelib/plugin/qlibrary/qlibrary.pro +++ /dev/null @@ -1,15 +0,0 @@ -QT = core -TEMPLATE = subdirs - -tst.depends = lib lib2 -# lib2 has to be installed after lib, so that plain libmylib.so symlink points -# to version 2 as expected by the test -lib2.depends = lib - -SUBDIRS = lib \ - lib2 \ - tst -TARGET = tst_qlibrary - -# no special install rule for subdir -INSTALLS = diff --git a/tests/auto/corelib/plugin/qlibrary/tst/CMakeLists.txt b/tests/auto/corelib/plugin/qlibrary/tst/CMakeLists.txt new file mode 100644 index 0000000000..fc452f37f5 --- /dev/null +++ b/tests/auto/corelib/plugin/qlibrary/tst/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## tst_qlibrary Test: +##################################################################### + +# Collect test data +list(APPEND test_data "../library_path/invalid.so") + +qt_internal_add_test(tst_qlibrary + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" + SOURCES + ../tst_qlibrary.cpp + TESTDATA ${test_data} + LIBRARIES mylib mylib2 +) + +add_dependencies(tst_qlibrary mylib mylib2) + +if(ANDROID) + list(APPEND extra_libs + "${CMAKE_CURRENT_BINARY_DIR}/../libmylib.so") + list(APPEND extra_libs + "${CMAKE_CURRENT_BINARY_DIR}/../libsystem.qt.test.mylib.so") + set_target_properties(tst_qlibrary PROPERTIES + QT_ANDROID_EXTRA_LIBS "${extra_libs}") +endif() diff --git a/tests/auto/corelib/plugin/qlibrary/tst/tst.pro b/tests/auto/corelib/plugin/qlibrary/tst/tst.pro deleted file mode 100644 index 56bef14405..0000000000 --- a/tests/auto/corelib/plugin/qlibrary/tst/tst.pro +++ /dev/null @@ -1,25 +0,0 @@ -CONFIG += testcase -TARGET = ../tst_qlibrary -QT = core testlib -SOURCES = ../tst_qlibrary.cpp - -win32 { - CONFIG(debug, debug|release) { - TARGET = ../../debug/tst_qlibrary - } else { - TARGET = ../../release/tst_qlibrary - } -} - -TESTDATA += ../library_path/invalid.so - -android { - libs.prefix = android_test_data - libs.base = $$OUT_PWD/.. - libs.files += $$OUT_PWD/../libmylib.so \ - $$OUT_PWD/../libmylib.so2 \ - $$OUT_PWD/../libmylib.prl \ - $$OUT_PWD/../system.qt.test.mylib.so - - RESOURCES += libs -} diff --git a/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp b/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp index c9c9202a80..28f4581997 100644 --- a/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp +++ b/tests/auto/corelib/plugin/qlibrary/tst_qlibrary.cpp @@ -1,36 +1,11 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include <QtTest/QtTest> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + + +#include <QTest> #include <qdir.h> #include <qlibrary.h> -#include <QtCore/QRegExp> +#include <QtCore/QRegularExpression> // Helper macros to let us know if some suffixes and prefixes are valid @@ -104,24 +79,27 @@ enum QLibraryOperation { QString sys_qualifiedLibraryName(const QString &fileName); QString directory; -#ifdef Q_OS_ANDROID - QSharedPointer<QTemporaryDir> temporaryDir; -#endif private slots: void initTestCase(); + void cleanup(); - void load(); void load_data(); - void library_data(); + void load(); void resolve_data(); void resolve(); void unload_data(); void unload(); void unload_after_implicit_load(); + void setFilenameAfterFailedLoad(); + void loadAfterFailedLoad(); void isLibrary_data(); void isLibrary(); void version_data(); void version(); + void loadTwoVersions(); + void setFileNameAndVersionTwice(); + void setFileNameAndVersionAfterFailedLoad_data() { version_data(); } + void setFileNameAndVersionAfterFailedLoad(); void errorString_data(); void errorString(); void loadHints(); @@ -141,34 +119,49 @@ typedef int (*VersionFunction)(void); void tst_QLibrary::initTestCase() { #ifdef Q_OS_ANDROID - auto tempDir = QEXTRACTTESTDATA("android_test_data"); - - QVERIFY2(QDir::setCurrent(tempDir->path()), qPrintable("Could not chdir to " + tempDir->path())); - - // copy :/library_path into ./library_path - QVERIFY(QDir().mkdir("library_path")); - QDirIterator iterator(":/library_path", QDirIterator::Subdirectories); - while (iterator.hasNext()) { - iterator.next(); - QFileInfo sourceFileInfo(iterator.path()); - QFileInfo targetFileInfo("./library_path/" + sourceFileInfo.fileName()); - if (!targetFileInfo.exists()) { - QDir().mkpath(targetFileInfo.path()); - QVERIFY(QFile::copy(sourceFileInfo.filePath(), targetFileInfo.filePath())); - } - } - directory = tempDir->path(); - temporaryDir = std::move(tempDir); -#elif !defined(Q_OS_WINRT) + const QStringList paths = QCoreApplication::libraryPaths(); + QVERIFY(!paths.isEmpty()); + directory = paths.first(); +#else // chdir to our testdata directory, and use relative paths in some tests. QString testdatadir = QFileInfo(QFINDTESTDATA("library_path")).absolutePath(); QVERIFY2(QDir::setCurrent(testdatadir), qPrintable("Could not chdir to " + testdatadir)); directory = QCoreApplication::applicationDirPath(); -#elif defined(Q_OS_WINRT) - directory = QCoreApplication::applicationDirPath(); #endif } +void tst_QLibrary::cleanup() +{ + // unload the libraries, if they are still loaded after the test ended + // (probably in a failure) + + static struct { + QString name; + int version = -1; + } libs[] = { + { directory + "/mylib" }, + { directory + "/mylib", 1 }, + { directory + "/mylib", 2 }, + { sys_qualifiedLibraryName("mylib") }, + + // stuff that load_data() succeeds with + { directory + "/" PREFIX "mylib" }, + { directory + "/" PREFIX "mylib" SUFFIX }, +#if defined(Q_OS_WIN32) + { directory + "/mylib.dl2" }, + { directory + "/system.qt.test.mylib.dll" }, +#elif !defined(Q_OS_ANDROID) + // .so even on macOS + { directory + "/libmylib.so2" }, + { directory + "/system.qt.test.mylib.so" }, +#endif + + }; + for (const auto &entry : libs) { + do {} while (QLibrary(entry.name, entry.version).unload()); + } +} + void tst_QLibrary::version_data() { #ifdef Q_OS_ANDROID @@ -205,6 +198,70 @@ void tst_QLibrary::version() #endif } +void tst_QLibrary::loadTwoVersions() +{ +#if defined(Q_OS_ANDROID) || defined(Q_OS_WIN) + QSKIP("Versioned files are not generated for this OS, so this test is not applicable."); +#endif + + QLibrary lib1(directory + "/mylib", 1); + QLibrary lib2(directory + "/mylib", 2); + QVERIFY(!lib1.isLoaded()); + QVERIFY(!lib2.isLoaded()); + + // load the first one + QVERIFY(lib1.load()); + QVERIFY(lib1.isLoaded()); + + // let's see if we can load the second one too + QVERIFY(lib2.load()); + QVERIFY(lib2.isLoaded()); + + auto p1 = (VersionFunction)lib1.resolve("mylibversion"); + QVERIFY(p1); + + auto p2 = (VersionFunction)lib2.resolve("mylibversion"); + QVERIFY(p2); + + QCOMPARE_NE(p1(), p2()); + + lib2.unload(); + lib1.unload(); +} + +void tst_QLibrary::setFileNameAndVersionTwice() +{ +#if defined(Q_OS_ANDROID) || defined(Q_OS_WIN) + QSKIP("Versioned files are not generated for this OS, so this test is not applicable."); +#endif + + QLibrary library(directory + "/mylib", 1); + QVERIFY(library.load()); + QVERIFY(library.isLoaded()); + + auto p1 = (VersionFunction)library.resolve("mylibversion"); + QVERIFY(p1); + // don't .unload() + + library.setFileNameAndVersion(directory + "/mylib", 2); + QVERIFY(!library.isLoaded()); + QVERIFY(library.load()); + QVERIFY(library.isLoaded()); + + auto p2 = (VersionFunction)library.resolve("mylibversion"); + QVERIFY(p2); + QCOMPARE_NE(p1(), p2()); + + QVERIFY(library.unload()); + QVERIFY(!library.isLoaded()); + + // set back + // it'll look like it isn't loaded, but it is and we can't unload it! + library.setFileNameAndVersion(directory + "/mylib", 1); + QVERIFY(!library.isLoaded()); + QVERIFY(!library.unload()); +} + void tst_QLibrary::load_data() { QTest::addColumn<QString>("lib"); @@ -216,7 +273,7 @@ void tst_QLibrary::load_data() QTest::newRow( "notexist" ) << appDir + "/nolib" << false; QTest::newRow( "badlibrary" ) << appDir + "/qlibrary.pro" << false; -#ifdef Q_OS_MAC +#ifdef Q_OS_DARWIN QTest::newRow("ok (libmylib ver. 1)") << appDir + "/libmylib" <<true; #endif @@ -226,7 +283,10 @@ void tst_QLibrary::load_data() QTest::newRow( "ok03 (with many dots)" ) << appDir + "/system.qt.test.mylib.dll" << true; # elif defined Q_OS_UNIX QTest::newRow( "ok01 (with suffix)" ) << appDir + "/libmylib" SUFFIX << true; +#ifndef Q_OS_ANDROID + // We do not support non-standard suffixes on Android QTest::newRow( "ok02 (with non-standard suffix)" ) << appDir + "/libmylib.so2" << true; +#endif QTest::newRow( "ok03 (with many dots)" ) << appDir + "/system.qt.test.mylib.so" << true; # endif // Q_OS_UNIX } @@ -282,6 +342,76 @@ void tst_QLibrary::unload_after_implicit_load() QCOMPARE(library.isLoaded(), false); } +void tst_QLibrary::setFilenameAfterFailedLoad() +{ +#if defined(Q_OS_WIN) || defined(Q_OS_ANDROID) + QSKIP("### FIXME: The helper libraries are currently messed up in the CMakeLists.txt"); +#endif + + QLibrary library(directory + "/nolib"); + QVERIFY(!library.load()); + QVERIFY(!library.isLoaded()); + QVERIFY(!library.load()); + QVERIFY(!library.isLoaded()); + + library.setFileName(directory + "/mylib"); + QVERIFY(library.load()); + QVERIFY(library.isLoaded()); + auto p = (VersionFunction)library.resolve("mylibversion"); + QVERIFY(p); + QCOMPARE(p(), 2); + library.unload(); +} + +void tst_QLibrary::setFileNameAndVersionAfterFailedLoad() +{ + QLibrary library(directory + "/nolib"); + QVERIFY(!library.load()); + QVERIFY(!library.isLoaded()); + QVERIFY(!library.load()); + QVERIFY(!library.isLoaded()); + +#if !defined(Q_OS_AIX) && !defined(Q_OS_WIN) + QFETCH(QString, lib); + QFETCH(int, loadversion); + QFETCH(int, resultversion); + + library.setFileNameAndVersion(directory + '/' + lib, loadversion); + QVERIFY(library.load()); + QVERIFY(library.isLoaded()); + auto p = (VersionFunction)library.resolve("mylibversion"); + QVERIFY(p); + QCOMPARE(p(), resultversion); + library.unload(); +#endif +} + +void tst_QLibrary::loadAfterFailedLoad() +{ +#if defined(Q_OS_WIN) || defined(Q_OS_ANDROID) + QSKIP("### FIXME: The helper libraries are currently messed up in the CMakeLists.txt"); +#endif + + QTemporaryDir dir; + QLibrary library(dir.path() + "/mylib"); + QVERIFY(!library.load()); + QVERIFY(!library.isLoaded()); + QVERIFY(!library.load()); + QVERIFY(!library.isLoaded()); + + // now copy the actual lib file into our dir + QString actualLib = PREFIX "mylib" SUFFIX; + QVERIFY(QFile::copy(directory + '/' + actualLib, dir.filePath(actualLib))); + + // try again, must succeed now + QVERIFY(library.load()); + QVERIFY(library.isLoaded()); + auto p = (VersionFunction)library.resolve("mylibversion"); + QVERIFY(p); + QCOMPARE(p(), 2); + library.unload(); +} + void tst_QLibrary::resolve_data() { QTest::addColumn<QString>("lib"); @@ -302,21 +432,27 @@ void tst_QLibrary::resolve() QFETCH( QString, symbol ); QFETCH( bool, goodPointer ); - QLibrary library( lib ); - testFunc func = (testFunc) library.resolve( symbol.toLatin1() ); - if ( goodPointer ) { - QVERIFY( func != 0 ); + QLibrary library(lib); + QVERIFY(!library.isLoaded()); + testFunc func = (testFunc) library.resolve(symbol.toLatin1()); + + if (goodPointer) { + QVERIFY(library.isLoaded()); + QVERIFY(func); + + QLibrary lib2(lib); + QVERIFY(!lib2.isLoaded()); + QVERIFY(lib2.load()); + + // this unload() won't unload and it must still be loaded + QVERIFY(!lib2.unload()); + func(); // doesn't crash } else { - QVERIFY( func == 0 ); + QVERIFY(func == nullptr); } library.unload(); } -void tst_QLibrary::library_data() -{ - QTest::addColumn<QString>("lib"); -} - void tst_QLibrary::isLibrary_data() { QTest::addColumn<QString>("filename"); @@ -337,7 +473,7 @@ void tst_QLibrary::isLibrary_data() QTest::newRow("version+.so+version") << QString("liboil-0.3.so.0.1.0") << so_VALID; // special tests: -#ifdef Q_OS_MAC +#ifdef Q_OS_DARWIN QTest::newRow("good (libmylib.1.0.0.dylib)") << QString("libmylib.1.0.0.dylib") << true; QTest::newRow("good (libmylib.dylib)") << QString("libmylib.dylib") << true; QTest::newRow("good (libmylib.so)") << QString("libmylib.so") << true; @@ -368,13 +504,13 @@ void tst_QLibrary::errorString_data() QTest::newRow("bad load()") << (int)Load << QString("nosuchlib") << false << QString("Cannot load library nosuchlib: .*"); QTest::newRow("call errorString() on QLibrary with no d-pointer (crashtest)") << (int)(Load | DontSetFileName) << QString() << false << QString("Unknown error"); - QTest::newRow("bad resolve") << (int)Resolve << appDir + "/mylib" << false << QString("Cannot resolve symbol \"nosuchsymbol\" in \\S+: .*"); + QTest::newRow("bad resolve") << (int)Resolve << appDir + "/mylib" << false << QString("Unknown error"); QTest::newRow("good resolve") << (int)Resolve << appDir + "/mylib" << true << QString("Unknown error"); #ifdef Q_OS_WIN QTest::newRow("bad load() with .dll suffix") << (int)Load << QString("nosuchlib.dll") << false << QString("Cannot load library nosuchlib.dll: The specified module could not be found."); // QTest::newRow("bad unload") << (int)Unload << QString("nosuchlib.dll") << false << QString("QLibrary::unload_sys: Cannot unload nosuchlib.dll (The specified module could not be found.)"); -#elif defined Q_OS_MAC +#elif defined Q_OS_DARWIN #else QTest::newRow("load invalid file") << (int)Load << QFINDTESTDATA("library_path/invalid.so") << false << QString("Cannot load library.*"); #endif @@ -414,10 +550,12 @@ void tst_QLibrary::errorString() QFAIL(qPrintable(QString("Unknown operation: %1").arg(operation))); break; } - QRegExp re(errorString); +#if QT_CONFIG(regularexpression) + QRegularExpression re(QRegularExpression::anchoredPattern(errorString)); QString libErrorString = lib.errorString(); + QVERIFY2(re.match(libErrorString).hasMatch(), qPrintable(libErrorString)); +#endif QVERIFY(!lib.isLoaded() || lib.unload()); - QVERIFY2(re.exactMatch(libErrorString), qPrintable(libErrorString)); QCOMPARE(ok, success); } @@ -432,13 +570,16 @@ void tst_QLibrary::loadHints_data() QString appDir = directory; lh |= QLibrary::ResolveAllSymbolsHint; -# if defined(Q_OS_WIN32) || defined(Q_OS_WINRT) +# if defined(Q_OS_WIN32) QTest::newRow( "ok01 (with suffix)" ) << appDir + "/mylib.dll" << int(lh) << true; QTest::newRow( "ok02 (with non-standard suffix)" ) << appDir + "/mylib.dl2" << int(lh) << true; QTest::newRow( "ok03 (with many dots)" ) << appDir + "/system.qt.test.mylib.dll" << int(lh) << true; # elif defined Q_OS_UNIX QTest::newRow( "ok01 (with suffix)" ) << appDir + "/libmylib" SUFFIX << int(lh) << true; +#ifndef Q_OS_ANDROID + // We do not support non-standard suffixes on Android QTest::newRow( "ok02 (with non-standard suffix)" ) << appDir + "/libmylib.so2" << int(lh) << true; +#endif QTest::newRow( "ok03 (with many dots)" ) << appDir + "/system.qt.test.mylib.so" << int(lh) << true; # endif // Q_OS_UNIX } @@ -484,7 +625,7 @@ void tst_QLibrary::fileName_data() QTest::newRow( "ok02" ) << sys_qualifiedLibraryName(QLatin1String("mylib")) << sys_qualifiedLibraryName(QLatin1String("mylib")); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) +#if defined(Q_OS_WIN) QTest::newRow( "ok03" ) << "user32" << "USER32.dll"; #endif @@ -517,7 +658,7 @@ void tst_QLibrary::multipleInstancesForOneLibrary() QCOMPARE(lib2.isLoaded(), false); lib1.load(); QCOMPARE(lib1.isLoaded(), true); - QCOMPARE(lib2.isLoaded(), true); + QCOMPARE(lib2.isLoaded(), false); // lib2 didn't call load() QCOMPARE(lib1.unload(), true); QCOMPARE(lib1.isLoaded(), false); QCOMPARE(lib2.isLoaded(), false); @@ -526,7 +667,7 @@ void tst_QLibrary::multipleInstancesForOneLibrary() QCOMPARE(lib1.isLoaded(), true); QCOMPARE(lib2.isLoaded(), true); QCOMPARE(lib1.unload(), false); - QCOMPARE(lib1.isLoaded(), true); + QCOMPARE(lib1.isLoaded(), false); // lib1 did call unload() QCOMPARE(lib2.isLoaded(), true); QCOMPARE(lib2.unload(), true); QCOMPARE(lib1.isLoaded(), false); @@ -535,17 +676,6 @@ void tst_QLibrary::multipleInstancesForOneLibrary() // Finally; unload on that is already unloaded QCOMPARE(lib1.unload(), false); } - - //now let's try with a 3rd one that will go out of scope - { - QLibrary lib1(lib); - QCOMPARE(lib1.isLoaded(), false); - lib1.load(); - QCOMPARE(lib1.isLoaded(), true); - } - QLibrary lib2(lib); - //lib2 should be loaded because lib1 was loaded and never unloaded - QCOMPARE(lib2.isLoaded(), true); } QTEST_MAIN(tst_QLibrary) diff --git a/tests/auto/corelib/plugin/qplugin/CMakeLists.txt b/tests/auto/corelib/plugin/qplugin/CMakeLists.txt new file mode 100644 index 0000000000..d0e8736e09 --- /dev/null +++ b/tests/auto/corelib/plugin/qplugin/CMakeLists.txt @@ -0,0 +1,48 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qplugin LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +add_subdirectory(invalidplugin) +add_subdirectory(debugplugin) +add_subdirectory(releaseplugin) + +qt_internal_add_test(tst_qplugin + SOURCES + tst_qplugin.cpp + LIBRARIES + Qt::CorePrivate +) + +if(NOT ANDROID) + # Collect test data + file(GLOB_RECURSE test_data_glob + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + plugins/*) + list(APPEND test_data ${test_data_glob}) + set_target_properties(tst_qplugin PROPERTIES TESTDATA "${test_data}") +else() + # On Android the plugins must be located in the libs subdir of the APK. + # Use QT_ANDROID_EXTRA_LIBS to achieve that. + set(plugins + invalidplugin + debugplugin + releaseplugin + ) + set(extra_libs) + foreach(plugin IN LISTS plugins) + list(APPEND extra_libs + "${CMAKE_CURRENT_BINARY_DIR}/plugins/lib${plugin}_${CMAKE_ANDROID_ARCH_ABI}.so") + endforeach() + set_target_properties(tst_qplugin PROPERTIES + QT_ANDROID_EXTRA_LIBS "${extra_libs}" + ) +endif() + +target_compile_definitions(tst_qplugin PRIVATE CMAKE_BUILD=1) + +add_dependencies(tst_qplugin invalidplugin debugplugin releaseplugin) diff --git a/tests/auto/corelib/plugin/qplugin/debugplugin/CMakeLists.txt b/tests/auto/corelib/plugin/qplugin/debugplugin/CMakeLists.txt new file mode 100644 index 0000000000..230282f175 --- /dev/null +++ b/tests/auto/corelib/plugin/qplugin/debugplugin/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## debugplugin Generic Library: +##################################################################### + +qt_internal_add_cmake_library(debugplugin + MODULE + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../plugins" + SOURCES + main.cpp + LIBRARIES + Qt::Core +) + +qt_autogen_tools_initial_setup(debugplugin) diff --git a/tests/auto/corelib/plugin/qplugin/debugplugin/debugplugin.pro b/tests/auto/corelib/plugin/qplugin/debugplugin/debugplugin.pro deleted file mode 100644 index ca47df22bd..0000000000 --- a/tests/auto/corelib/plugin/qplugin/debugplugin/debugplugin.pro +++ /dev/null @@ -1,6 +0,0 @@ -TEMPLATE = lib -CONFIG += plugin debug -CONFIG -= release debug_and_release -SOURCES = main.cpp -QT = core -DESTDIR = ../plugins diff --git a/tests/auto/corelib/plugin/qplugin/debugplugin/main.cpp b/tests/auto/corelib/plugin/qplugin/debugplugin/main.cpp index c610bfdc46..fe25c44d87 100644 --- a/tests/auto/corelib/plugin/qplugin/debugplugin/main.cpp +++ b/tests/auto/corelib/plugin/qplugin/debugplugin/main.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtPlugin> #include <QObject> diff --git a/tests/auto/corelib/plugin/qplugin/invalidplugin/CMakeLists.txt b/tests/auto/corelib/plugin/qplugin/invalidplugin/CMakeLists.txt new file mode 100644 index 0000000000..0b12e9c0f0 --- /dev/null +++ b/tests/auto/corelib/plugin/qplugin/invalidplugin/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## invalidplugin Generic Library: +##################################################################### + +qt_internal_add_cmake_library(invalidplugin + MODULE + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../plugins" + SOURCES + main.cpp + LIBRARIES + Qt::Core +) + +# TEMPLATE = "lib" + +qt_autogen_tools_initial_setup(invalidplugin) diff --git a/tests/auto/corelib/plugin/qplugin/invalidplugin/invalidplugin.pro b/tests/auto/corelib/plugin/qplugin/invalidplugin/invalidplugin.pro deleted file mode 100644 index d953c6d367..0000000000 --- a/tests/auto/corelib/plugin/qplugin/invalidplugin/invalidplugin.pro +++ /dev/null @@ -1,5 +0,0 @@ -QT = core -TEMPLATE = lib -CONFIG += plugin -SOURCES = main.cpp -DESTDIR = ../plugins diff --git a/tests/auto/corelib/plugin/qplugin/invalidplugin/main.cpp b/tests/auto/corelib/plugin/qplugin/invalidplugin/main.cpp index e6603ec89f..10b6131857 100644 --- a/tests/auto/corelib/plugin/qplugin/invalidplugin/main.cpp +++ b/tests/auto/corelib/plugin/qplugin/invalidplugin/main.cpp @@ -1,33 +1,9 @@ -/**************************************************************************** -** -** Copyright (C) 2018 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2018 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qplugin.h> +// be careful when updating to V2, the header is different on ELF systems QT_PLUGIN_METADATA_SECTION static const char pluginMetaData[512] = { 'q', 'p', 'l', 'u', 'g', 'i', 'n', ' ', diff --git a/tests/auto/corelib/plugin/qplugin/qplugin.pro b/tests/auto/corelib/plugin/qplugin/qplugin.pro deleted file mode 100644 index 96fc704c07..0000000000 --- a/tests/auto/corelib/plugin/qplugin/qplugin.pro +++ /dev/null @@ -1,17 +0,0 @@ -TEMPLATE = subdirs -TESTPLUGINS = invalidplugin - -win32 { - contains(QT_CONFIG, debug): TESTPLUGINS += debugplugin - contains(QT_CONFIG, release): TESTPLUGINS += releaseplugin -} else:osx { - CONFIG(debug, debug|release): TESTPLUGINS += debugplugin - CONFIG(release, debug|release): TESTPLUGINS += releaseplugin -} else { - TESTPLUGINS += debugplugin releaseplugin -} - -SUBDIRS += main $$TESTPLUGINS -main.file = tst_qplugin.pro -main.depends = $$TESTPLUGINS - diff --git a/tests/auto/corelib/plugin/qplugin/releaseplugin/CMakeLists.txt b/tests/auto/corelib/plugin/qplugin/releaseplugin/CMakeLists.txt new file mode 100644 index 0000000000..3ec89eb4c6 --- /dev/null +++ b/tests/auto/corelib/plugin/qplugin/releaseplugin/CMakeLists.txt @@ -0,0 +1,17 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## releaseplugin Generic Library: +##################################################################### + +qt_internal_add_cmake_library(releaseplugin + MODULE + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../plugins" + SOURCES + main.cpp + LIBRARIES + Qt::Core +) + +qt_autogen_tools_initial_setup(releaseplugin) diff --git a/tests/auto/corelib/plugin/qplugin/releaseplugin/main.cpp b/tests/auto/corelib/plugin/qplugin/releaseplugin/main.cpp index dd936f7da1..ee14da8384 100644 --- a/tests/auto/corelib/plugin/qplugin/releaseplugin/main.cpp +++ b/tests/auto/corelib/plugin/qplugin/releaseplugin/main.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtPlugin> #include <QObject> diff --git a/tests/auto/corelib/plugin/qplugin/releaseplugin/releaseplugin.pro b/tests/auto/corelib/plugin/qplugin/releaseplugin/releaseplugin.pro deleted file mode 100644 index b7dea67894..0000000000 --- a/tests/auto/corelib/plugin/qplugin/releaseplugin/releaseplugin.pro +++ /dev/null @@ -1,6 +0,0 @@ -TEMPLATE = lib -CONFIG += plugin release -CONFIG -= debug debug_and_release -SOURCES = main.cpp -QT = core -DESTDIR = ../plugins diff --git a/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp b/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp index a290c012df..3d3cb8330d 100644 --- a/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp +++ b/tests/auto/corelib/plugin/qplugin/tst_qplugin.cpp @@ -1,32 +1,7 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2018 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ -#include <QtTest/QtTest> +// Copyright (C) 2020 The Qt Company Ltd. +// Copyright (C) 2021 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#include <QTest> #include <QCoreApplication> #include <QDebug> @@ -41,7 +16,6 @@ class tst_QPlugin : public QObject Q_OBJECT QDir dir; - QString invalidPluginName; public: tst_QPlugin(); @@ -55,8 +29,15 @@ private slots: }; tst_QPlugin::tst_QPlugin() - : dir(QFINDTESTDATA("plugins")) { + // On Android the plugins must be located in the APK's libs subdir +#ifndef Q_OS_ANDROID + dir = QFINDTESTDATA("plugins"); +#else + const QStringList paths = QCoreApplication::libraryPaths(); + if (!paths.isEmpty()) + dir = paths.first(); +#endif } void tst_QPlugin::initTestCase() @@ -64,25 +45,27 @@ void tst_QPlugin::initTestCase() QVERIFY2(dir.exists(), qPrintable(QString::fromLatin1("Cannot find the 'plugins' directory starting from '%1'"). arg(QDir::toNativeSeparators(QDir::currentPath())))); - - const auto fileNames = dir.entryList({"*invalid*"}, QDir::Files); - if (!fileNames.isEmpty()) - invalidPluginName = dir.absoluteFilePath(fileNames.first()); } void tst_QPlugin::loadDebugPlugin() { const auto fileNames = dir.entryList(QStringList() << "*debug*", QDir::Files); + if (fileNames.isEmpty()) + QSKIP("No debug plugins found - skipping test"); + for (const QString &fileName : fileNames) { if (!QLibrary::isLibrary(fileName)) continue; QPluginLoader loader(dir.filePath(fileName)); -#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) +#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) // we can always load a plugin on unix QVERIFY(loader.load()); QObject *object = loader.instance(); QVERIFY(object != 0); #else +# if defined(CMAKE_BUILD) && defined(QT_NO_DEBUG) + QSKIP("Skipping test as it is not possible to disable build targets based on configuration with CMake"); +# endif // loading a plugin is dependent on which lib we are running against # if defined(QT_NO_DEBUG) // release build, we cannot load debug plugins @@ -100,16 +83,22 @@ void tst_QPlugin::loadDebugPlugin() void tst_QPlugin::loadReleasePlugin() { const auto fileNames = dir.entryList(QStringList() << "*release*", QDir::Files); + if (fileNames.isEmpty()) + QSKIP("No release plugins found - skipping test"); + for (const QString &fileName : fileNames) { if (!QLibrary::isLibrary(fileName)) continue; QPluginLoader loader(dir.filePath(fileName)); -#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) +#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) // we can always load a plugin on unix QVERIFY(loader.load()); QObject *object = loader.instance(); QVERIFY(object != 0); #else +# if defined(CMAKE_BUILD) && !defined(QT_NO_DEBUG) + QSKIP("Skipping test as it is not possible to disable build targets based on configuration with CMake"); +# endif // loading a plugin is dependent on which lib we are running against # if defined(QT_NO_DEBUG) // release build, we can load debug plugins @@ -130,49 +119,10 @@ void tst_QPlugin::scanInvalidPlugin_data() QTest::addColumn<bool>("loads"); QTest::addColumn<QString>("errMsg"); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - // Binary JSON metadata - QByteArray prefix = "QTMETADATA "; - - { - QJsonObject obj; - obj.insert("IID", "org.qt-project.tst_qplugin"); - obj.insert("className", "tst"); - obj.insert("version", int(QT_VERSION)); -#ifdef QT_NO_DEBUG - obj.insert("debug", false); -#else - obj.insert("debug", true); -#endif - obj.insert("MetaData", QJsonObject()); - QTest::newRow("json-control") << (prefix + QJsonDocument(obj).toBinaryData()) << true << ""; - } - - QTest::newRow("json-zeroes") << prefix << false << " "; - - prefix += "qbjs"; - QTest::newRow("bad-json-version0") << prefix << false << " "; - QTest::newRow("bad-json-version2") << (prefix + QByteArray("\2\0\0\0", 4)) << false << " "; - - // valid qbjs version 1 - prefix += QByteArray("\1\0\0\0"); - - // too large for the file (100 MB) - QTest::newRow("bad-json-size-large1") << (prefix + QByteArray("\0\0\x40\x06")) << false << " "; - - // too large for binary JSON (512 MB) - QTest::newRow("bad-json-size-large2") << (prefix + QByteArray("\0\0\0\x20")) << false << " "; - - // could overflow - QTest::newRow("bad-json-size-large3") << (prefix + "\xff\xff\xff\x7f") << false << " "; -#endif - // CBOR metadata - QByteArray cprefix = "QTMETADATA !1234"; - cprefix[12] = 0; // current version - cprefix[13] = QT_VERSION_MAJOR; - cprefix[14] = QT_VERSION_MINOR; - cprefix[15] = qPluginArchRequirements(); + static constexpr QPluginMetaData::MagicHeader header = {}; + static constexpr qsizetype MagicLen = sizeof(header.magic); + QByteArray cprefix(reinterpret_cast<const char *>(&header), sizeof(header)); QByteArray cborValid = [] { QCborMap m; @@ -183,27 +133,27 @@ void tst_QPlugin::scanInvalidPlugin_data() }(); QTest::newRow("cbor-control") << (cprefix + cborValid) << true << ""; - cprefix[12] = 1; - QTest::newRow("cbor-major-too-new") << (cprefix + cborValid) << false - << " Invalid metadata version"; - - cprefix[12] = 0; - cprefix[13] = QT_VERSION_MAJOR + 1; + cprefix[MagicLen + 1] = QT_VERSION_MAJOR + 1; QTest::newRow("cbor-major-too-new") << (cprefix + cborValid) << false << ""; - cprefix[13] = QT_VERSION_MAJOR - 1; + cprefix[MagicLen + 1] = QT_VERSION_MAJOR - 1; QTest::newRow("cbor-major-too-old") << (cprefix + cborValid) << false << ""; - cprefix[13] = QT_VERSION_MAJOR; - cprefix[14] = QT_VERSION_MINOR + 1; + cprefix[MagicLen + 1] = QT_VERSION_MAJOR; + cprefix[MagicLen + 2] = QT_VERSION_MINOR + 1; QTest::newRow("cbor-minor-too-new") << (cprefix + cborValid) << false << ""; + cprefix[MagicLen + 2] = QT_VERSION_MINOR; QTest::newRow("cbor-invalid") << (cprefix + "\xff") << false << " Metadata parsing error: Invalid CBOR stream: unexpected 'break' byte"; QTest::newRow("cbor-not-map1") << (cprefix + "\x01") << false << " Unexpected metadata contents"; QTest::newRow("cbor-not-map2") << (cprefix + "\x81\x01") << false << " Unexpected metadata contents"; + + ++cprefix[MagicLen + 0]; + QTest::newRow("cbor-major-too-new-invalid") + << (cprefix + cborValid) << false << " Invalid metadata version"; } static const char invalidPluginSignature[] = "qplugin testfile"; @@ -227,7 +177,16 @@ static qsizetype locateMetadata(const uchar *data, qsizetype len) void tst_QPlugin::scanInvalidPlugin() { - QVERIFY(!invalidPluginName.isEmpty()); +#if defined(Q_OS_MACOS) && defined(Q_PROCESSOR_ARM) + QSKIP("This test crashes on ARM macOS"); +#endif + const auto fileNames = dir.entryList({"*invalid*"}, QDir::Files); + QString invalidPluginName; + if (fileNames.isEmpty()) + QSKIP("No invalid plugin found - skipping test"); + else + invalidPluginName = dir.absoluteFilePath(fileNames.first()); + // copy the file QFileInfo fn(invalidPluginName); @@ -257,13 +216,14 @@ void tst_QPlugin::scanInvalidPlugin() memset(data + offset + metadata.size(), 0, 512 - metadata.size()); } +#if defined(Q_OS_QNX) + // On QNX plugin access is still too early + QTest::qSleep(1000); +#endif + // now try to load this QFETCH(bool, loads); QFETCH(QString, errMsg); - if (!errMsg.isEmpty()) - QTest::ignoreMessage(QtWarningMsg, - "Found invalid metadata in lib " + QFile::encodeName(newName) + - ":" + errMsg.toUtf8()); QPluginLoader loader(newName); QCOMPARE(loader.load(), loads); if (loads) diff --git a/tests/auto/corelib/plugin/qplugin/tst_qplugin.pro b/tests/auto/corelib/plugin/qplugin/tst_qplugin.pro deleted file mode 100644 index 4432ee20c1..0000000000 --- a/tests/auto/corelib/plugin/qplugin/tst_qplugin.pro +++ /dev/null @@ -1,6 +0,0 @@ -CONFIG += testcase -TARGET = tst_qplugin -QT = core-private testlib -SOURCES = tst_qplugin.cpp - -TESTDATA += plugins/* diff --git a/tests/auto/corelib/plugin/qpluginloader/CMakeLists.txt b/tests/auto/corelib/plugin/qpluginloader/CMakeLists.txt new file mode 100644 index 0000000000..592b8632fa --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/CMakeLists.txt @@ -0,0 +1,19 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qpluginloader LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +add_subdirectory(lib) +add_subdirectory(staticplugin) +add_subdirectory(theplugin) +add_subdirectory(tst) +if(UNIX AND NOT ANDROID AND NOT APPLE) + add_subdirectory(almostplugin) +endif() +if(MACOS AND QT_FEATURE_private_tests AND TARGET Qt::Gui) + add_subdirectory(machtest) +endif() diff --git a/tests/auto/corelib/plugin/qpluginloader/almostplugin/CMakeLists.txt b/tests/auto/corelib/plugin/qpluginloader/almostplugin/CMakeLists.txt new file mode 100644 index 0000000000..15ae79dfb1 --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/almostplugin/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## almostplugin Generic Library: +##################################################################### + +qt_internal_add_cmake_library(almostplugin + MODULE + INSTALL_DIRECTORY "${INSTALL_TESTSDIR}/tst_qpluginloader/bin" + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../bin" + SOURCES + almostplugin.cpp almostplugin.h + LIBRARIES + Qt::Core +) + +qt_autogen_tools_initial_setup(almostplugin) diff --git a/tests/auto/corelib/plugin/qpluginloader/almostplugin/almostplugin.cpp b/tests/auto/corelib/plugin/qpluginloader/almostplugin/almostplugin.cpp index 75806dd285..29b6df2683 100644 --- a/tests/auto/corelib/plugin/qpluginloader/almostplugin/almostplugin.cpp +++ b/tests/auto/corelib/plugin/qpluginloader/almostplugin/almostplugin.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtCore/QString> #include "almostplugin.h" #include <QtCore/qplugin.h> diff --git a/tests/auto/corelib/plugin/qpluginloader/almostplugin/almostplugin.h b/tests/auto/corelib/plugin/qpluginloader/almostplugin/almostplugin.h index 6071d0c4d7..dea26875c2 100644 --- a/tests/auto/corelib/plugin/qpluginloader/almostplugin/almostplugin.h +++ b/tests/auto/corelib/plugin/qpluginloader/almostplugin/almostplugin.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef ALMOSTPLUGIN_H #define ALMOSTPLUGIN_H @@ -39,7 +14,7 @@ class AlmostPlugin : public QObject, public PluginInterface Q_INTERFACES(PluginInterface) public: - QString pluginName() const; + QString pluginName() const override; void unresolvedSymbol() const; }; diff --git a/tests/auto/corelib/plugin/qpluginloader/almostplugin/almostplugin.pro b/tests/auto/corelib/plugin/qpluginloader/almostplugin/almostplugin.pro deleted file mode 100644 index abfc70883e..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/almostplugin/almostplugin.pro +++ /dev/null @@ -1,12 +0,0 @@ -TEMPLATE = lib -CONFIG += plugin -HEADERS = almostplugin.h -SOURCES = almostplugin.cpp -TARGET = almostplugin -DESTDIR = ../bin -QT = core -*-g++*:QMAKE_LFLAGS -= -Wl,--no-undefined - -# This is testdata for the tst_qpluginloader test. -target.path = $$[QT_INSTALL_TESTS]/tst_qpluginloader/bin -INSTALLS += target diff --git a/tests/auto/corelib/plugin/qpluginloader/elftest/corrupt1.elf64.so b/tests/auto/corelib/plugin/qpluginloader/elftest/corrupt1.elf64.so Binary files differdeleted file mode 100644 index 12ce7362dc..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/elftest/corrupt1.elf64.so +++ /dev/null diff --git a/tests/auto/corelib/plugin/qpluginloader/elftest/corrupt2.elf64.so b/tests/auto/corelib/plugin/qpluginloader/elftest/corrupt2.elf64.so Binary files differdeleted file mode 100644 index 11fdc2c118..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/elftest/corrupt2.elf64.so +++ /dev/null diff --git a/tests/auto/corelib/plugin/qpluginloader/elftest/corrupt3.elf64.so b/tests/auto/corelib/plugin/qpluginloader/elftest/corrupt3.elf64.so Binary files differdeleted file mode 100644 index 94a2bc3560..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/elftest/corrupt3.elf64.so +++ /dev/null diff --git a/tests/auto/corelib/plugin/qpluginloader/elftest/garbage1.so b/tests/auto/corelib/plugin/qpluginloader/elftest/garbage1.so deleted file mode 100644 index 0c7453077f..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/elftest/garbage1.so +++ /dev/null @@ -1,4 +0,0 @@ -p¶¤Ðã¨ø±ÕÛcdL+ôúæî&‘¿&÷ýeü¥=კ² -•o°Ã’ÊŽI›§ÙÏmgƒ]!ÀZ -L'Ž)t± -ÙN»¸(e©×P)Y8öG ˆ6ß-yÈÏÀñŸ§÷—“"ô–ZÖÿ›kõ4â?Ë^náÁÇß5$ž’ôY=£ð#y
\ No newline at end of file diff --git a/tests/auto/corelib/plugin/qpluginloader/elftest/garbage2.so b/tests/auto/corelib/plugin/qpluginloader/elftest/garbage2.so deleted file mode 100644 index c06338e0c8..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/elftest/garbage2.so +++ /dev/null @@ -1 +0,0 @@ -£Çv.³Y‹¨tKëW3
\ No newline at end of file diff --git a/tests/auto/corelib/plugin/qpluginloader/elftest/garbage3.so b/tests/auto/corelib/plugin/qpluginloader/elftest/garbage3.so deleted file mode 100644 index a24c523a77..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/elftest/garbage3.so +++ /dev/null @@ -1 +0,0 @@ -£ÝÈÈ‚åžT-õ«´ÊôÚ¥ Àä¸ï¨ì¾œÀi8¼_ñxÓõª¾I±Ð×®ÝxÎ=úØ4@þñ[¨—úBàKS$ú
\ No newline at end of file diff --git a/tests/auto/corelib/plugin/qpluginloader/elftest/garbage4.so b/tests/auto/corelib/plugin/qpluginloader/elftest/garbage4.so deleted file mode 100644 index 4f45cf5157..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/elftest/garbage4.so +++ /dev/null @@ -1 +0,0 @@ -¶!¦\~çUu³†:9©ˆ œ§T+91ˆQ¬EøåÇšx¨ng5Óã—zhŒ–…ÿÆ^t™ŠµŽ¦'ÆÎmm*ˈdXH;vw+ªG“²ÃàØ
¨9Lƒ0!
\ No newline at end of file diff --git a/tests/auto/corelib/plugin/qpluginloader/elftest/garbage5.so b/tests/auto/corelib/plugin/qpluginloader/elftest/garbage5.so deleted file mode 100644 index f8c0a1d544..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/elftest/garbage5.so +++ /dev/null @@ -1,2 +0,0 @@ -ïÌô’Q² -ãµ-¢9Ò
\ No newline at end of file diff --git a/tests/auto/corelib/plugin/qpluginloader/fakeplugin.cpp b/tests/auto/corelib/plugin/qpluginloader/fakeplugin.cpp index 9e7a1f750b..e84bfa6dbc 100644 --- a/tests/auto/corelib/plugin/qpluginloader/fakeplugin.cpp +++ b/tests/auto/corelib/plugin/qpluginloader/fakeplugin.cpp @@ -1,36 +1,57 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtCore module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2021 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#ifndef QT_VERSION_MAJOR +# include <QtCore/qglobal.h> +#endif -#include <QtCore/qplugin.h> +extern "C" void *qt_plugin_instance() +{ + return nullptr; +} -#if QT_POINTER_SIZE == 8 -QT_PLUGIN_METADATA_SECTION void *const pluginSection = (void*)(0xc0ffeec0ffeeL); +#ifdef QT_DEBUG +static constexpr bool IsDebug = true; #else -QT_PLUGIN_METADATA_SECTION void *const pluginSection = (void*)0xc0ffee; +static constexpr bool IsDebug = false; +#endif + +#ifndef PLUGIN_VERSION +# define PLUGIN_VERSION (QT_VERSION_MAJOR >= 7 ? 1 : 0) +#endif +#if PLUGIN_VERSION == 1 +# define PLUGIN_HEADER 1, QT_VERSION_MAJOR, 0, IsDebug ? 0x80 : 0 +#else +# define PLUGIN_HEADER 0, QT_VERSION_MAJOR, 0, IsDebug +#endif + +#if defined(__ELF__) && PLUGIN_VERSION >= 1 +// GCC will produce: +// fakeplugin.cpp:64:3: warning: ‘no_sanitize’ attribute ignored [-Wattributes] +__attribute__((section(".note.qt.metadata"), used, no_sanitize("address"), aligned(sizeof(void*)))) +static const struct { + unsigned n_namesz = sizeof(name); + unsigned n_descsz = sizeof(payload); + unsigned n_type = 0x74510001; + char name[12] = "qt-project!"; + alignas(unsigned) unsigned char payload[2 + 4] = { + PLUGIN_HEADER, + 0xbf, + 0xff, + }; +} qtnotemetadata; +#elif PLUGIN_VERSION >= 0 +# ifdef _MSC_VER +# pragma section(".qtmetadata",read,shared) +__declspec(allocate(".qtmetadata")) +# elif defined(__APPLE__) +__attribute__ ((section ("__TEXT,qtmetadata"), used)) +# else +__attribute__ ((section(".qtmetadata"), used)) +# endif +static const unsigned char qtmetadata[] = { + 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!', + PLUGIN_HEADER, + 0xbf, + 0xff, +}; #endif -QT_PLUGIN_METADATA_SECTION const char message[] = "QTMETADATA"; diff --git a/tests/auto/corelib/plugin/qpluginloader/lib/CMakeLists.txt b/tests/auto/corelib/plugin/qpluginloader/lib/CMakeLists.txt new file mode 100644 index 0000000000..283bdb1352 --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/lib/CMakeLists.txt @@ -0,0 +1,34 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## tst_qpluginloaderlib Generic Library: +##################################################################### + +qt_internal_add_cmake_library(tst_qpluginloaderlib + SHARED + INSTALL_DIRECTORY "${INSTALL_TESTSDIR}/tst_qpluginloader/bin" + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../bin" + SOURCES + mylib.c + LIBRARIES + Qt::Core +) + +if(WIN32) + # CMake sets for Windows-GNU platforms the suffix "lib" + set_property(TARGET tst_qpluginloaderlib PROPERTY PREFIX "") +endif() + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_qpluginloaderlib CONDITION MSVC + DEFINES + WIN32_MSVC +) + +set_target_properties(tst_qpluginloaderlib PROPERTIES + C_VISIBILITY_PRESET "default" + CXX_VISIBILITY_PRESET "default" +) diff --git a/tests/auto/corelib/plugin/qpluginloader/lib/lib.pro b/tests/auto/corelib/plugin/qpluginloader/lib/lib.pro deleted file mode 100644 index 9fc76a4201..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/lib/lib.pro +++ /dev/null @@ -1,14 +0,0 @@ -TEMPLATE = lib -CONFIG += dll -CONFIG -= staticlib -SOURCES = mylib.c -TARGET = tst_qpluginloaderlib -DESTDIR = ../bin -winrt:include(../winrt.pri) -QT = core - -msvc: DEFINES += WIN32_MSVC - -# This is testdata for the tst_qpluginloader test. -target.path = $$[QT_INSTALL_TESTS]/tst_qpluginloader/bin -INSTALLS += target diff --git a/tests/auto/corelib/plugin/qpluginloader/lib/mylib.c b/tests/auto/corelib/plugin/qpluginloader/lib/mylib.c index 8d23b999c4..3f1fe03114 100644 --- a/tests/auto/corelib/plugin/qpluginloader/lib/mylib.c +++ b/tests/auto/corelib/plugin/qpluginloader/lib/mylib.c @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the documentation of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <qglobal.h> diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/CMakeLists.txt b/tests/auto/corelib/plugin/qpluginloader/machtest/CMakeLists.txt new file mode 100644 index 0000000000..daf922b42c --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/machtest/CMakeLists.txt @@ -0,0 +1,140 @@ +# Copyright (C) 2024 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause +set_directory_properties(PROPERTIES + _qt_good_targets "" + _qt_stub_targets "" +) + +function(add_plugin_binary) + set(no_value_options "") + set(single_value_options NAME ARCH OUT_TARGET) + set(multi_value_options SOURCES) + cmake_parse_arguments(PARSE_ARGV 0 arg + "${no_value_options}" "${single_value_options}" "${multi_value_options}" + ) + + set(output_name ${arg_NAME}.${arg_ARCH}) + set(target tst_qpluginloader.${output_name}) + set(${arg_OUT_TARGET} ${target} PARENT_SCOPE) + set_property(DIRECTORY APPEND PROPERTY _qt_${arg_NAME}_targets ${target}) + add_library(${target} MODULE ${arg_SOURCES}) + add_dependencies(tst_qpluginloader ${target}) + set_target_properties(${target} PROPERTIES + OUTPUT_NAME ${output_name} + PREFIX "" + SUFFIX ".dylib" + DEBUG_POSTFIX "" + OSX_ARCHITECTURES ${arg_ARCH} + ) +endfunction() + +function(add_good_binary) + set(no_value_options "") + set(single_value_options ARCH) + set(multi_value_options "") + cmake_parse_arguments(PARSE_ARGV 0 arg + "${no_value_options}" "${single_value_options}" "${multi_value_options}" + ) + + add_plugin_binary( + NAME good + ARCH ${arg_ARCH} + SOURCES ../fakeplugin.cpp + OUT_TARGET target + ) + + # We cannot link against Qt6::Core, because the architecture might not match. + # Extract the include directories from Qt6::Core. + get_target_property(incdirs Qt6::Core INTERFACE_INCLUDE_DIRECTORIES) + target_include_directories(${target} PRIVATE ${incdirs}) + + # Extract the compile definitions from Qt6::Core and disable version tagging. + get_target_property(compdefs Qt6::Core INTERFACE_COMPILE_DEFINITIONS) + target_compile_definitions(${target} PRIVATE + ${compdefs} + QT_NO_VERSION_TAGGING + ) +endfunction() + +function(add_stub_binary) + set(no_value_options "") + set(single_value_options ARCH) + set(multi_value_options "") + cmake_parse_arguments(PARSE_ARGV 0 arg + "${no_value_options}" "${single_value_options}" "${multi_value_options}" + ) + + add_plugin_binary( + NAME stub + ARCH ${arg_ARCH} + SOURCES stub.cpp + ) +endfunction() + +function(add_fat_binary) + set(no_value_options "") + set(single_value_options NAME OUT_TARGET) + set(multi_value_options TARGETS) + cmake_parse_arguments(PARSE_ARGV 0 arg + "${no_value_options}" "${single_value_options}" "${multi_value_options}" + ) + + set(arch_args "") + foreach(dependency IN LISTS arg_TARGETS) + get_target_property(arch ${dependency} OSX_ARCHITECTURES) + list(APPEND arch_args -arch ${arch} $<TARGET_FILE_NAME:${dependency}>) + endforeach() + + set(output_name good.fat.${arg_NAME}) + set(output_file ${output_name}.dylib) + set(target tst_qpluginloader.${output_name}) + set(${arg_OUT_TARGET} ${target} PARENT_SCOPE) + add_custom_command( + OUTPUT ${output_file} + COMMAND lipo -create -output ${output_file} ${arch_args} + DEPENDS ${arg_TARGETS} + ) + add_custom_target(${target} + DEPENDS ${output_file} + ) + add_dependencies(tst_qpluginloader ${target}) +endfunction() + +set(archs_to_test arm64 x86_64) +foreach(arch IN LISTS archs_to_test) + add_good_binary(ARCH ${arch}) + add_stub_binary(ARCH ${arch}) +endforeach() + +get_directory_property(good_targets _qt_good_targets) +add_fat_binary(NAME all TARGETS ${good_targets}) + +set(targets ${good_targets}) +list(FILTER targets EXCLUDE REGEX "\\.arm64$") +add_fat_binary(NAME no-arm64 TARGETS ${targets}) + +set(targets ${good_targets}) +list(FILTER targets EXCLUDE REGEX "\\.x86_64$") +add_fat_binary(NAME no-x86_64 TARGETS ${targets}) + +get_directory_property(stub_targets _qt_stub_targets) +set(targets ${stub_targets}) +list(FILTER targets INCLUDE REGEX "\\.arm64$") +add_fat_binary(NAME stub-arm64 TARGETS ${targets}) + +set(targets ${stub_targets}) +list(FILTER targets INCLUDE REGEX "\\.x86_64$") +add_fat_binary(NAME stub-x86_64 TARGETS ${targets}) + +set(bad_binary_names "") +foreach(i RANGE 1 13) + list(APPEND bad_binary_names "bad${i}.dylib") +endforeach() +add_custom_command( + OUTPUT ${bad_binary_names} + COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/generate-bad.pl +) +add_custom_target(tst_qpluginloader_generate_bad_binaries + DEPENDS ${bad_binary_names} +) +add_dependencies(tst_qpluginloader tst_qpluginloader_generate_bad_binaries) diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/generate-bad.pl b/tests/auto/corelib/plugin/qpluginloader/machtest/generate-bad.pl index 4fed135049..3de1eb581a 100755 --- a/tests/auto/corelib/plugin/qpluginloader/machtest/generate-bad.pl +++ b/tests/auto/corelib/plugin/qpluginloader/machtest/generate-bad.pl @@ -1,31 +1,6 @@ #!/usr/bin/perl -############################################################################# -## -## Copyright (C) 2016 Intel Corporation. -## Contact: https://www.qt.io/licensing/ -## -## This file is the build configuration utility of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# +# Copyright (C) 2016 Intel Corporation. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 use strict; use constant FAT_MAGIC => 0xcafebabe; diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest.pri b/tests/auto/corelib/plugin/qpluginloader/machtest/machtest.pri deleted file mode 100644 index ca4a0a07e9..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest.pri +++ /dev/null @@ -1,13 +0,0 @@ -TEMPLATE = aux - -# Needs explicit load()ing due to aux template. Relies on QT being non-empty. -load(qt) - -goodlib.target = good.$${QMAKE_APPLE_DEVICE_ARCHS}.dylib -goodlib.commands = $(CXX) $(CXXFLAGS) -shared -o $@ -I$(INCPATH) $< -goodlib.depends += $$PWD/../fakeplugin.cpp - -all.depends += goodlib - -QMAKE_EXTRA_TARGETS += goodlib all -QMAKE_CLEAN += $$goodlib.target diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest.pro b/tests/auto/corelib/plugin/qpluginloader/machtest/machtest.pro deleted file mode 100644 index 795dd89895..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest.pro +++ /dev/null @@ -1,15 +0,0 @@ -TEMPLATE = subdirs - -SUBDIRS = \ - machtest_i386.pro \ - machtest_x86_64.pro \ - machtest_ppc64.pro \ - machtest_fat.pro - -machtest_fat-pro.depends = \ - machtest_i386.pro \ - machtest_x86_64.pro \ - machtest_ppc64.pro - -machtest_ppc64-pro.depends = \ - machtest_x86_64.pro diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest_fat.pro b/tests/auto/corelib/plugin/qpluginloader/machtest/machtest_fat.pro deleted file mode 100644 index 8daa343e2b..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest_fat.pro +++ /dev/null @@ -1,41 +0,0 @@ -TEMPLATE = aux -OTHER_FILES += generate-bad.pl - -# Needs explicit load()ing due to aux template. Relies on QT being non-empty. -load(qt) - -# Generate a fat binary with three architectures -fat_all.target = good.fat.all.dylib -fat_all.commands = lipo -create -output $@ \ - -arch ppc64 good.ppc64.dylib \ - -arch i386 good.i386.dylib \ - -arch x86_64 good.x86_64.dylib -fat_all.depends += good.i386.dylib good.x86_64.dylib good.ppc64.dylib - -fat_no_i386.target = good.fat.no-i386.dylib -fat_no_i386.commands = lipo -create -output $@ -arch x86_64 good.x86_64.dylib -arch ppc64 good.ppc64.dylib -fat_no_i386.depends += good.x86_64.dylib good.ppc64.dylib - -fat_no_x86_64.target = good.fat.no-x86_64.dylib -fat_no_x86_64.commands = lipo -create -output $@ -arch i386 good.i386.dylib -arch ppc64 good.ppc64.dylib -fat_no_x86_64.depends += good.i386.dylib good.ppc64.dylib - -fat_stub_i386.target = good.fat.stub-i386.dylib -fat_stub_i386.commands = lipo -create -output $@ -arch ppc64 good.ppc64.dylib -arch_blank i386 -fat_stub_i386.depends += good.x86_64.dylib good.ppc64.dylib - -fat_stub_x86_64.target = good.fat.stub-x86_64.dylib -fat_stub_x86_64.commands = lipo -create -output $@ -arch ppc64 good.ppc64.dylib -arch_blank x86_64 -fat_stub_x86_64.depends += good.i386.dylib good.ppc64.dylib - -bad.commands = $$PWD/generate-bad.pl -bad.depends += $$PWD/generate-bad.pl - -MYTARGETS = $$fat_all.depends fat_all fat_no_x86_64 fat_no_i386 \ - fat_stub_i386 fat_stub_x86_64 bad -all.depends += $$MYTARGETS -QMAKE_EXTRA_TARGETS += $$MYTARGETS all - -QMAKE_CLEAN += $$fat_all.target $$fat_no_i386.target $$fat_no_x86_64.target \ - $$fat_stub_i386.target $$fat_stub_x86_64.target \ - "bad*.dylib" diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest_i386.pro b/tests/auto/corelib/plugin/qpluginloader/machtest/machtest_i386.pro deleted file mode 100644 index bfb2e0930c..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest_i386.pro +++ /dev/null @@ -1,3 +0,0 @@ -QMAKE_APPLE_DEVICE_ARCHS = i386 -include(machtest.pri) - diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest_ppc64.pro b/tests/auto/corelib/plugin/qpluginloader/machtest/machtest_ppc64.pro deleted file mode 100644 index a73f97ccc6..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest_ppc64.pro +++ /dev/null @@ -1,9 +0,0 @@ -QMAKE_APPLE_DEVICE_ARCHS = ppc64 -include(machtest.pri) - -OTHER_FILES += ppcconverter.pl - -# Current macOS toolchains have no compiler for PPC anymore -# So we fake it by converting an x86-64 binary to (little-endian!) PPC64 -goodlib.commands = $$PWD/ppcconverter.pl $< $@ -goodlib.depends = good.x86_64.dylib $$PWD/ppcconverter.pl diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest_x86_64.pro b/tests/auto/corelib/plugin/qpluginloader/machtest/machtest_x86_64.pro deleted file mode 100644 index 9dbae5c4ee..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/machtest/machtest_x86_64.pro +++ /dev/null @@ -1,2 +0,0 @@ -QMAKE_APPLE_DEVICE_ARCHS = x86_64 -include(machtest.pri) diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/ppcconverter.pl b/tests/auto/corelib/plugin/qpluginloader/machtest/ppcconverter.pl deleted file mode 100755 index 7242d7596b..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/machtest/ppcconverter.pl +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/perl -############################################################################# -## -## Copyright (C) 2016 Intel Corporation. -## Contact: https://www.qt.io/licensing/ -## -## This file is the build configuration utility of the Qt Toolkit. -## -## $QT_BEGIN_LICENSE:GPL-EXCEPT$ -## Commercial License Usage -## Licensees holding valid commercial Qt licenses may use this file in -## accordance with the commercial license agreement provided with the -## Software or, alternatively, in accordance with the terms contained in -## a written agreement between you and The Qt Company. For licensing terms -## and conditions see https://www.qt.io/terms-conditions. For further -## information use the contact form at https://www.qt.io/contact-us. -## -## GNU General Public License Usage -## Alternatively, this file may be used under the terms of the GNU -## General Public License version 3 as published by the Free Software -## Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -## included in the packaging of this file. Please review the following -## information to ensure the GNU General Public License requirements will -## be met: https://www.gnu.org/licenses/gpl-3.0.html. -## -## $QT_END_LICENSE$ -## -############################################################################# - -# Changes the Mach-O file type header to PowerPC. -# -# The header is (from mach-o/loader.h): -# struct mach_header { -# uint32_t magic; /* mach magic number identifier */ -# cpu_type_t cputype; /* cpu specifier */ -# cpu_subtype_t cpusubtype; /* machine specifier */ -# uint32_t filetype; /* type of file */ -# uint32_t ncmds; /* number of load commands */ -# uint32_t sizeofcmds; /* the size of all the load commands */ -# uint32_t flags; /* flags */ -# }; -# -# The 64-bit header is identical in the first three fields, except for a different -# magic number. We will not touch the magic number, we'll just reset the cputype -# field to the PowerPC type and the subtype field to zero. -# -# We will not change the file's endianness. That means we might create a little-endian -# PowerPC binary, which could not be run in real life. -# -# We will also not change the 64-bit ABI flag, which is found in the cputype's high -# byte. That means we'll create a PPC64 binary if fed a 64-bit input. -# -use strict; -use constant MH_MAGIC => 0xfeedface; -use constant MH_CIGAM => 0xcefaedfe; -use constant MH_MAGIC_64 => 0xfeedfacf; -use constant MH_CIGAM_64 => 0xcffaedfe; -use constant CPU_TYPE_POWERPC => 18; -use constant CPU_SUBTYPE_POWERPC_ALL => 0; - -my $infile = shift @ARGV or die("Missing input filename"); -my $outfile = shift @ARGV or die("Missing output filename"); - -open IN, "<$infile" or die("Can't open $infile for reading: $!\n"); -open OUT, ">$outfile" or die("Can't open $outfile for writing: $!\n"); - -binmode IN; -binmode OUT; - -# Read the first 12 bytes, which includes the interesting fields of the header -my $buffer; -read(IN, $buffer, 12); - -my $magic = vec($buffer, 0, 32); -if ($magic == MH_MAGIC || $magic == MH_MAGIC_64) { - # Big endian - # The low byte of cputype is at offset 7 - vec($buffer, 7, 8) = CPU_TYPE_POWERPC; -} elsif ($magic == MH_CIGAM || $magic == MH_CIGAM_64) { - # Little endian - # The low byte of cpytype is at offset 4 - vec($buffer, 4, 8) = CPU_TYPE_POWERPC; -} else { - $magic = ''; - $magic .= sprintf("%02X ", $_) for unpack("CCCC", $buffer); - die("Invalid input. Unknown magic $magic\n"); -} -vec($buffer, 2, 32) = CPU_SUBTYPE_POWERPC_ALL; - -print OUT $buffer; - -# Copy the rest -while (!eof(IN)) { - read(IN, $buffer, 4096) and - print OUT $buffer or - die("Problem copying: $!\n"); -} -close(IN); -close(OUT); diff --git a/tests/auto/corelib/plugin/qpluginloader/machtest/stub.cpp b/tests/auto/corelib/plugin/qpluginloader/machtest/stub.cpp new file mode 100644 index 0000000000..eed7228a29 --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/machtest/stub.cpp @@ -0,0 +1,3 @@ +// Copyright (C) 2024 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +void dummy() {} diff --git a/tests/auto/corelib/plugin/qpluginloader/qpluginloader.pro b/tests/auto/corelib/plugin/qpluginloader/qpluginloader.pro deleted file mode 100644 index 3745782dfc..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/qpluginloader.pro +++ /dev/null @@ -1,20 +0,0 @@ -QT = core -TEMPLATE = subdirs - -tst.depends = lib theplugin -SUBDIRS = lib \ - theplugin \ - tst -!android:!win32:!darwin { - tst.depends += almostplugin - SUBDIRS += almostplugin -} -macos:qtConfig(private_tests):qtHaveModule(gui) { - tst.depends += machtest - SUBDIRS += machtest -} - -# no special install rule for subdir -INSTALLS = - - diff --git a/tests/auto/corelib/plugin/qpluginloader/staticplugin/.gitignore b/tests/auto/corelib/plugin/qpluginloader/staticplugin/.gitignore new file mode 100644 index 0000000000..26f7ecd506 --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/staticplugin/.gitignore @@ -0,0 +1,3 @@ +*staticplugin.prl +libstaticplugin.a +staticplugin.lib diff --git a/tests/auto/corelib/plugin/qpluginloader/staticplugin/CMakeLists.txt b/tests/auto/corelib/plugin/qpluginloader/staticplugin/CMakeLists.txt new file mode 100644 index 0000000000..647c8ac207 --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/staticplugin/CMakeLists.txt @@ -0,0 +1,25 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## staticplugin Generic Library: +##################################################################### + +qt_internal_add_cmake_library(staticplugin + STATIC + SOURCES + main.cpp + LIBRARIES + Qt::Core + MOC_OPTIONS + "-M" + "ExtraMetaData=StaticPlugin" + "-M" + "ExtraMetaData=foo" +) + +# TEMPLATE = "lib" + +qt_autogen_tools_initial_setup(staticplugin) + +target_compile_definitions(staticplugin PRIVATE QT_STATICPLUGIN) diff --git a/tests/auto/corelib/plugin/qpluginloader/staticplugin/main.cpp b/tests/auto/corelib/plugin/qpluginloader/staticplugin/main.cpp new file mode 100644 index 0000000000..208096b425 --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/staticplugin/main.cpp @@ -0,0 +1,14 @@ +// Copyright (C) 2018 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#include <QtPlugin> +#include <QObject> + +class StaticPlugin : public QObject +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID "SomeIID" URI "qt.test.pluginloader.staticplugin") +public: + StaticPlugin() {} +}; + +#include "main.moc" diff --git a/tests/auto/corelib/plugin/qpluginloader/theplugin/CMakeLists.txt b/tests/auto/corelib/plugin/qpluginloader/theplugin/CMakeLists.txt new file mode 100644 index 0000000000..dfce9d6a52 --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/theplugin/CMakeLists.txt @@ -0,0 +1,32 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +qt_internal_add_cmake_library(theplugin + MODULE + INSTALL_DIRECTORY "${INSTALL_TESTSDIR}/tst_qpluginloader/bin" + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../bin" + SOURCES + theplugin.cpp theplugin.h + LIBRARIES + Qt::Core +) +qt_autogen_tools_initial_setup(theplugin) + +if (UNIX AND NOT APPLE) + qt_internal_add_cmake_library(theoldplugin + MODULE + INSTALL_DIRECTORY "${INSTALL_TESTSDIR}/tst_qpluginloader/bin" + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../bin" + SOURCES + theoldplugin.cpp theoldplugin.h + LIBRARIES + Qt::Core + ) + qt_autogen_tools_initial_setup(theoldplugin) + + # Force unoptimized builds with debugging information so some "QTMETADATA !" + # strings appear elsewhere in the binary. + target_compile_options(theplugin PRIVATE -O0 -g3) + target_compile_options(theoldplugin PRIVATE -O0 -g3) +endif() + diff --git a/tests/auto/corelib/plugin/qpluginloader/theplugin/plugininterface.h b/tests/auto/corelib/plugin/qpluginloader/theplugin/plugininterface.h index 12285ba016..3fd6c384a4 100644 --- a/tests/auto/corelib/plugin/qpluginloader/theplugin/plugininterface.h +++ b/tests/auto/corelib/plugin/qpluginloader/theplugin/plugininterface.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef PLUGININTERFACE_H #define PLUGININTERFACE_H diff --git a/tests/auto/corelib/plugin/qpluginloader/theplugin/theoldplugin.cpp b/tests/auto/corelib/plugin/qpluginloader/theplugin/theoldplugin.cpp new file mode 100644 index 0000000000..20e65b4bb0 --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/theplugin/theoldplugin.cpp @@ -0,0 +1,80 @@ +// Copyright (C) 2021 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#include "theoldplugin.h" +#include <QtCore/QString> +#include <QtCore/qplugin.h> + +QString TheOldPlugin::pluginName() const +{ + return QLatin1String("Plugin ok"); +} + +static int pluginVariable = 0xc0ffee; +extern "C" Q_DECL_EXPORT int *pointerAddress() +{ + return &pluginVariable; +} + +// This hardcodes the old plugin metadata from before Qt 6.2 +QT_PLUGIN_METADATA_SECTION +static constexpr unsigned char qt_pluginMetaData_ThePlugin[] = { + 'Q', 'T', 'M', 'E', 'T', 'A', 'D', 'A', 'T', 'A', ' ', '!', + // metadata version, Qt version, architectural requirements + 0, QT_VERSION_MAJOR, QT_VERSION_MINOR, qPluginArchRequirements(), + 0xbf, + // "IID" + 0x02, 0x78, 0x2b, 'o', 'r', 'g', '.', 'q', + 't', '-', 'p', 'r', 'o', 'j', 'e', 'c', + 't', '.', 'Q', 't', '.', 'a', 'u', 't', + 'o', 't', 'e', 's', 't', 's', '.', 'p', + 'l', 'u', 'g', 'i', 'n', 'i', 'n', 't', + 'e', 'r', 'f', 'a', 'c', 'e', + // "className" + 0x03, 0x69, 'T', 'h', 'e', 'P', 'l', 'u', + 'g', 'i', 'n', + // "MetaData" + 0x04, 0xa2, 0x67, 'K', 'P', 'l', 'u', 'g', + 'i', 'n', 0xa8, 0x64, 'N', 'a', 'm', 'e', + 0x6e, 'W', 'i', 'n', 'd', 'o', 'w', 'G', + 'e', 'o', 'm', 'e', 't', 'r', 'y', 0x68, + 'N', 'a', 'm', 'e', '[', 'm', 'r', ']', + 0x78, 0x1f, uchar('\xe0'), uchar('\xa4'), uchar('\x9a'), uchar('\xe0'), uchar('\xa5'), uchar('\x8c'), + uchar('\xe0'), uchar('\xa4'), uchar('\x95'), uchar('\xe0'), uchar('\xa4'), uchar('\x9f'), ' ', uchar('\xe0'), + uchar('\xa4'), uchar('\xad'), uchar('\xe0'), uchar('\xa5'), uchar('\x82'), uchar('\xe0'), uchar('\xa4'), uchar('\xae'), + uchar('\xe0'), uchar('\xa4'), uchar('\xbf'), uchar('\xe0'), uchar('\xa4'), uchar('\xa4'), uchar('\xe0'), uchar('\xa5'), + uchar('\x80'), 0x68, 'N', 'a', 'm', 'e', '[', 'p', + 'a', ']', 0x78, 0x24, uchar('\xe0'), uchar('\xa8'), uchar('\xb5'), uchar('\xe0'), + uchar('\xa8'), uchar('\xbf'), uchar('\xe0'), uchar('\xa9'), uchar('\xb0'), uchar('\xe0'), uchar('\xa8'), uchar('\xa1'), + uchar('\xe0'), uchar('\xa9'), uchar('\x8b'), uchar('\xe0'), uchar('\xa8'), uchar('\x9c'), uchar('\xe0'), uchar('\xa9'), + uchar('\x81'), uchar('\xe0'), uchar('\xa8'), uchar('\xae'), uchar('\xe0'), uchar('\xa9'), uchar('\x88'), uchar('\xe0'), + uchar('\xa8'), uchar('\x9f'), uchar('\xe0'), uchar('\xa8'), uchar('\xb0'), uchar('\xe0'), uchar('\xa9'), uchar('\x80'), + 0x68, 'N', 'a', 'm', 'e', '[', 't', 'h', + ']', 0x78, 0x39, uchar('\xe0'), uchar('\xb8'), uchar('\xa1'), uchar('\xe0'), uchar('\xb8'), + uchar('\xb4'), uchar('\xe0'), uchar('\xb8'), uchar('\x95'), uchar('\xe0'), uchar('\xb8'), uchar('\xb4'), uchar('\xe0'), + uchar('\xb8'), uchar('\x82'), uchar('\xe0'), uchar('\xb8'), uchar('\x99'), uchar('\xe0'), uchar('\xb8'), uchar('\xb2'), + uchar('\xe0'), uchar('\xb8'), uchar('\x94'), uchar('\xe0'), uchar('\xb8'), uchar('\x82'), uchar('\xe0'), uchar('\xb8'), + uchar('\xad'), uchar('\xe0'), uchar('\xb8'), uchar('\x87'), uchar('\xe0'), uchar('\xb8'), uchar('\xab'), uchar('\xe0'), + uchar('\xb8'), uchar('\x99'), uchar('\xe0'), uchar('\xb9'), uchar('\x89'), uchar('\xe0'), uchar('\xb8'), uchar('\xb2'), + uchar('\xe0'), uchar('\xb8'), uchar('\x95'), uchar('\xe0'), uchar('\xb9'), uchar('\x88'), uchar('\xe0'), uchar('\xb8'), + uchar('\xb2'), uchar('\xe0'), uchar('\xb8'), uchar('\x87'), 0x68, 'N', 'a', 'm', + 'e', '[', 'u', 'k', ']', 0x78, 0x19, uchar('\xd0'), + uchar('\xa0'), uchar('\xd0'), uchar('\xbe'), uchar('\xd0'), uchar('\xb7'), uchar('\xd0'), uchar('\xbc'), uchar('\xd1'), + uchar('\x96'), uchar('\xd1'), uchar('\x80'), uchar('\xd0'), uchar('\xb8'), ' ', uchar('\xd0'), uchar('\xb2'), + uchar('\xd1'), uchar('\x96'), uchar('\xd0'), uchar('\xba'), uchar('\xd0'), uchar('\xbd'), uchar('\xd0'), uchar('\xb0'), + 0x6b, 'N', 'a', 'm', 'e', '[', 'z', 'h', + '_', 'C', 'N', ']', 0x6c, uchar('\xe7'), uchar('\xaa'), uchar('\x97'), + uchar('\xe5'), uchar('\x8f'), uchar('\xa3'), uchar('\xe5'), uchar('\xbd'), uchar('\xa2'), uchar('\xe7'), uchar('\x8a'), + uchar('\xb6'), 0x6b, 'N', 'a', 'm', 'e', '[', 'z', + 'h', '_', 'T', 'W', ']', 0x6c, uchar('\xe8'), uchar('\xa6'), + uchar('\x96'), uchar('\xe7'), uchar('\xaa'), uchar('\x97'), uchar('\xe4'), uchar('\xbd'), uchar('\x8d'), uchar('\xe7'), + uchar('\xbd'), uchar('\xae'), 0x6c, 'S', 'e', 'r', 'v', 'i', + 'c', 'e', 'T', 'y', 'p', 'e', 's', 0x81, + 0x68, 'K', 'C', 'M', 'o', 'd', 'u', 'l', + 'e', 0x76, 'X', '-', 'K', 'D', 'E', '-', + 'P', 'a', 'r', 'e', 'n', 't', 'C', 'o', + 'm', 'p', 'o', 'n', 'e', 'n', 't', 's', + 0x81, 0x6e, 'w', 'i', 'n', 'd', 'o', 'w', + 'g', 'e', 'o', 'm', 'e', 't', 'r', 'y', + 0xff, +}; +QT_MOC_EXPORT_PLUGIN(TheOldPlugin, ThePlugin) diff --git a/tests/auto/corelib/plugin/qpluginloader/theplugin/theoldplugin.h b/tests/auto/corelib/plugin/qpluginloader/theplugin/theoldplugin.h new file mode 100644 index 0000000000..786ce3f618 --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/theplugin/theoldplugin.h @@ -0,0 +1,21 @@ +// Copyright (C) 2021 Intel Corportaion. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only +#ifndef THEOLDPLUGIN_H +#define THEOLDPLUGIN_H + +#include <QObject> +#include <QtPlugin> +#include "plugininterface.h" + +class TheOldPlugin : public QObject, public PluginInterface +{ + Q_OBJECT + // Q_PLUGIN_METADATA intentionally missing + Q_INTERFACES(PluginInterface) + +public: + virtual QString pluginName() const override; +}; + +#endif // THEOLDPLUGIN_H + diff --git a/tests/auto/corelib/plugin/qpluginloader/theplugin/theplugin.cpp b/tests/auto/corelib/plugin/qpluginloader/theplugin/theplugin.cpp index 01563c3dc9..bfa45c7c48 100644 --- a/tests/auto/corelib/plugin/qpluginloader/theplugin/theplugin.cpp +++ b/tests/auto/corelib/plugin/qpluginloader/theplugin/theplugin.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtCore/QString> #include "theplugin.h" #include <QtCore/qplugin.h> diff --git a/tests/auto/corelib/plugin/qpluginloader/theplugin/theplugin.h b/tests/auto/corelib/plugin/qpluginloader/theplugin/theplugin.h index ac349c2f75..a6b7e4a083 100644 --- a/tests/auto/corelib/plugin/qpluginloader/theplugin/theplugin.h +++ b/tests/auto/corelib/plugin/qpluginloader/theplugin/theplugin.h @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #ifndef THEPLUGIN_H #define THEPLUGIN_H @@ -39,7 +14,7 @@ class ThePlugin : public QObject, public PluginInterface Q_INTERFACES(PluginInterface) public: - virtual QString pluginName() const; + virtual QString pluginName() const override; }; #endif // THEPLUGIN_H diff --git a/tests/auto/corelib/plugin/qpluginloader/theplugin/theplugin.pro b/tests/auto/corelib/plugin/qpluginloader/theplugin/theplugin.pro deleted file mode 100644 index 6aa8161699..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/theplugin/theplugin.pro +++ /dev/null @@ -1,14 +0,0 @@ -TEMPLATE = lib -CONFIG += plugin -HEADERS = theplugin.h -SOURCES = theplugin.cpp -# Use a predictable name for the plugin, no debug extension. Just like most apps do. -#TARGET = $$qtLibraryTarget(theplugin) -TARGET = theplugin -DESTDIR = ../bin -winrt:include(../winrt.pri) -QT = core - -# This is testdata for the tst_qpluginloader test. -target.path = $$[QT_INSTALL_TESTS]/tst_qpluginloader/bin -INSTALLS += target diff --git a/tests/auto/corelib/plugin/qpluginloader/tst/CMakeLists.txt b/tests/auto/corelib/plugin/qpluginloader/tst/CMakeLists.txt new file mode 100644 index 0000000000..16dd1cf9cf --- /dev/null +++ b/tests/auto/corelib/plugin/qpluginloader/tst/CMakeLists.txt @@ -0,0 +1,71 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## tst_qpluginloader Test: +##################################################################### + +# Collect test data +list(APPEND test_data "../elftest") +list(APPEND test_data "../machtest") + +qt_internal_add_test(tst_qpluginloader + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" + SOURCES + ../fakeplugin.cpp + ../theplugin/plugininterface.h + ../tst_qpluginloader.cpp + LIBRARIES + staticplugin + TESTDATA ${test_data} +) + +add_dependencies(tst_qpluginloader tst_qpluginloaderlib staticplugin theplugin) +if (UNIX) + if(NOT APPLE) + add_dependencies(tst_qpluginloader theoldplugin) + endif() + if (NOT ANDROID AND NOT APPLE) + add_dependencies(tst_qpluginloader almostplugin) + endif() +endif() + +if(ANDROID) + add_compile_definitions(ANDROID_ARCH="${CMAKE_ANDROID_ARCH_ABI}") + set(plugins + theplugin + theoldplugin + tst_qpluginloaderlib + ) + set(extra_libs) + foreach(plugin IN LISTS plugins) + list(APPEND extra_libs + "${CMAKE_CURRENT_BINARY_DIR}/../bin/lib${plugin}_${CMAKE_ANDROID_ARCH_ABI}.so") + endforeach() + set_target_properties(tst_qpluginloader PROPERTIES + QT_ANDROID_EXTRA_LIBS "${extra_libs}" + ) +endif() + +## Scopes: +##################################################################### + +qt_internal_extend_target(tst_qpluginloader CONDITION QT_FEATURE_private_tests + LIBRARIES + Qt::CorePrivate +) + +qt_internal_extend_target(tst_qpluginloader CONDITION CMAKE_BUILD_TYPE STREQUAL Debug AND WIN32 AND debug_and_release + LIBRARIES + # Remove: L../staticplugin/debug +) + +qt_internal_extend_target(tst_qpluginloader CONDITION WIN32 AND debug_and_release AND NOT CMAKE_BUILD_TYPE STREQUAL Debug + LIBRARIES + # Remove: L../staticplugin/release +) + +qt_internal_extend_target(tst_qpluginloader CONDITION UNIX OR NOT debug_and_release + LIBRARIES + # Remove: L../staticplugin +) diff --git a/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro b/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro deleted file mode 100644 index c20e56ba4c..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/tst/tst.pro +++ /dev/null @@ -1,16 +0,0 @@ -CONFIG += testcase -TARGET = ../tst_qpluginloader -QT = core testlib -qtConfig(private_tests): QT += core-private -SOURCES = ../tst_qpluginloader.cpp ../fakeplugin.cpp -HEADERS = ../theplugin/plugininterface.h - -win32 { - CONFIG(debug, debug|release) { - TARGET = ../../debug/tst_qpluginloader - } else { - TARGET = ../../release/tst_qpluginloader - } -} - -TESTDATA += ../elftest ../machtest diff --git a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp index c517c0809a..f4ecf5bfb3 100644 --- a/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp +++ b/tests/auto/corelib/plugin/qpluginloader/tst_qpluginloader.cpp @@ -1,41 +1,23 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Copyright (C) 2016 Intel Corporation. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <QtTest/QtTest> +// Copyright (C) 2020 The Qt Company Ltd. +// Copyright (C) 2021 Intel Corporation. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include <QTest> +#include <QSignalSpy> +#include <QJsonArray> #include <qdir.h> +#include <qendian.h> #include <qpluginloader.h> +#include <qtemporaryfile.h> +#include <QScopeGuard> #include "theplugin/plugininterface.h" #if defined(QT_BUILD_INTERNAL) && defined(Q_OF_MACH_O) # include <QtCore/private/qmachparser_p.h> #endif +using namespace Qt::StringLiterals; + // Helper macros to let us know if some suffixes are valid #define bundle_VALID false #define dylib_VALID false @@ -51,11 +33,11 @@ # define bundle_VALID true # define dylib_VALID true # define so_VALID true -//# ifdef QT_NO_DEBUG +# ifdef QT_NO_DEBUG # define SUFFIX ".dylib" -//# else -//# define SUFFIX "_debug.dylib" -//#endif +# else +# define SUFFIX "_debug.dylib" +# endif # define PREFIX "lib" #elif defined(Q_OS_HPUX) && !defined(__ia64) @@ -89,14 +71,113 @@ # define PREFIX "lib" #endif +#if defined(Q_OF_ELF) +#if __has_include(<elf.h>) +# include <elf.h> +#else +# include <sys/elf.h> +#endif +# include <memory> +# include <functional> + +# ifdef _LP64 +using ElfHeader = Elf64_Ehdr; +using ElfPhdr = Elf64_Phdr; +using ElfNhdr = Elf64_Nhdr; +using ElfShdr = Elf64_Shdr; +# else +using ElfHeader = Elf32_Ehdr; +using ElfPhdr = Elf32_Phdr; +using ElfNhdr = Elf32_Nhdr; +using ElfShdr = Elf32_Shdr; +# endif + +struct ElfPatcher +{ + using FullPatcher = void(ElfHeader *, QFile *); + FullPatcher *f; + + ElfPatcher(FullPatcher *f = nullptr) : f(f) {} + + template <typename T> using IsSingleArg = std::is_invocable<T, ElfHeader *>; + template <typename T> static std::enable_if_t<IsSingleArg<T>::value, ElfPatcher> fromLambda(T &&t) + { + using WithoutQFile = void(*)(ElfHeader *); + static const WithoutQFile f = t; + return { [](ElfHeader *h, QFile *) { f(h);} }; + } + template <typename T> static std::enable_if_t<!IsSingleArg<T>::value, ElfPatcher> fromLambda(T &&t) + { + return { t }; + } +}; + +Q_DECLARE_METATYPE(ElfPatcher) + +static std::unique_ptr<QTemporaryFile> patchElf(const QString &source, ElfPatcher patcher) +{ + std::unique_ptr<QTemporaryFile> tmplib; + + bool ok = false; + [&]() { + QFile srclib(source); + QVERIFY2(srclib.open(QIODevice::ReadOnly), qPrintable(srclib.errorString())); + qint64 srcsize = srclib.size(); + const uchar *srcdata = srclib.map(0, srcsize, QFile::MapPrivateOption); + QVERIFY2(srcdata, qPrintable(srclib.errorString())); + + // copy our source plugin so we can modify it + const char *basename = QTest::currentDataTag(); + if (!basename) + basename = QTest::currentTestFunction(); + tmplib.reset(new QTemporaryFile(QDir::currentPath() + u'/' + basename + u".XXXXXX" SUFFIX ""_s)); + QVERIFY2(tmplib->open(), qPrintable(tmplib->errorString())); + + // sanity-check + QByteArray magic = QByteArray::fromRawData(reinterpret_cast<const char *>(srcdata), SELFMAG); + QCOMPARE(magic, QByteArray(ELFMAG)); + + // copy everything via mmap() + QVERIFY2(tmplib->resize(srcsize), qPrintable(tmplib->errorString())); + uchar *dstdata = tmplib->map(0, srcsize); + memcpy(dstdata, srcdata, srcsize); + + // now patch the file + patcher.f(reinterpret_cast<ElfHeader *>(dstdata), tmplib.get()); + + ok = true; + }(); + if (!ok) + tmplib.reset(); + return tmplib; +} + +// All ELF systems are expected to support GCC expression statements +#define patchElf(source, patcher) __extension__({ \ + auto r = patchElf(source, patcher); \ + if (QTest::currentTestFailed()) return; \ + std::move(r); \ + }) +#endif // Q_OF_ELF + static QString sys_qualifiedLibraryName(const QString &fileName) { +#ifdef Q_OS_ANDROID + // On Android all the libraries must be located in the APK's libs subdir + const QStringList paths = QCoreApplication::libraryPaths(); + if (!paths.isEmpty()) { + return QLatin1String("%1/%2%3_%4%5").arg(paths.first(), PREFIX, fileName, + ANDROID_ARCH, SUFFIX); + } + return fileName; +#else QString name = QLatin1String("bin/") + QLatin1String(PREFIX) + fileName + QLatin1String(SUFFIX); const QString libname = QFINDTESTDATA(name); QFileInfo fi(libname); if (fi.exists()) return fi.canonicalFilePath(); return libname; +#endif } QT_FORWARD_DECLARE_CLASS(QPluginLoader) @@ -109,20 +190,29 @@ private slots: void errorString(); void loadHints(); void deleteinstanceOnUnload(); +#if defined (Q_OF_ELF) void loadDebugObj(); + void loadCorruptElf_data(); void loadCorruptElf(); +# if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) + void loadCorruptElfOldPlugin_data(); + void loadCorruptElfOldPlugin(); +# endif +#endif void loadMachO_data(); void loadMachO(); -#if defined (Q_OS_UNIX) - void loadGarbage(); -#endif void relativePath(); void absolutePath(); void reloadPlugin(); + void loadSectionTableStrippedElf(); void preloadedPlugin_data(); void preloadedPlugin(); + void staticPlugins(); + void reregisteredStaticPlugins(); }; +Q_IMPORT_PLUGIN(StaticPlugin) + void tst_QPluginLoader::cleanup() { // check if the library/plugin was leaked @@ -190,7 +280,9 @@ void tst_QPluginLoader::errorString() QVERIFY(!unloaded); } -#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC) && !defined(Q_OS_HPUX) +// A bug in QNX causes the test to crash on exit after attempting to load +// a shared library with undefined symbols (tracked as QTBUG-114682). +#if !defined(Q_OS_WIN) && !defined(Q_OS_DARWIN) && !defined(Q_OS_HPUX) && !defined(Q_OS_QNX) { QPluginLoader loader( sys_qualifiedLibraryName("almostplugin")); //a plugin with unresolved symbols loader.setLoadHints(QLibrary::ResolveAllSymbolsHint); @@ -208,29 +300,36 @@ void tst_QPluginLoader::errorString() } #endif - { - QPluginLoader loader( sys_qualifiedLibraryName("theplugin")); //a plugin - - // Check metadata - const QJsonObject metaData = loader.metaData(); - QCOMPARE(metaData.value("IID").toString(), QStringLiteral("org.qt-project.Qt.autotests.plugininterface")); - const QJsonObject kpluginObject = metaData.value("MetaData").toObject().value("KPlugin").toObject(); - QCOMPARE(kpluginObject.value("Name[mr]").toString(), QString::fromUtf8("चौकट à¤à¥‚मिती")); - - // Load - QCOMPARE(loader.load(), true); - QCOMPARE(loader.errorString(), unknown); - - QVERIFY(loader.instance() != static_cast<QObject*>(0)); - QCOMPARE(loader.errorString(), unknown); - - // Make sure that plugin really works - PluginInterface* theplugin = qobject_cast<PluginInterface*>(loader.instance()); - QString pluginName = theplugin->pluginName(); - QCOMPARE(pluginName, QLatin1String("Plugin ok")); - - QCOMPARE(loader.unload(), true); - QCOMPARE(loader.errorString(), unknown); + static constexpr std::initializer_list<const char *> validplugins = { + "theplugin", +#if defined(Q_OF_ELF) && QT_VERSION < QT_VERSION_CHECK(7, 0, 0) + "theoldplugin" +#endif + }; + for (const char *basename : validplugins) { + QPluginLoader loader( sys_qualifiedLibraryName(basename)); //a plugin + + // Check metadata + const QJsonObject metaData = loader.metaData(); + QVERIFY2(!metaData.isEmpty(), "No metadata from " + loader.fileName().toLocal8Bit()); + QCOMPARE(metaData.value("IID").toString(), QStringLiteral("org.qt-project.Qt.autotests.plugininterface")); + const QJsonObject kpluginObject = metaData.value("MetaData").toObject().value("KPlugin").toObject(); + QCOMPARE(kpluginObject.value("Name[mr]").toString(), QString::fromUtf8("चौकट à¤à¥‚मिती")); + + // Load + QVERIFY2(loader.load(), qPrintable(loader.errorString())); + QCOMPARE(loader.errorString(), unknown); + + QVERIFY(loader.instance() != static_cast<QObject*>(0)); + QCOMPARE(loader.errorString(), unknown); + + // Make sure that plugin really works + PluginInterface* theplugin = qobject_cast<PluginInterface*>(loader.instance()); + QString pluginName = theplugin->pluginName(); + QCOMPARE(pluginName, QLatin1String("Plugin ok")); + + QCOMPARE(loader.unload(), true); + QCOMPARE(loader.errorString(), unknown); } } @@ -240,10 +339,37 @@ void tst_QPluginLoader::loadHints() QSKIP("This test requires Qt to create shared libraries."); #endif QPluginLoader loader; - QCOMPARE(loader.loadHints(), (QLibrary::LoadHints)0); //Do not crash + QCOMPARE(loader.loadHints(), QLibrary::PreventUnloadHint); //Do not crash + loader.setLoadHints(QLibrary::ResolveAllSymbolsHint); + QCOMPARE(loader.loadHints(), QLibrary::ResolveAllSymbolsHint); + // We can clear load hints when file name is not set. + loader.setLoadHints(QLibrary::LoadHints{}); + QCOMPARE(loader.loadHints(), QLibrary::LoadHints{}); + // Set the hints again loader.setLoadHints(QLibrary::ResolveAllSymbolsHint); + QCOMPARE(loader.loadHints(), QLibrary::ResolveAllSymbolsHint); loader.setFileName( sys_qualifiedLibraryName("theplugin")); //a plugin QCOMPARE(loader.loadHints(), QLibrary::ResolveAllSymbolsHint); + + QPluginLoader loader4; + QCOMPARE(loader4.loadHints(), QLibrary::PreventUnloadHint); + loader4.setLoadHints(QLibrary::LoadHints{}); + QCOMPARE(loader4.loadHints(), QLibrary::LoadHints{}); + loader4.setFileName(sys_qualifiedLibraryName("theplugin")); + // Hints are merged with hints from the previous loader. + QCOMPARE(loader4.loadHints(), QLibrary::ResolveAllSymbolsHint); + // We cannot clear load hints after associating the loader with a file. + loader.setLoadHints(QLibrary::LoadHints{}); + QCOMPARE(loader.loadHints(), QLibrary::ResolveAllSymbolsHint); + + QPluginLoader loader2; + QCOMPARE(loader2.loadHints(), QLibrary::PreventUnloadHint); + loader2.setFileName(sys_qualifiedLibraryName("theplugin")); + // Hints are merged with hints from previous loaders. + QCOMPARE(loader2.loadHints(), QLibrary::PreventUnloadHint | QLibrary::ResolveAllSymbolsHint); + + QPluginLoader loader3(sys_qualifiedLibraryName("theplugin")); + QCOMPARE(loader3.loadHints(), QLibrary::PreventUnloadHint | QLibrary::ResolveAllSymbolsHint); } void tst_QPluginLoader::deleteinstanceOnUnload() @@ -273,92 +399,485 @@ void tst_QPluginLoader::deleteinstanceOnUnload() QVERIFY(spy2.isValid()); if (pass == 0) { QCOMPARE(loader2.unload(), false); // refcount not reached 0, not really unloaded - QCOMPARE(spy1.count(), 0); - QCOMPARE(spy2.count(), 0); + QCOMPARE(spy1.size(), 0); + QCOMPARE(spy2.size(), 0); } QCOMPARE(instance1->pluginName(), QLatin1String("Plugin ok")); QCOMPARE(instance2->pluginName(), QLatin1String("Plugin ok")); QVERIFY(loader1.unload()); // refcount reached 0, did really unload - QCOMPARE(spy1.count(), 1); - QCOMPARE(spy2.count(), 1); + QCOMPARE(spy1.size(), 1); + QCOMPARE(spy2.size(), 1); } } +#if defined(Q_OF_ELF) + void tst_QPluginLoader::loadDebugObj() { #if !defined(QT_SHARED) QSKIP("This test requires a shared build of Qt, as QPluginLoader::setFileName is a no-op in static builds"); #endif -#if defined (__ELF__) QVERIFY(QFile::exists(QFINDTESTDATA("elftest/debugobj.so"))); QPluginLoader lib1(QFINDTESTDATA("elftest/debugobj.so")); QCOMPARE(lib1.load(), false); +} + +template <typename Lambda> +static void newRow(const char *rowname, QString &&snippet, Lambda &&patcher) +{ + QTest::newRow(rowname) + << std::move(snippet) << ElfPatcher::fromLambda(std::forward<Lambda>(patcher)); +} + +static ElfPhdr *getProgramEntry(ElfHeader *h, int index) +{ + auto phdr = reinterpret_cast<ElfPhdr *>(h->e_phoff + reinterpret_cast<uchar *>(h)); + return phdr + index; +} + +static void loadCorruptElfCommonRows() +{ + QTest::addColumn<QString>("snippet"); + QTest::addColumn<ElfPatcher>("patcher"); + + using H = ElfHeader *; // because I'm lazy + newRow("not-elf", "invalid signature", [](H h) { + h->e_ident[EI_MAG0] = 'Q'; + h->e_ident[EI_MAG1] = 't'; + }); + + newRow("wrong-word-size", "file is for a different word size", [](H h) { + h->e_ident[EI_CLASS] = sizeof(void *) == 8 ? ELFCLASS32 : ELFCLASS64; + + // unnecessary, but we're doing it anyway +# ifdef _LP64 + Elf32_Ehdr o; + o.e_phentsize = sizeof(Elf32_Phdr); + o.e_shentsize = sizeof(Elf32_Shdr); +# else + Elf64_Ehdr o; + o.e_phentsize = sizeof(Elf64_Phdr); + o.e_shentsize = sizeof(Elf64_Shdr); +# endif + memcpy(o.e_ident, h->e_ident, EI_NIDENT); + o.e_type = h->e_type; + o.e_machine = h->e_machine; + o.e_version = h->e_version; + o.e_entry = h->e_entry; + o.e_phoff = h->e_phoff; + o.e_shoff = h->e_shoff; + o.e_flags = h->e_flags; + o.e_ehsize = sizeof(o); + o.e_phnum = h->e_phnum; + o.e_shnum = h->e_shnum; + o.e_shstrndx = h->e_shstrndx; + memcpy(h, &o, sizeof(o)); + }); + newRow("invalid-word-size", "file is for a different word size", [](H h) { + h->e_ident[EI_CLASS] = ELFCLASSNONE; + }); + newRow("unknown-word-size", "file is for a different word size", [](H h) { + h->e_ident[EI_CLASS] |= 0x40; + }); + + newRow("wrong-endian", "file is for the wrong endianness", [](H h) { + h->e_ident[EI_DATA] = QSysInfo::ByteOrder == QSysInfo::LittleEndian ? ELFDATA2MSB : ELFDATA2LSB; + + // unnecessary, but we're doing it anyway + h->e_type = qbswap(h->e_type); + h->e_machine = qbswap(h->e_machine); + h->e_version = qbswap(h->e_version); + h->e_entry = qbswap(h->e_entry); + h->e_phoff = qbswap(h->e_phoff); + h->e_shoff = qbswap(h->e_shoff); + h->e_flags = qbswap(h->e_flags); + h->e_ehsize = qbswap(h->e_ehsize); + h->e_phnum = qbswap(h->e_phnum); + h->e_phentsize = qbswap(h->e_phentsize); + h->e_shnum = qbswap(h->e_shnum); + h->e_shentsize = qbswap(h->e_shentsize); + h->e_shstrndx = qbswap(h->e_shstrndx); + }); + newRow("invalid-endian", "file is for the wrong endianness", [](H h) { + h->e_ident[EI_DATA] = ELFDATANONE; + }); + newRow("unknown-endian", "file is for the wrong endianness", [](H h) { + h->e_ident[EI_DATA] |= 0x40; + }); + + newRow("elf-version-0", "file has an unknown ELF version", [](H h) { + --h->e_ident[EI_VERSION]; + }); + newRow("elf-version-2", "file has an unknown ELF version", [](H h) { + ++h->e_ident[EI_VERSION]; + }); + + newRow("executable", "file is not a shared object", [](H h) { + h->e_type = ET_EXEC; + }); + newRow("relocatable", "file is not a shared object", [](H h) { + h->e_type = ET_REL; + }); + newRow("core-file", "file is not a shared object", [](H h) { + h->e_type = ET_CORE; + }); + newRow("invalid-type", "file is not a shared object", [](H h) { + h->e_type |= 0x100; + }); + + newRow("wrong-arch", "file is for a different processor", [](H h) { + // could just ++h->e_machine... +# if defined(Q_PROCESSOR_X86_64) + h->e_machine = EM_AARCH64; +# elif defined(Q_PROCESSOR_ARM_64) + h->e_machine = EM_X86_64; +# elif defined(Q_PROCESSOR_X86_32) + h->e_machine = EM_ARM; +# elif defined(Q_PROCESSOR_ARM) + h->e_machine = EM_386; +# elif defined(Q_PROCESSOR_MIPS_64) + h->e_machine = EM_PPC64; +# elif defined(Q_PROCESSOR_MIPS_32) + h->e_machine = EM_PPC; +# elif defined(Q_PROCESSOR_POWER_64) + h->e_machine = EM_S390; +# elif defined(Q_PROCESSOR_POWER_32) + h->e_machine = EM_MIPS; +# endif + }); + + newRow("file-version-0", "file has an unknown ELF version", [](H h) { + --h->e_version; + }); + newRow("file-version-2", "file has an unknown ELF version", [](H h) { + ++h->e_version; + }); + + newRow("program-entry-size-zero", "unexpected program header entry size", [](H h) { + h->e_phentsize = 0; + }); + newRow("program-entry-small", "unexpected program header entry size", [](H h) { + h->e_phentsize = alignof(ElfPhdr); + }); + + newRow("program-table-starts-past-eof", "program header table extends past the end of the file", + [](H h, QFile *f) { + h->e_phoff = f->size(); + }); + newRow("program-table-ends-past-eof", "program header table extends past the end of the file", + [](H h, QFile *f) { + h->e_phoff = f->size() + 1- h->e_phentsize * h->e_phnum; + }); + + newRow("segment-starts-past-eof", "a program header entry extends past the end of the file", + [](H h, QFile *f) { + for (int i = 0; i < h->e_phnum; ++i) { + ElfPhdr *p = getProgramEntry(h, i); + if (p->p_type != PT_LOAD) + continue; + p->p_offset = f->size(); + break; + } + }); + newRow("segment-ends-past-eof", "a program header entry extends past the end of the file", + [](H h, QFile *f) { + for (int i = 0; i < h->e_phnum; ++i) { + ElfPhdr *p = getProgramEntry(h, i); + if (p->p_type != PT_LOAD) + continue; + p->p_filesz = f->size() + 1 - p->p_offset; + break; + } + }); + newRow("segment-bounds-overflow", "a program header entry extends past the end of the file", + [](H h) { + for (int i = 0; i < h->e_phnum; ++i) { + ElfPhdr *p = getProgramEntry(h, i); + if (p->p_type != PT_LOAD) + continue; + p->p_filesz = ~size_t(0); // -1 + break; + } + }); + + newRow("no-code", "file has no code", [](H h) { + for (int i = 0; i < h->e_phnum; ++i) { + ElfPhdr *p = getProgramEntry(h, i); + if (p->p_type == PT_LOAD) + p->p_flags &= ~PF_X; + } + }); +} + +void tst_QPluginLoader::loadCorruptElf_data() +{ +#if !defined(QT_SHARED) + QSKIP("This test requires a shared build of Qt, as QPluginLoader::setFileName is a no-op in static builds"); #endif + loadCorruptElfCommonRows(); + using H = ElfHeader *; // because I'm lazy + + // PT_NOTE tests + // general validity is tested in the common rows, for all segments + + newRow("misaligned-note-segment", "note segment start is not properly aligned", [](H h) { + for (int i = 0; i < h->e_phnum; ++i) { + ElfPhdr *p = getProgramEntry(h, i); + if (p->p_type == PT_NOTE) + ++p->p_offset; + } + }); + + static const auto getFirstNote = [](void *header, ElfPhdr *phdr) { + return reinterpret_cast<ElfNhdr *>(static_cast<uchar *>(header) + phdr->p_offset); + }; + static const auto getNextNote = [](void *header, ElfPhdr *phdr, ElfNhdr *n) { + // how far into the segment are we? + size_t offset = reinterpret_cast<uchar *>(n) - static_cast<uchar *>(header) - phdr->p_offset; + + size_t delta = sizeof(*n) + n->n_namesz + phdr->p_align - 1; + delta &= -phdr->p_align; + delta += n->n_descsz + phdr->p_align - 1; + delta &= -phdr->p_align; + + offset += delta; + if (offset < phdr->p_filesz) + n = reinterpret_cast<ElfNhdr *>(reinterpret_cast<uchar *>(n) + delta); + else + n = nullptr; + return n; + }; + + // all the intra-note errors cause the notes simply to be skipped + auto newNoteRow = [](const char *rowname, auto &&lambda) { + newRow(rowname, "is not a Qt plugin (metadata not found)", std::move(lambda)); + }; + newNoteRow("no-notes", [](H h) { + for (int i = 0; i < h->e_phnum; ++i) { + ElfPhdr *p = getProgramEntry(h, i); + if (p->p_type == PT_NOTE) + p->p_type = PT_NULL; + } + }); + + newNoteRow("note-larger-than-segment-nonqt", [](H h) { + for (int i = 0; i < h->e_phnum; ++i) { + ElfPhdr *p = getProgramEntry(h, i); + if (p->p_type != PT_NOTE) + continue; + ElfNhdr *n = getFirstNote(h, p); + n->n_descsz = p->p_filesz; + n->n_type = 0; // ensure it's not the Qt note + } + }); + newNoteRow("note-larger-than-segment-qt", [](H h) { + for (int i = 0; i < h->e_phnum; ++i) { + ElfPhdr *p = getProgramEntry(h, i); + if (p->p_type != PT_NOTE || p->p_align != alignof(QPluginMetaData::ElfNoteHeader)) + continue; + + // find the Qt metadata note + constexpr QPluginMetaData::ElfNoteHeader header(0); + ElfNhdr *n = getFirstNote(h, p); + for ( ; n; n = getNextNote(h, p, n)) { + if (n->n_type == header.n_type && n->n_namesz == header.n_namesz) { + if (memcmp(n + 1, header.name, sizeof(header.name)) == 0) + break; + } + } + + if (!n) + break; + n->n_descsz = p->p_filesz; + return; + } + qWarning("Could not find the Qt metadata note in this file. Test will fail."); + }); + newNoteRow("note-size-overflow1", [](H h) { + // due to limited range, this will not overflow on 64-bit + for (int i = 0; i < h->e_phnum; ++i) { + ElfPhdr *p = getProgramEntry(h, i); + if (p->p_type != PT_NOTE) + continue; + ElfNhdr *n = getFirstNote(h, p); + n->n_namesz = ~decltype(n->n_namesz)(0); + } + }); + newNoteRow("note-size-overflow2", [](H h) { + // due to limited range, this will not overflow on 64-bit + for (int i = 0; i < h->e_phnum; ++i) { + ElfPhdr *p = getProgramEntry(h, i); + if (p->p_type != PT_NOTE) + continue; + ElfNhdr *n = getFirstNote(h, p); + n->n_namesz = ~decltype(n->n_namesz)(0) / 2; + n->n_descsz = ~decltype(n->n_descsz)(0) / 2; + } + }); +} + +static void loadCorruptElf_helper(const QString &origLibrary) +{ + QFETCH(QString, snippet); + QFETCH(ElfPatcher, patcher); + + std::unique_ptr<QTemporaryFile> tmplib = patchElf(origLibrary, patcher); + + QPluginLoader lib(tmplib->fileName()); + QVERIFY(!lib.load()); + QVERIFY2(lib.errorString().contains(snippet), qPrintable(lib.errorString())); } void tst_QPluginLoader::loadCorruptElf() { + loadCorruptElf_helper(sys_qualifiedLibraryName("theplugin")); +} + +# if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) +void tst_QPluginLoader::loadCorruptElfOldPlugin_data() +{ #if !defined(QT_SHARED) QSKIP("This test requires a shared build of Qt, as QPluginLoader::setFileName is a no-op in static builds"); #endif -#if defined (__ELF__) - if (sizeof(void*) == 8) { - QVERIFY(QFile::exists(QFINDTESTDATA("elftest/corrupt1.elf64.so"))); - - QPluginLoader lib1(QFINDTESTDATA("elftest/corrupt1.elf64.so")); - QCOMPARE(lib1.load(), false); - QVERIFY2(lib1.errorString().contains("not an ELF object"), qPrintable(lib1.errorString())); - - QPluginLoader lib2(QFINDTESTDATA("elftest/corrupt2.elf64.so")); - QCOMPARE(lib2.load(), false); - QVERIFY2(lib2.errorString().contains("invalid"), qPrintable(lib2.errorString())); - - QPluginLoader lib3(QFINDTESTDATA("elftest/corrupt3.elf64.so")); - QCOMPARE(lib3.load(), false); - QVERIFY2(lib3.errorString().contains("invalid"), qPrintable(lib3.errorString())); - } else if (sizeof(void*) == 4) { - QPluginLoader libW(QFINDTESTDATA("elftest/corrupt3.elf64.so")); - QCOMPARE(libW.load(), false); - QVERIFY2(libW.errorString().contains("architecture"), qPrintable(libW.errorString())); - } else { - QFAIL("Please port QElfParser to this platform or blacklist this test."); - } -#endif + loadCorruptElfCommonRows(); + using H = ElfHeader *; // because I'm lazy + + newRow("section-entry-size-zero", "unexpected section entry size", [](H h) { + h->e_shentsize = 0; + }); + newRow("section-entry-small", "unexpected section entry size", [](H h) { + h->e_shentsize = alignof(ElfShdr); + }); + newRow("section-entry-misaligned", "unexpected section entry size", [](H h) { + ++h->e_shentsize; + }); + newRow("no-sections", "is not a Qt plugin (metadata not found)", [](H h){ + h->e_shnum = h->e_shoff = h->e_shstrndx = 0; + }); + + // section table tests + newRow("section-table-starts-past-eof", "section table extends past the end of the file", + [](H h, QFile *f) { + h->e_shoff = f->size(); + }); + newRow("section-table-ends-past-eof", "section table extends past the end of the file", + [](H h, QFile *f) { + h->e_shoff = f->size() + 1 - h->e_shentsize * h->e_shnum; + }); + + static auto getSection = +[](H h, int index) { + auto sections = reinterpret_cast<ElfShdr *>(h->e_shoff + reinterpret_cast<uchar *>(h)); + return sections + index; + }; + + // arbitrary section bounds checks + // section index = 0 is usually a NULL section, so we try 1 + newRow("section1-starts-past-eof", "section contents extend past the end of the file", + [](H h, QFile *f) { + ElfShdr *s = getSection(h, 1); + s->sh_offset = f->size(); + }); + newRow("section1-ends-past-eof", "section contents extend past the end of the file", + [](H h, QFile *f) { + ElfShdr *s = getSection(h, 1); + s->sh_size = f->size() + 1 - s->sh_offset; + }); + newRow("section1-bounds-overflow", "section contents extend past the end of the file", [](H h) { + ElfShdr *s = getSection(h, 1); + s->sh_size = -sizeof(*s); + }); + + // section header string table tests + newRow("shstrndx-invalid", "e_shstrndx greater than the number of sections", [](H h) { + h->e_shstrndx = h->e_shnum; + }); + newRow("shstrtab-starts-past-eof", "section header string table extends past the end of the file", + [](H h, QFile *f) { + ElfShdr *s = getSection(h, h->e_shstrndx); + s->sh_offset = f->size(); + }); + newRow("shstrtab-ends-past-eof", "section header string table extends past the end of the file", + [](H h, QFile *f) { + ElfShdr *s = getSection(h, h->e_shstrndx); + s->sh_size = f->size() + 1 - s->sh_offset; + }); + newRow("shstrtab-bounds-overflow", "section header string table extends past the end of the file", [](H h) { + ElfShdr *s = getSection(h, h->e_shstrndx); + s->sh_size = -sizeof(*s); + }); + newRow("section-name-past-eof", "section name extends past the end of the file", [](H h, QFile *f) { + ElfShdr *section1 = getSection(h, 1); + ElfShdr *shstrtab = getSection(h, h->e_shstrndx); + section1->sh_name = f->size() - shstrtab->sh_offset; + }); + newRow("section-name-past-end-of-shstrtab", "section name extends past the end of the file", [](H h) { + ElfShdr *section1 = getSection(h, 1); + ElfShdr *shstrtab = getSection(h, h->e_shstrndx); + section1->sh_name = shstrtab->sh_size; + }); + + newRow("debug-symbols", "metadata not found", [](H h) { + // attempt to make it look like extracted debug info + for (int i = 1; i < h->e_shnum; ++i) { + ElfShdr *s = getSection(h, i); + if (s->sh_type == SHT_NOBITS) + break; + if (s->sh_type != SHT_NOTE && s->sh_flags & SHF_ALLOC) + s->sh_type = SHT_NOBITS; + } + }); + + // we don't know which section is .qtmetadata, so we just apply to all of them + static auto applyToAllSectionFlags = +[](H h, int flag) { + for (int i = 0; i < h->e_shnum; ++i) + getSection(h, i)->sh_flags |= flag; + }; + newRow("qtmetadata-executable", ".qtmetadata section is executable", [](H h) { + applyToAllSectionFlags(h, SHF_EXECINSTR); + }); + newRow("qtmetadata-writable", ".qtmetadata section is writable", [](H h) { + applyToAllSectionFlags(h, SHF_WRITE); + }); } +void tst_QPluginLoader::loadCorruptElfOldPlugin() +{ + // ### Qt7: don't forget to remove theoldplugin from the build + loadCorruptElf_helper(sys_qualifiedLibraryName("theoldplugin")); +} +# endif // Qt 7 +#endif // Q_OF_ELF + void tst_QPluginLoader::loadMachO_data() { #if defined(QT_BUILD_INTERNAL) && defined(Q_OF_MACH_O) - QTest::addColumn<int>("parseResult"); + QTest::addColumn<bool>("success"); - QTest::newRow("/dev/null") << int(QMachOParser::NotSuitable); - QTest::newRow("elftest/debugobj.so") << int(QMachOParser::NotSuitable); - QTest::newRow("tst_qpluginloader.cpp") << int(QMachOParser::NotSuitable); - QTest::newRow("tst_qpluginloader") << int(QMachOParser::NotSuitable); + QTest::newRow("/dev/null") << false; + QTest::newRow("elftest/debugobj.so") << false; + QTest::newRow("tst_qpluginloader.cpp") << false; + QTest::newRow("tst_qpluginloader") << false; # ifdef Q_PROCESSOR_X86_64 - QTest::newRow("machtest/good.x86_64.dylib") << int(QMachOParser::QtMetaDataSection); - QTest::newRow("machtest/good.i386.dylib") << int(QMachOParser::NotSuitable); - QTest::newRow("machtest/good.fat.no-x86_64.dylib") << int(QMachOParser::NotSuitable); - QTest::newRow("machtest/good.fat.no-i386.dylib") << int(QMachOParser::QtMetaDataSection); -# elif defined(Q_PROCESSOR_X86_32) - QTest::newRow("machtest/good.i386.dylib") << int(QMachOParser::QtMetaDataSection); - QTest::newRow("machtest/good.x86_64.dylib") << int(QMachOParser::NotSuitable); - QTest::newRow("machtest/good.fat.no-i386.dylib") << int(QMachOParser::NotSuitable); - QTest::newRow("machtest/good.fat.no-x86_64.dylib") << int(QMachOParser::QtMetaDataSection); -# endif -# ifndef Q_PROCESSOR_POWER_64 - QTest::newRow("machtest/good.ppc64.dylib") << int(QMachOParser::NotSuitable); + QTest::newRow("machtest/good.x86_64.dylib") << true; + QTest::newRow("machtest/good.arm64.dylib") << false; + QTest::newRow("machtest/good.fat.no-x86_64.dylib") << false; + QTest::newRow("machtest/good.fat.no-arm64.dylib") << true; +# elif defined(Q_PROCESSOR_ARM) + QTest::newRow("machtest/good.arm64.dylib") << true; + QTest::newRow("machtest/good.x86_64.dylib") << false; + QTest::newRow("machtest/good.fat.no-arm64.dylib") << false; + QTest::newRow("machtest/good.fat.no-x86_64.dylib") << true; # endif - QTest::newRow("machtest/good.fat.all.dylib") << int(QMachOParser::QtMetaDataSection); - QTest::newRow("machtest/good.fat.stub-x86_64.dylib") << int(QMachOParser::NotSuitable); - QTest::newRow("machtest/good.fat.stub-i386.dylib") << int(QMachOParser::NotSuitable); + QTest::newRow("machtest/good.fat.all.dylib") << true; + QTest::newRow("machtest/good.fat.stub-x86_64.dylib") << false; + QTest::newRow("machtest/good.fat.stub-arm64.dylib") << false; QDir d(QFINDTESTDATA("machtest")); - QStringList badlist = d.entryList(QStringList() << "bad*.dylib"); - foreach (const QString &bad, badlist) - QTest::newRow(qPrintable("machtest/" + bad)) << int(QMachOParser::NotSuitable); + const QStringList badlist = d.entryList(QStringList() << "bad*.dylib"); + for (const QString &bad : badlist) + QTest::newRow(qPrintable("machtest/" + bad)) << false; #endif } @@ -369,60 +888,49 @@ void tst_QPluginLoader::loadMachO() QVERIFY(f.open(QIODevice::ReadOnly)); QByteArray data = f.readAll(); - qsizetype pos; - qsizetype len; - QString errorString; - int r = QMachOParser::parse(data.constData(), data.size(), f.fileName(), &errorString, &pos, &len); - - QFETCH(int, parseResult); - QCOMPARE(r, parseResult); + QString errorString = f.fileName(); + QLibraryScanResult r = QMachOParser::parse(data.constData(), data.size(), &errorString); - if (r == QMachOParser::NotSuitable) + QFETCH(bool, success); + if (success) { + QVERIFY(r.length != 0); + } else { + QCOMPARE(r.length, 0); return; + } - QVERIFY(pos > 0); - QVERIFY(len >= sizeof(void*)); - QVERIFY(pos + long(len) < data.size()); - QCOMPARE(pos & (sizeof(void*) - 1), 0UL); - - void *value = *(void**)(data.constData() + pos); - QCOMPARE(value, sizeof(void*) > 4 ? (void*)(0xc0ffeec0ffeeL) : (void*)0xc0ffee); + QVERIFY(r.pos > 0); + QVERIFY(r.pos + r.length < data.size()); // now that we know it's valid, let's try to make it invalid - ulong offeredlen = pos; + ulong offeredlen = r.pos; do { --offeredlen; - r = QMachOParser::parse(data.constData(), offeredlen, f.fileName(), &errorString, &pos, &len); - QVERIFY2(r == QMachOParser::NotSuitable, qPrintable(QString("Failed at size 0x%1").arg(offeredlen, 0, 16))); + errorString = f.fileName(); + r = QMachOParser::parse(data.constData(), offeredlen, &errorString); + QVERIFY2(r.length == 0, qPrintable(QString("Failed at size 0x%1").arg(offeredlen, 0, 16))); } while (offeredlen); #endif } -#if defined (Q_OS_UNIX) -void tst_QPluginLoader::loadGarbage() -{ -#if !defined(QT_SHARED) - QSKIP("This test requires a shared build of Qt, as QPluginLoader::setFileName is a no-op in static builds"); -#endif - for (int i=0; i<5; i++) { - const QString name = QLatin1String("elftest/garbage") + QString::number(i + 1) + QLatin1String(".so"); - QPluginLoader lib(QFINDTESTDATA(name)); - QCOMPARE(lib.load(), false); - QVERIFY(lib.errorString() != QString("Unknown error")); - } -} -#endif - void tst_QPluginLoader::relativePath() { #if !defined(QT_SHARED) QSKIP("This test requires Qt to create shared libraries."); #endif +#ifdef Q_OS_ANDROID + // On Android we do not need to explicitly set library paths, as they are + // already set. + // But we need to use ARCH suffix in pulgin name + const QString pluginName("theplugin_" ANDROID_ARCH SUFFIX); +#else // Windows binaries run from release and debug subdirs, so we can't rely on the current dir. const QString binDir = QFINDTESTDATA("bin"); QVERIFY(!binDir.isEmpty()); QCoreApplication::addLibraryPath(binDir); - QPluginLoader loader("theplugin"); + const QString pluginName("theplugin" SUFFIX); +#endif + QPluginLoader loader(pluginName); loader.load(); // not recommended, instance() should do the job. PluginInterface *instance = qobject_cast<PluginInterface*>(loader.instance()); QVERIFY(instance); @@ -435,13 +943,27 @@ void tst_QPluginLoader::absolutePath() #if !defined(QT_SHARED) QSKIP("This test requires Qt to create shared libraries."); #endif +#ifdef Q_OS_ANDROID + // On Android we need to clear library paths to make sure that the absolute + // path works + const QStringList libraryPaths = QCoreApplication::libraryPaths(); + QVERIFY(!libraryPaths.isEmpty()); + QCoreApplication::setLibraryPaths(QStringList()); + const QString pluginPath(libraryPaths.first() + "/" PREFIX "theplugin_" ANDROID_ARCH SUFFIX); +#else // Windows binaries run from release and debug subdirs, so we can't rely on the current dir. const QString binDir = QFINDTESTDATA("bin"); QVERIFY(!binDir.isEmpty()); QVERIFY(QDir::isAbsolutePath(binDir)); - QPluginLoader loader(binDir + "/theplugin"); + const QString pluginPath(binDir + "/" PREFIX "theplugin" SUFFIX); +#endif + QPluginLoader loader(pluginPath); loader.load(); // not recommended, instance() should do the job. PluginInterface *instance = qobject_cast<PluginInterface*>(loader.instance()); +#ifdef Q_OS_ANDROID + // Restore library paths + QCoreApplication::setLibraryPaths(libraryPaths); +#endif QVERIFY(instance); QCOMPARE(instance->pluginName(), QLatin1String("Plugin ok")); QVERIFY(loader.unload()); @@ -462,7 +984,7 @@ void tst_QPluginLoader::reloadPlugin() QSignalSpy spy(loader.instance(), &QObject::destroyed); QVERIFY(spy.isValid()); QVERIFY(loader.unload()); // refcount reached 0, did really unload - QCOMPARE(spy.count(), 1); + QCOMPARE(spy.size(), 1); // reload plugin QVERIFY(loader.load()); @@ -475,6 +997,54 @@ void tst_QPluginLoader::reloadPlugin() QVERIFY(loader.unload()); } +void tst_QPluginLoader::loadSectionTableStrippedElf() +{ +#ifdef Q_OS_ANDROID + if (QNativeInterface::QAndroidApplication::sdkVersion() >= 24) + QSKIP("Android 7+ (API 24+) linker doesn't allow missing or bad section header"); +#endif +#if !defined(QT_SHARED) + QSKIP("This test requires a shared build of Qt, as QPluginLoader::setFileName is a no-op in static builds"); +#elif !defined(Q_OF_ELF) + QSKIP("Test specific to the ELF file format"); +#else + ElfPatcher patcher { [](ElfHeader *header, QFile *f) { + // modify the header to make it look like the section table was stripped + header->e_shoff = header->e_shnum = header->e_shstrndx = 0; + + // and append a bad header at the end + QPluginMetaData::MagicHeader badHeader = {}; + --badHeader.header.qt_major_version; + f->seek(f->size()); + f->write(reinterpret_cast<const char *>(&badHeader), sizeof(badHeader)); + } }; + + QString tmpLibName; + { + std::unique_ptr<QTemporaryFile> tmplib = + patchElf(sys_qualifiedLibraryName("theplugin"), patcher); + + tmpLibName = tmplib->fileName(); + tmplib->setAutoRemove(false); + } +#if defined(Q_OS_QNX) + // On QNX plugin access is still too early, even when QTemporaryFile is closed + QTest::qSleep(1000); +#endif + auto removeTmpLib = qScopeGuard([=]{ + QFile::remove(tmpLibName); + }); + + // now attempt to load it + QPluginLoader loader(tmpLibName); + QVERIFY2(loader.load(), qPrintable(loader.errorString())); + PluginInterface *instance = qobject_cast<PluginInterface*>(loader.instance()); + QVERIFY(instance); + QCOMPARE(instance->pluginName(), QLatin1String("Plugin ok")); + QVERIFY(loader.unload()); +#endif +} + void tst_QPluginLoader::preloadedPlugin_data() { QTest::addColumn<bool>("doLoad"); @@ -520,5 +1090,50 @@ void tst_QPluginLoader::preloadedPlugin() QVERIFY(lib.unload()); } +void tst_QPluginLoader::staticPlugins() +{ + const QObjectList instances = QPluginLoader::staticInstances(); + QVERIFY(instances.size()); + + // ensure the our plugin only shows up once + int foundCount = std::count_if(instances.begin(), instances.end(), [](QObject *obj) { + return obj->metaObject()->className() == QLatin1String("StaticPlugin"); + }); + QCOMPARE(foundCount, 1); + + const auto plugins = QPluginLoader::staticPlugins(); + QCOMPARE(plugins.size(), instances.size()); + + // find the metadata + QJsonObject metaData; + bool found = false; + for (const auto &p : plugins) { + metaData = p.metaData(); + found = metaData.value("className").toString() == QLatin1String("StaticPlugin"); + if (found) + break; + } + QVERIFY(found); + + // We don't store the patch release version anymore (since 5.13) + QCOMPARE(metaData.value("version").toInt() / 0x100, QT_VERSION / 0x100); + QCOMPARE(metaData.value("IID").toString(), "SomeIID"); + QCOMPARE(metaData.value("ExtraMetaData"), QJsonArray({ "StaticPlugin", "foo" })); + QCOMPARE(metaData.value("URI").toString(), "qt.test.pluginloader.staticplugin"); +} + +void tst_QPluginLoader::reregisteredStaticPlugins() +{ + // the Q_IMPORT_PLUGIN macro will have already done this + qRegisterStaticPluginFunction(qt_static_plugin_StaticPlugin()); + staticPlugins(); + if (QTest::currentTestFailed()) + return; + + qRegisterStaticPluginFunction(qt_static_plugin_StaticPlugin()); + staticPlugins(); +} + + QTEST_MAIN(tst_QPluginLoader) #include "tst_qpluginloader.moc" diff --git a/tests/auto/corelib/plugin/qpluginloader/winrt.pri b/tests/auto/corelib/plugin/qpluginloader/winrt.pri deleted file mode 100644 index 31602634b2..0000000000 --- a/tests/auto/corelib/plugin/qpluginloader/winrt.pri +++ /dev/null @@ -1,9 +0,0 @@ -# We cannot use TESTDATA as plugins have to reside physically -# inside the package directory -winrt { - CONFIG(debug, debug|release) { - DESTDIR = ../debug/bin - } else { - DESTDIR = ../release/bin - } -} diff --git a/tests/auto/corelib/plugin/quuid/CMakeLists.txt b/tests/auto/corelib/plugin/quuid/CMakeLists.txt new file mode 100644 index 0000000000..be90dc1849 --- /dev/null +++ b/tests/auto/corelib/plugin/quuid/CMakeLists.txt @@ -0,0 +1,11 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_quuid LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + +add_subdirectory(testProcessUniqueness) +add_subdirectory(test) diff --git a/tests/auto/corelib/plugin/quuid/quuid.pro b/tests/auto/corelib/plugin/quuid/quuid.pro deleted file mode 100644 index 25e24561ae..0000000000 --- a/tests/auto/corelib/plugin/quuid/quuid.pro +++ /dev/null @@ -1,6 +0,0 @@ -TEMPLATE = subdirs - -SUBDIRS = testProcessUniqueness - -SUBDIRS += test - diff --git a/tests/auto/corelib/plugin/quuid/test/CMakeLists.txt b/tests/auto/corelib/plugin/quuid/test/CMakeLists.txt new file mode 100644 index 0000000000..ec6c1979f7 --- /dev/null +++ b/tests/auto/corelib/plugin/quuid/test/CMakeLists.txt @@ -0,0 +1,28 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## tst_quuid Test: +##################################################################### + +qt_internal_add_test(tst_quuid + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/../" + SOURCES + ../tst_quuid.cpp + LIBRARIES + Qt::TestPrivate +) + +## Scopes: + +qt_internal_extend_target(tst_quuid CONDITION APPLE + SOURCES + ../tst_quuid_darwin.mm + LIBRARIES + Qt::CorePrivate + ${FWFoundation} +) + +if(QT_FEATURE_process AND NOT ANDROID) + add_dependencies(tst_quuid testProcessUniqueness) +endif() diff --git a/tests/auto/corelib/plugin/quuid/test/test.pro b/tests/auto/corelib/plugin/quuid/test/test.pro deleted file mode 100644 index 562bfbdc25..0000000000 --- a/tests/auto/corelib/plugin/quuid/test/test.pro +++ /dev/null @@ -1,19 +0,0 @@ -CONFIG += testcase -TARGET = tst_quuid -QT = core testlib -SOURCES = ../tst_quuid.cpp - -darwin { - OBJECTIVE_SOURCES = ../tst_quuid_darwin.mm - LIBS += -framework Foundation -} - -CONFIG(debug_and_release_target) { - CONFIG(debug, debug|release) { - DESTDIR = ../debug - } else { - DESTDIR = ../release - } -} else { - DESTDIR = .. -} diff --git a/tests/auto/corelib/plugin/quuid/testProcessUniqueness/CMakeLists.txt b/tests/auto/corelib/plugin/quuid/testProcessUniqueness/CMakeLists.txt new file mode 100644 index 0000000000..f207cdaa3a --- /dev/null +++ b/tests/auto/corelib/plugin/quuid/testProcessUniqueness/CMakeLists.txt @@ -0,0 +1,15 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +##################################################################### +## testProcessUniqueness Binary: +##################################################################### + +qt_internal_add_executable(testProcessUniqueness + INSTALL_DIRECTORY "${INSTALL_TESTSDIR}/tst_quuid/testProcessUniqueness" + OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/" + SOURCES + main.cpp +) + +set_target_properties(testProcessUniqueness PROPERTIES MACOSX_BUNDLE TRUE) diff --git a/tests/auto/corelib/plugin/quuid/testProcessUniqueness/main.cpp b/tests/auto/corelib/plugin/quuid/testProcessUniqueness/main.cpp index d1e138d8eb..93d1201631 100644 --- a/tests/auto/corelib/plugin/quuid/testProcessUniqueness/main.cpp +++ b/tests/auto/corelib/plugin/quuid/testProcessUniqueness/main.cpp @@ -1,30 +1,5 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <stdio.h> #include <QUuid> @@ -32,8 +7,8 @@ // This is a testcase for QTBUG-11213 int main(int argc, char **argv) { - Q_UNUSED(argc) - Q_UNUSED(argv) + Q_UNUSED(argc); + Q_UNUSED(argv); // Now print a few uuids. printf("%s", qPrintable(QUuid::createUuid().toString())); diff --git a/tests/auto/corelib/plugin/quuid/testProcessUniqueness/testProcessUniqueness.pro b/tests/auto/corelib/plugin/quuid/testProcessUniqueness/testProcessUniqueness.pro deleted file mode 100644 index 5ee7b1a21f..0000000000 --- a/tests/auto/corelib/plugin/quuid/testProcessUniqueness/testProcessUniqueness.pro +++ /dev/null @@ -1,9 +0,0 @@ -SOURCES = main.cpp -QT = core -CONFIG += console - -DESTDIR = ./ - -# This app is testdata for tst_quuid -target.path = $$[QT_INSTALL_TESTS]/tst_quuid/$$TARGET -INSTALLS += target diff --git a/tests/auto/corelib/plugin/quuid/tst_quuid.cpp b/tests/auto/corelib/plugin/quuid/tst_quuid.cpp index 16552059dd..08a5b826e9 100644 --- a/tests/auto/corelib/plugin/quuid/tst_quuid.cpp +++ b/tests/auto/corelib/plugin/quuid/tst_quuid.cpp @@ -1,33 +1,12 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - - -#include <QtTest/QtTest> +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + + +#include <QTest> +#include <QtTest/private/qcomparisontesthelper_p.h> +#if QT_CONFIG(process) +#include <QProcess> +#endif #include <qcoreapplication.h> #include <quuid.h> @@ -39,6 +18,7 @@ class tst_QUuid : public QObject private slots: void initTestCase(); + void compareCompiles(); void fromChar(); void toString(); void fromString_data(); @@ -47,6 +27,8 @@ private slots: void fromByteArray(); void toRfc4122(); void fromRfc4122(); + void id128(); + void uint128(); void createUuidV3OrV5(); void check_QDataStream(); void isNull(); @@ -109,20 +91,28 @@ void tst_QUuid::initTestCase() uuidD = QUuid(0x21f7f8de, 0x8051, 0x5b89, 0x86, 0x80, 0x01, 0x95, 0xef, 0x79, 0x8b, 0x6a); } +void tst_QUuid::compareCompiles() +{ + QTestPrivate::testAllComparisonOperatorsCompile<QUuid>(); +#if defined(Q_OS_WIN) + QTestPrivate::testEqualityOperatorsCompile<QUuid, GUID>(); +#endif +} + void tst_QUuid::fromChar() { - QCOMPARE(uuidA, QUuid("{fc69b59e-cc34-4436-a43c-ee95d128b8c5}")); - QCOMPARE(uuidA, QUuid("fc69b59e-cc34-4436-a43c-ee95d128b8c5}")); - QCOMPARE(uuidA, QUuid("{fc69b59e-cc34-4436-a43c-ee95d128b8c5")); - QCOMPARE(uuidA, QUuid("fc69b59e-cc34-4436-a43c-ee95d128b8c5")); - QCOMPARE(QUuid(), QUuid("{fc69b59e-cc34-4436-a43c-ee95d128b8c")); - QCOMPARE(QUuid(), QUuid("{fc69b59e-cc34")); - QCOMPARE(QUuid(), QUuid("fc69b59e-cc34-")); - QCOMPARE(QUuid(), QUuid("fc69b59e-cc34")); - QCOMPARE(QUuid(), QUuid("cc34")); - QCOMPARE(QUuid(), QUuid(NULL)); - - QCOMPARE(uuidB, QUuid(QString("{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}"))); + QT_TEST_EQUALITY_OPS(uuidA, QUuid("{fc69b59e-cc34-4436-a43c-ee95d128b8c5}"), true); + QT_TEST_EQUALITY_OPS(uuidA, QUuid("fc69b59e-cc34-4436-a43c-ee95d128b8c5}"), true); + QT_TEST_EQUALITY_OPS(uuidA, QUuid("{fc69b59e-cc34-4436-a43c-ee95d128b8c5"), true); + QT_TEST_EQUALITY_OPS(uuidA, QUuid("fc69b59e-cc34-4436-a43c-ee95d128b8c5"), true); + QT_TEST_EQUALITY_OPS(QUuid(), QUuid("{fc69b59e-cc34-4436-a43c-ee95d128b8c"), true); + QT_TEST_EQUALITY_OPS(QUuid(), QUuid("{fc69b59e-cc34"), true); + QT_TEST_EQUALITY_OPS(QUuid(), QUuid("fc69b59e-cc34-"), true); + QT_TEST_EQUALITY_OPS(QUuid(), QUuid("fc69b59e-cc34"), true); + QT_TEST_EQUALITY_OPS(QUuid(), QUuid("cc34"), true); + QT_TEST_EQUALITY_OPS(QUuid(), QUuid(nullptr), true); + + QT_TEST_EQUALITY_OPS(uuidB, QUuid(QString("{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}")), true); } void tst_QUuid::toString() @@ -157,7 +147,7 @@ void tst_QUuid::fromString_data() ROW(uuidA, "{fc69b59e-cc34-4436-a43c-ee95d128b8c56"); // too long (not an error!) ROW(invalid, "{fc69b59e-cc34-4436-a43c-ee95d128b8c" ); // premature end (within length limits) ROW(invalid, " fc69b59e-cc34-4436-a43c-ee95d128b8c5}"); // leading space - ROW(uuidA, "{fc69b59e-cc34-4436-a43c-ee95d128b8c5 "); // trailing space (not an error!) + ROW(uuidB, "{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b "); // trailing space (not an error!) ROW(invalid, "{gc69b59e-cc34-4436-a43c-ee95d128b8c5}"); // non-hex digit in 1st group ROW(invalid, "{fc69b59e-cp34-4436-a43c-ee95d128b8c5}"); // non-hex digit in 2nd group ROW(invalid, "{fc69b59e-cc34-44r6-a43c-ee95d128b8c5}"); // non-hex digit in 3rd group @@ -182,16 +172,21 @@ void tst_QUuid::fromString() const auto inputL1 = input.toLatin1(); const auto inputU8 = input.toUtf8(); - QCOMPARE(expected, QUuid(input)); - QCOMPARE(expected, QUuid(inputU8)); - QCOMPARE(expected, QUuid(inputL1)); + QT_TEST_EQUALITY_OPS(expected, QUuid(input), true); + QT_TEST_EQUALITY_OPS(expected, QUuid(inputU8), true); + QT_TEST_EQUALITY_OPS(expected, QUuid(inputL1), true); - QCOMPARE(expected, QUuid::fromString(input)); + QT_TEST_EQUALITY_OPS(expected, QUuid::fromString(input), true); // for QLatin1String, construct one whose data() is not NUL-terminated: const auto longerInputL1 = inputL1 + '5'; // the '5' makes the premature end check incorrectly succeed const auto inputL1S = QLatin1String(longerInputL1.data(), inputL1.size()); - QCOMPARE(expected, QUuid::fromString(inputL1S)); + QT_TEST_EQUALITY_OPS(expected, QUuid::fromString(inputL1S), true); + + // for QUtf8StringView, too: + const auto longerInputU8 = inputU8 + '5'; // the '5' makes the premature end check incorrectly succeed + const auto inputU8S = QUtf8StringView(longerInputU8.data(), inputU8.size()); + QT_TEST_EQUALITY_OPS(expected, QUuid::fromString(inputU8S), true); } void tst_QUuid::toByteArray() @@ -211,37 +206,112 @@ void tst_QUuid::toByteArray() void tst_QUuid::fromByteArray() { - QCOMPARE(uuidA, QUuid(QByteArray("{fc69b59e-cc34-4436-a43c-ee95d128b8c5}"))); - QCOMPARE(uuidA, QUuid(QByteArray("fc69b59e-cc34-4436-a43c-ee95d128b8c5}"))); - QCOMPARE(uuidA, QUuid(QByteArray("{fc69b59e-cc34-4436-a43c-ee95d128b8c5"))); - QCOMPARE(uuidA, QUuid(QByteArray("fc69b59e-cc34-4436-a43c-ee95d128b8c5"))); - QCOMPARE(QUuid(), QUuid(QByteArray("{fc69b59e-cc34-4436-a43c-ee95d128b8c"))); + QT_TEST_EQUALITY_OPS(uuidA, QUuid(QByteArray("{fc69b59e-cc34-4436-a43c-ee95d128b8c5}")), true); + QT_TEST_EQUALITY_OPS(uuidA, QUuid(QByteArray("fc69b59e-cc34-4436-a43c-ee95d128b8c5}")), true); + QT_TEST_EQUALITY_OPS(uuidA, QUuid(QByteArray("{fc69b59e-cc34-4436-a43c-ee95d128b8c5")), true); + QT_TEST_EQUALITY_OPS(uuidA, QUuid(QByteArray("fc69b59e-cc34-4436-a43c-ee95d128b8c5")), true); + QT_TEST_EQUALITY_OPS(QUuid(), QUuid(QByteArray("{fc69b59e-cc34-4436-a43c-ee95d128b8c")), true); - QCOMPARE(uuidB, QUuid(QByteArray("{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}"))); + QT_TEST_EQUALITY_OPS(uuidB, QUuid(QByteArray("{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}")), true); } void tst_QUuid::toRfc4122() { QCOMPARE(uuidA.toRfc4122(), QByteArray::fromHex("fc69b59ecc344436a43cee95d128b8c5")); - QCOMPARE(uuidB.toRfc4122(), QByteArray::fromHex("1ab6e93ab1cb4a87ba47ec7e99039a7b")); } void tst_QUuid::fromRfc4122() { - QCOMPARE(uuidA, QUuid::fromRfc4122(QByteArray::fromHex("fc69b59ecc344436a43cee95d128b8c5"))); + QT_TEST_EQUALITY_OPS( + uuidA, + QUuid::fromRfc4122(QByteArray::fromHex("fc69b59ecc344436a43cee95d128b8c5")), true); + + QT_TEST_EQUALITY_OPS( + uuidB, QUuid::fromRfc4122(QByteArray::fromHex("1ab6e93ab1cb4a87ba47ec7e99039a7b")), + true); +} - QCOMPARE(uuidB, QUuid::fromRfc4122(QByteArray::fromHex("1ab6e93ab1cb4a87ba47ec7e99039a7b"))); +void tst_QUuid::id128() +{ + constexpr QUuid::Id128Bytes bytesA = { { + 0xfc, 0x69, 0xb5, 0x9e, + 0xcc, 0x34, + 0x44, 0x36, + 0xa4, 0x3c, 0xee, 0x95, 0xd1, 0x28, 0xb8, 0xc5, + } }; + constexpr QUuid::Id128Bytes bytesB = { { + 0x1a, 0xb6, 0xe9, 0x3a, + 0xb1, 0xcb, + 0x4a, 0x87, + 0xba, 0x47, 0xec, 0x7e, 0x99, 0x03, 0x9a, 0x7b, + } }; + + QT_TEST_EQUALITY_OPS(QUuid(bytesA), uuidA, true); + QT_TEST_EQUALITY_OPS(QUuid(bytesB), uuidB, true); + QVERIFY(memcmp(uuidA.toBytes().data, bytesA.data, sizeof(QUuid::Id128Bytes)) == 0); + QVERIFY(memcmp(uuidB.toBytes().data, bytesB.data, sizeof(QUuid::Id128Bytes)) == 0); + + QUuid::Id128Bytes leBytesA = {}; + for (int i = 0; i < 16; i++) + leBytesA.data[15 - i] = bytesA.data[i]; + QT_TEST_EQUALITY_OPS(QUuid(leBytesA, QSysInfo::LittleEndian), uuidA, true); + QVERIFY(memcmp(uuidA.toBytes(QSysInfo::LittleEndian).data, leBytesA.data, sizeof(leBytesA)) == 0); + + // check the new q{To,From}{Big,Little}Endian() overloads + QUuid::Id128Bytes roundtrip = qFromLittleEndian(qToLittleEndian(bytesA)); + QVERIFY(memcmp(roundtrip.data, bytesA.data, sizeof(bytesA)) == 0); + roundtrip = qFromBigEndian(qToBigEndian(bytesA)); + QVERIFY(memcmp(roundtrip.data, bytesA.data, sizeof(bytesA)) == 0); +#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN + const QUuid::Id128Bytes beBytesA = qToBigEndian(leBytesA); + QVERIFY(memcmp(beBytesA.data, bytesA.data, sizeof(beBytesA)) == 0); + const QUuid::Id128Bytes otherLeBytesA = qFromBigEndian(bytesA); + QVERIFY(memcmp(otherLeBytesA.data, leBytesA.data, sizeof(leBytesA)) == 0); +#else // Q_BIG_ENDIAN + const QUuid::Id128Bytes otherLeBytesA = qToLittleEndian(bytesA); + QVERIFY(memcmp(otherLeBytesA.data, leBytesA.data, sizeof(leBytesA)) == 0); + const QUuid::Id128Bytes beBytesA = qFromLittleEndian(leBytesA); + QVERIFY(memcmp(beBytesA.data, bytesA.data, sizeof(beBytesA)) == 0); +#endif // Q_BYTE_ORDER == Q_LITTLE_ENDIAN +} + +void tst_QUuid::uint128() +{ +#ifdef QT_SUPPORTS_INT128 + constexpr quint128 u = Q_UINT128_C(0xfc69b59e'cc344436'a43cee95'd128b8c5); // This is LE + constexpr quint128 be = qToBigEndian(u); + constexpr QUuid uuid = QUuid::fromUInt128(be); + static_assert(uuid.toUInt128() == be, "Round-trip through QUuid failed"); + + QT_TEST_EQUALITY_OPS(uuid, uuidA, true); + QCOMPARE(uuid.toUInt128(), be); + + quint128 le = qFromBigEndian(be); + QCOMPARE(uuid.toUInt128(QSysInfo::LittleEndian), le); + QT_TEST_EQUALITY_OPS(QUuid::fromUInt128(le, QSysInfo::LittleEndian), uuidA, true); + + QUuid::Id128Bytes bytes = { .data128 = { qToBigEndian(u) } }; + QUuid uuid2(bytes); + QT_TEST_EQUALITY_OPS(uuid2, uuid, true); + + // verify that toBytes() and toUInt128() provide bytewise similar result + constexpr quint128 val = uuid.toUInt128(); + bytes = uuid.toBytes(); + QVERIFY(memcmp(&val, bytes.data, sizeof(val)) == 0); +#else + QSKIP("This platform has no support for 128-bit integer"); +#endif } void tst_QUuid::createUuidV3OrV5() { //"www.widgets.com" is also from RFC4122 - QCOMPARE(uuidC, QUuid::createUuidV3(uuidNS, QByteArray("www.widgets.com"))); - QCOMPARE(uuidC, QUuid::createUuidV3(uuidNS, QString("www.widgets.com"))); + QT_TEST_EQUALITY_OPS(uuidC, QUuid::createUuidV3(uuidNS, QByteArray("www.widgets.com")), true); + QT_TEST_EQUALITY_OPS(uuidC, QUuid::createUuidV3(uuidNS, QString("www.widgets.com")), true); - QCOMPARE(uuidD, QUuid::createUuidV5(uuidNS, QByteArray("www.widgets.com"))); - QCOMPARE(uuidD, QUuid::createUuidV5(uuidNS, QString("www.widgets.com"))); + QT_TEST_EQUALITY_OPS(uuidD, QUuid::createUuidV5(uuidNS, QByteArray("www.widgets.com")), true); + QT_TEST_EQUALITY_OPS(uuidD, QUuid::createUuidV5(uuidNS, QString("www.widgets.com")), true); } void tst_QUuid::check_QDataStream() @@ -257,7 +327,7 @@ void tst_QUuid::check_QDataStream() QDataStream in(&ar,QIODevice::ReadOnly); in.setByteOrder(QDataStream::BigEndian); in >> tmp; - QCOMPARE(uuidA, tmp); + QT_TEST_EQUALITY_OPS(uuidA, tmp, true); } { QDataStream out(&ar,QIODevice::WriteOnly); @@ -268,7 +338,7 @@ void tst_QUuid::check_QDataStream() QDataStream in(&ar,QIODevice::ReadOnly); in.setByteOrder(QDataStream::LittleEndian); in >> tmp; - QCOMPARE(uuidA, tmp); + QT_TEST_EQUALITY_OPS(uuidA, tmp, true); } } @@ -283,14 +353,14 @@ void tst_QUuid::isNull() void tst_QUuid::equal() { - QVERIFY( !(uuidA == uuidB) ); + QT_TEST_EQUALITY_OPS(uuidA, uuidB, false); QUuid copy(uuidA); - QCOMPARE(uuidA, copy); + QT_TEST_EQUALITY_OPS(uuidA, copy, true); QUuid assigned; assigned = uuidA; - QCOMPARE(uuidA, assigned); + QT_TEST_EQUALITY_OPS(uuidA, assigned, true); } @@ -302,8 +372,8 @@ void tst_QUuid::notEqual() void tst_QUuid::cpp11() { #ifdef Q_COMPILER_UNIFORM_INIT // "{fc69b59e-cc34-4436-a43c-ee95d128b8c5}" cf, initTestCase - Q_DECL_CONSTEXPR QUuid u1{0xfc69b59e, 0xcc34, 0x4436, 0xa4, 0x3c, 0xee, 0x95, 0xd1, 0x28, 0xb8, 0xc5}; - Q_DECL_CONSTEXPR QUuid u2 = {0xfc69b59e, 0xcc34, 0x4436, 0xa4, 0x3c, 0xee, 0x95, 0xd1, 0x28, 0xb8, 0xc5}; + constexpr QUuid u1{0xfc69b59e, 0xcc34, 0x4436, 0xa4, 0x3c, 0xee, 0x95, 0xd1, 0x28, 0xb8, 0xc5}; + constexpr QUuid u2 = {0xfc69b59e, 0xcc34, 0x4436, 0xa4, 0x3c, 0xee, 0x95, 0xd1, 0x28, 0xb8, 0xc5}; Q_UNUSED(u1); Q_UNUSED(u2); #else @@ -327,10 +397,12 @@ void tst_QUuid::less() QVERIFY( uuidB <= uuidA); QVERIFY(!(uuidA < uuidB) ); QVERIFY(!(uuidA <= uuidB)); + QT_TEST_ALL_COMPARISON_OPS(uuidB, uuidA, Qt::strong_ordering::less); QUuid null_uuid; QVERIFY(null_uuid < uuidA); // Null uuid is always less than a valid one QVERIFY(null_uuid <= uuidA); + QT_TEST_ALL_COMPARISON_OPS(null_uuid, uuidA, Qt::strong_ordering::less); QVERIFY(null_uuid <= null_uuid); QVERIFY(uuidA <= uuidA); @@ -343,6 +415,7 @@ void tst_QUuid::more() QVERIFY( uuidA >= uuidB); QVERIFY(!(uuidB > uuidA)); QVERIFY(!(uuidB >= uuidA)); + QT_TEST_ALL_COMPARISON_OPS(uuidA, uuidB, Qt::strong_ordering::greater); QUuid null_uuid; QVERIFY(!(null_uuid > uuidA)); // Null uuid is always less than a valid one @@ -350,6 +423,7 @@ void tst_QUuid::more() QVERIFY(null_uuid >= null_uuid); QVERIFY(uuidA >= uuidA); + QT_TEST_ALL_COMPARISON_OPS(uuidA, uuidA, Qt::strong_ordering::equal); } @@ -358,7 +432,7 @@ void tst_QUuid::variants() QVERIFY( uuidA.variant() == QUuid::DCE ); QVERIFY( uuidB.variant() == QUuid::DCE ); - QUuid NCS = "{3a2f883c-4000-000d-0000-00fb40000000}"; + QUuid NCS("{3a2f883c-4000-000d-0000-00fb40000000}"); QVERIFY( NCS.variant() == QUuid::NCS ); } @@ -368,10 +442,10 @@ void tst_QUuid::versions() QVERIFY( uuidA.version() == QUuid::Random ); QVERIFY( uuidB.version() == QUuid::Random ); - QUuid DCE_time= "{406c45a0-3b7e-11d0-80a3-0000c08810a7}"; + QUuid DCE_time("{406c45a0-3b7e-11d0-80a3-0000c08810a7}"); QVERIFY( DCE_time.version() == QUuid::Time ); - QUuid NCS = "{3a2f883c-4000-000d-0000-00fb40000000}"; + QUuid NCS("{3a2f883c-4000-000d-0000-00fb40000000}"); QVERIFY( NCS.version() == QUuid::VerUnknown ); } @@ -380,7 +454,7 @@ class UuidThread : public QThread public: QUuid uuid; - void run() + void run() override { uuid = QUuid::createUuid(); } @@ -388,14 +462,14 @@ public: void tst_QUuid::threadUniqueness() { - QVector<UuidThread *> threads(qMax(2, QThread::idealThreadCount())); - for (int i = 0; i < threads.count(); ++i) + QList<UuidThread *> threads(qMax(2, QThread::idealThreadCount())); + for (int i = 0; i < threads.size(); ++i) threads[i] = new UuidThread; - for (int i = 0; i < threads.count(); ++i) + for (int i = 0; i < threads.size(); ++i) threads[i]->start(); - for (int i = 0; i < threads.count(); ++i) + for (int i = 0; i < threads.size(); ++i) QVERIFY(threads[i]->wait(1000)); - for (int i = 1; i < threads.count(); ++i) + for (int i = 1; i < threads.size(); ++i) QVERIFY(threads[0]->uuid != threads[i]->uuid); qDeleteAll(threads); } @@ -413,7 +487,7 @@ void tst_QUuid::processUniqueness() QString processTwoOutput; // Start it once -#ifdef Q_OS_MAC +#ifdef Q_OS_DARWIN process.start("testProcessUniqueness/testProcessUniqueness.app"); #elif defined(Q_OS_ANDROID) process.start("libtestProcessUniqueness.so"); @@ -424,7 +498,7 @@ void tst_QUuid::processUniqueness() processOneOutput = process.readAllStandardOutput(); // Start it twice -#ifdef Q_OS_MAC +#ifdef Q_OS_DARWIN process.start("testProcessUniqueness/testProcessUniqueness.app"); #elif defined(Q_OS_ANDROID) process.start("libtestProcessUniqueness.so"); @@ -441,7 +515,7 @@ void tst_QUuid::processUniqueness() void tst_QUuid::hash() { - uint h = qHash(uuidA); + size_t h = qHash(uuidA); QCOMPARE(qHash(uuidA), h); QCOMPARE(qHash(QUuid(uuidA.toString())), h); } @@ -451,11 +525,11 @@ void tst_QUuid::qvariant() QUuid uuid = QUuid::createUuid(); QVariant v = QVariant::fromValue(uuid); QVERIFY(!v.isNull()); - QCOMPARE(v.type(), QVariant::Uuid); + QCOMPARE(v.metaType(), QMetaType(QMetaType::QUuid)); QUuid uuid2 = v.value<QUuid>(); QVERIFY(!uuid2.isNull()); - QCOMPARE(uuid, uuid2); + QT_TEST_EQUALITY_OPS(uuid, uuid2, true); } void tst_QUuid::qvariant_conversion() @@ -478,16 +552,16 @@ void tst_QUuid::qvariant_conversion() // try reverse conversion QString -> QUuid QVariant sv = QVariant::fromValue(uuid.toString()); - QCOMPARE(sv.type(), QVariant::String); + QCOMPARE(sv.metaType(), QMetaType(QMetaType::QString)); QVERIFY(sv.canConvert<QUuid>()); QCOMPARE(sv.value<QUuid>(), uuid); // QString -> QUuid { QVariant sv = QVariant::fromValue(uuid.toByteArray()); - QCOMPARE(sv.type(), QVariant::ByteArray); + QCOMPARE(sv.metaType(), QMetaType(QMetaType::QByteArray)); QVERIFY(sv.canConvert<QUuid>()); - QCOMPARE(sv.value<QUuid>(), uuid); + QT_TEST_EQUALITY_OPS(sv.value<QUuid>(), uuid, true); } } diff --git a/tests/auto/corelib/plugin/quuid/tst_quuid_darwin.mm b/tests/auto/corelib/plugin/quuid/tst_quuid_darwin.mm index 41ccece115..c3fc809b1f 100644 --- a/tests/auto/corelib/plugin/quuid/tst_quuid_darwin.mm +++ b/tests/auto/corelib/plugin/quuid/tst_quuid_darwin.mm @@ -1,33 +1,10 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the test suite of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:GPL-EXCEPT$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ +// Copyright (C) 2016 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtCore/QUuid> -#include <QtTest/QtTest> +#include <QTest> + +#include <QtCore/private/qcore_mac_p.h> #include <CoreFoundation/CoreFoundation.h> #include <Foundation/Foundation.h> |