qt 6.5.1 original

This commit is contained in:
kleuter
2023-10-29 23:33:08 +01:00
parent 71d22ab6b0
commit 85d238dfda
21202 changed files with 5499099 additions and 0 deletions

View File

@ -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()

View File

@ -0,0 +1,6 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(plugin1)
add_subdirectory(plugin2)
add_subdirectory(test)

View File

@ -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)

View File

@ -0,0 +1,9 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/qstring.h>
#include "plugin1.h"
QString Plugin1::pluginName() const
{
return QLatin1String("Plugin1 ok");
}

View File

@ -0,0 +1,20 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef THEPLUGIN_H
#define THEPLUGIN_H
#include <QtCore/qobject.h>
#include <QtCore/qplugin.h>
#include "plugininterface1.h"
class Plugin1 : public QObject, public PluginInterface1
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.autotests.plugininterface1")
Q_INTERFACES(PluginInterface1)
public:
virtual QString pluginName() const override;
};
#endif // THEPLUGIN_H

View File

@ -0,0 +1,21 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef PLUGININTERFACE1_H
#define PLUGININTERFACE1_H
#include <QtCore/QtGlobal>
struct PluginInterface1 {
virtual ~PluginInterface1() {}
virtual QString pluginName() const = 0;
};
QT_BEGIN_NAMESPACE
#define PluginInterface1_iid "org.qt-project.Qt.autotests.plugininterface1"
Q_DECLARE_INTERFACE(PluginInterface1, PluginInterface1_iid)
QT_END_NAMESPACE
#endif // PLUGININTERFACE1_H

View File

@ -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)

View File

@ -0,0 +1,9 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/qstring.h>
#include "plugin2.h"
QString Plugin2::pluginName() const
{
return QLatin1String("Plugin2 ok");
}

View File

@ -0,0 +1,20 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef THEPLUGIN_H
#define THEPLUGIN_H
#include <QtCore/qobject.h>
#include <QtCore/qplugin.h>
#include "plugininterface2.h"
class Plugin2 : public QObject, public PluginInterface2
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.autotests.plugininterface2")
Q_INTERFACES(PluginInterface2)
public:
virtual QString pluginName() const override;
};
#endif // THEPLUGIN_H

View File

@ -0,0 +1,21 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef PLUGININTERFACE2_H
#define PLUGININTERFACE2_H
#include <QtCore/QtGlobal>
struct PluginInterface2 {
virtual ~PluginInterface2() {}
virtual QString pluginName() const = 0;
};
QT_BEGIN_NAMESPACE
#define PluginInterface2_iid "org.qt-project.Qt.autotests.plugininterface2"
Q_DECLARE_INTERFACE(PluginInterface2, PluginInterface2_iid)
QT_END_NAMESPACE
#endif // PLUGININTERFACE2_H

View File

@ -0,0 +1,34 @@
# 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
)
## Scopes:
#####################################################################
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()

View File

@ -0,0 +1,113 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtTest/qtest.h>
#include <QtCore/qdir.h>
#include <QtCore/qfileinfo.h>
#include <QtCore/qplugin.h>
#include <private/qfactoryloader_p.h>
#include "plugin1/plugininterface1.h"
#include "plugin2/plugininterface2.h"
#if !QT_CONFIG(library)
Q_IMPORT_PLUGIN(Plugin1)
Q_IMPORT_PLUGIN(Plugin2)
#endif
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();
};
static const char binFolderC[] = "bin";
void tst_QFactoryLoader::initTestCase()
{
// 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");
#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
const QString suffix = QLatin1Char('/') + QLatin1String(binFolderC);
QFactoryLoader loader1(PluginInterface1_iid, suffix);
PluginInterface1 *plugin1 = qobject_cast<PluginInterface1 *>(loader1.instance(0));
QVERIFY2(plugin1,
qPrintable(QString::fromLatin1("Cannot load plugin '%1'")
.arg(QLatin1String(PluginInterface1_iid))));
QFactoryLoader loader2(PluginInterface2_iid, suffix);
PluginInterface2 *plugin2 = qobject_cast<PluginInterface2 *>(loader2.instance(0));
QVERIFY2(plugin2,
qPrintable(QString::fromLatin1("Cannot load plugin '%1'")
.arg(QLatin1String(PluginInterface2_iid))));
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
}
QTEST_MAIN(tst_QFactoryLoader)
#include "tst_qfactoryloader.moc"

View File

@ -0,0 +1,6 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(lib)
add_subdirectory(lib2)
add_subdirectory(tst)

View File

@ -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
)

View File

@ -0,0 +1,22 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qglobal.h>
#if defined(Q_CC_MSVC) || defined(Q_CC_MSVC_NET) || defined(Q_CC_BOR)
#define LIB_EXPORT __declspec(dllexport)
#else
#define LIB_EXPORT
#endif
#if defined(Q_CC_BOR)
# define BORLAND_STDCALL __stdcall
#else
# define BORLAND_STDCALL
#endif
LIB_EXPORT int BORLAND_STDCALL mylibversion()
{
return 1;
}

View File

@ -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
)

View File

@ -0,0 +1,22 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qglobal.h>
#if defined(Q_CC_MSVC) || defined(Q_CC_MSVC_NET) || defined(Q_CC_BOR)
#define LIB_EXPORT __declspec(dllexport)
#else
#define LIB_EXPORT
#endif
#if defined(Q_CC_BOR)
# define BORLAND_STDCALL __stdcall
#else
# define BORLAND_STDCALL
#endif
LIB_EXPORT int BORLAND_STDCALL mylibversion()
{
return 2;
}

View File

@ -0,0 +1 @@
This should be an invalid shared object file.

View File

@ -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()

View File

@ -0,0 +1,682 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <qdir.h>
#include <qlibrary.h>
#include <QtCore/QRegularExpression>
// Helper macros to let us know if some suffixes and prefixes are valid
#define bundle_VALID false
#define dylib_VALID false
#define sl_VALID false
#define a_VALID false
#define so_VALID false
#define dll_VALID false
#define DLL_VALID false
#if defined(Q_OS_DARWIN)
# undef bundle_VALID
# undef dylib_VALID
# undef so_VALID
# define bundle_VALID true
# define dylib_VALID true
# define so_VALID true
# define SUFFIX ".dylib"
# define PREFIX "lib"
#elif defined(Q_OS_HPUX)
# undef sl_VALID
# define sl_VALID true
# ifndef __ia64
# define SUFFIX ".sl"
# define PREFIX "lib"
# else
# undef so_VALID
# define so_VALID true
# define SUFFIX ".so"
# define PREFIX "lib"
# endif
#elif defined(Q_OS_AIX)
# undef a_VALID
# undef so_VALID
# define a_VALID true
# define so_VALID true
# define SUFFIX ".a"
# define PREFIX "lib"
#elif defined(Q_OS_WIN)
# undef dll_VALID
# define dll_VALID true
# undef DLL_VALID
# define DLL_VALID true
# define SUFFIX ".dll"
# define PREFIX ""
#else // all other Unix
# undef so_VALID
# define so_VALID true
# define SUFFIX ".so"
# define PREFIX "lib"
#endif
QT_FORWARD_DECLARE_CLASS(QLibrary)
class tst_QLibrary : public QObject
{
Q_OBJECT
enum QLibraryOperation {
Load = 1,
Unload = 2,
Resolve = 3,
OperationMask = 7,
DontSetFileName = 0x100
};
QString sys_qualifiedLibraryName(const QString &fileName);
QString directory;
private slots:
void initTestCase();
void cleanup();
void load_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();
void loadHints_data();
void fileName_data();
void fileName();
void multipleInstancesForOneLibrary();
};
QString tst_QLibrary::sys_qualifiedLibraryName(const QString &fileName)
{
return directory + QLatin1Char('/') + PREFIX + fileName + SUFFIX;
}
typedef int (*VersionFunction)(void);
void tst_QLibrary::initTestCase()
{
#ifdef Q_OS_ANDROID
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();
#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
QSKIP("Versioned .so files are not generated for Android, so this test is not applicable.");
#endif
QTest::addColumn<QString>("lib");
QTest::addColumn<int>("loadversion");
QTest::addColumn<int>("resultversion");
QTest::newRow( "ok00, version 1" ) << "mylib" << 1 << 1;
QTest::newRow( "ok00, version 2" ) << "mylib" << 2 << 2;
QTest::newRow( "ok00, load without version" ) << "mylib" << -1 << 2;
}
void tst_QLibrary::version()
{
QFETCH( QString, lib );
QFETCH( int, loadversion );
QFETCH( int, resultversion );
#if !defined(Q_OS_AIX) && !defined(Q_OS_WIN)
QString appDir = directory;
QLibrary library( appDir + QLatin1Char('/') + lib, loadversion );
QVERIFY2(library.load(), qPrintable(library.errorString()));
VersionFunction fnVersion = (VersionFunction)library.resolve("mylibversion");
QVERIFY(fnVersion);
QCOMPARE(fnVersion(), resultversion);
QVERIFY2(library.unload(), qPrintable(library.errorString()));
#else
Q_UNUSED(lib);
Q_UNUSED(loadversion);
Q_UNUSED(resultversion);
#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
library.setFileNameAndVersion(directory + "/mylib", 1);
QVERIFY(library.isLoaded());
QVERIFY(library.unload());
QVERIFY(!library.isLoaded());
}
void tst_QLibrary::load_data()
{
QTest::addColumn<QString>("lib");
QTest::addColumn<bool>("result");
QString appDir = directory;
QTest::newRow( "ok00" ) << appDir + "/mylib" << true;
QTest::newRow( "notexist" ) << appDir + "/nolib" << false;
QTest::newRow( "badlibrary" ) << appDir + "/qlibrary.pro" << false;
#ifdef Q_OS_MAC
QTest::newRow("ok (libmylib ver. 1)") << appDir + "/libmylib" <<true;
#endif
# if defined(Q_OS_WIN32)
QTest::newRow( "ok01 (with suffix)" ) << appDir + "/mylib.dll" << true;
QTest::newRow( "ok02 (with non-standard suffix)" ) << appDir + "/mylib.dl2" << true;
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
}
void tst_QLibrary::load()
{
QFETCH( QString, lib );
QFETCH( bool, result );
QLibrary library( lib );
bool ok = library.load();
if ( result ) {
QVERIFY2( ok, qPrintable(library.errorString()) );
QVERIFY2( library.unload(), qPrintable(library.errorString()) );
} else {
QVERIFY( !ok );
}
}
void tst_QLibrary::unload_data()
{
QTest::addColumn<QString>("lib");
QTest::addColumn<bool>("result");
QString appDir = directory;
QTest::newRow( "mylib" ) << appDir + "/mylib" << true;
QTest::newRow( "ok01" ) << appDir + "/nolib" << false;
}
void tst_QLibrary::unload()
{
QFETCH( QString, lib );
QFETCH( bool, result );
QLibrary library( lib );
library.load();
bool ok = library.unload();
if ( result ) {
QVERIFY2( ok, qPrintable(library.errorString()) );
} else {
QVERIFY( !ok );
}
}
void tst_QLibrary::unload_after_implicit_load()
{
QLibrary library( directory + "/mylib" );
QFunctionPointer p = library.resolve("mylibversion");
QVERIFY(p); // Check if it was loaded
QVERIFY(library.isLoaded());
QVERIFY(library.unload());
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");
QTest::addColumn<QString>("symbol");
QTest::addColumn<bool>("goodPointer");
QString appDir = directory;
QTest::newRow( "ok00" ) << appDir + "/mylib" << QString("mylibversion") << true;
QTest::newRow( "bad00" ) << appDir + "/mylib" << QString("nosym") << false;
QTest::newRow( "bad01" ) << appDir + "/nolib" << QString("nosym") << false;
}
void tst_QLibrary::resolve()
{
typedef int (*testFunc)();
QFETCH( QString, lib );
QFETCH( QString, symbol );
QFETCH( bool, goodPointer );
QLibrary library( lib );
testFunc func = (testFunc) library.resolve( symbol.toLatin1() );
if ( goodPointer ) {
QVERIFY( func != 0 );
} else {
QVERIFY( func == 0 );
}
library.unload();
}
void tst_QLibrary::isLibrary_data()
{
QTest::addColumn<QString>("filename");
QTest::addColumn<bool>("valid");
// use the macros #defined at the top of the file
QTest::newRow("bad") << QString("mylib.bad") << false;
QTest::newRow(".a") << QString("mylib.a") << a_VALID;
QTest::newRow(".bundle") << QString("mylib.bundle") << bundle_VALID;
QTest::newRow(".dll") << QString("mylib.dll") << dll_VALID;
QTest::newRow(".DLL") << QString("MYLIB.DLL") << DLL_VALID;
QTest::newRow(".dl2" ) << QString("mylib.dl2") << false;
QTest::newRow(".dylib") << QString("mylib.dylib") << dylib_VALID;
QTest::newRow(".sl") << QString("mylib.sl") << sl_VALID;
QTest::newRow(".so") << QString("mylib.so") << so_VALID;
QTest::newRow(".so+version") << QString("mylib.so.0") << so_VALID;
QTest::newRow("version+.so") << QString("libc-2.7.so") << so_VALID;
QTest::newRow("version+.so+version") << QString("liboil-0.3.so.0.1.0") << so_VALID;
// special tests:
#ifdef Q_OS_MAC
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;
QTest::newRow("good (libmylib.so.1.0.0)") << QString("libmylib.so.1.0.0") << true;
QTest::newRow("bad (libmylib.1.0.0.foo)") << QString("libmylib.1.0.0.foo") << false;
#elif defined(Q_OS_WIN)
QTest::newRow("good (with many dots)" ) << "/system.qt.test.mylib.dll" << true;
#endif
}
void tst_QLibrary::isLibrary()
{
QFETCH( QString, filename );
QFETCH( bool, valid );
QCOMPARE(QLibrary::isLibrary(filename), valid);
}
void tst_QLibrary::errorString_data()
{
QTest::addColumn<int>("operation");
QTest::addColumn<QString>("fileName");
QTest::addColumn<bool>("success");
QTest::addColumn<QString>("errorString");
QString appDir = directory;
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("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
#else
QTest::newRow("load invalid file") << (int)Load << QFINDTESTDATA("library_path/invalid.so") << false << QString("Cannot load library.*");
#endif
}
void tst_QLibrary::errorString()
{
QFETCH(int, operation);
QFETCH(QString, fileName);
QFETCH(bool, success);
QFETCH(QString, errorString);
QLibrary lib;
if (!(operation & DontSetFileName)) {
lib.setFileName(fileName);
}
bool ok = false;
switch (operation & OperationMask) {
case Load:
ok = lib.load();
break;
case Unload:
ok = lib.load(); //###
ok = lib.unload();
break;
case Resolve: {
ok = lib.load();
QCOMPARE(ok, true);
if (success) {
ok = lib.resolve("mylibversion");
} else {
ok = lib.resolve("nosuchsymbol");
}
break;}
default:
QFAIL(qPrintable(QString("Unknown operation: %1").arg(operation)));
break;
}
#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());
QCOMPARE(ok, success);
}
void tst_QLibrary::loadHints_data()
{
QTest::addColumn<QString>("lib");
QTest::addColumn<int>("loadHints");
QTest::addColumn<bool>("result");
QLibrary::LoadHints lh;
QString appDir = directory;
lh |= QLibrary::ResolveAllSymbolsHint;
# 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
}
void tst_QLibrary::loadHints()
{
QFETCH( QString, lib );
QFETCH( int, loadHints);
QFETCH( bool, result );
//QLibrary library( lib );
QLibrary library;
QLibrary::LoadHints lh(loadHints);
if (int(loadHints) != 0) {
lh |= library.loadHints();
library.setLoadHints(lh);
// confirm that another QLibrary doesn't get affected - QTBUG-39642
QCOMPARE(QLibrary().loadHints(), QLibrary::LoadHints());
}
library.setFileName(lib);
QCOMPARE(library.loadHints(), lh);
bool ok = library.load();
// we can't change the hints anymore
library.setLoadHints(QLibrary::LoadHints());
QCOMPARE(library.loadHints(), lh);
// confirm that a new QLibrary inherits the hints too
QCOMPARE(QLibrary(lib).loadHints(), lh);
if ( result ) {
QVERIFY( ok );
QVERIFY(library.unload());
} else {
QVERIFY( !ok );
}
}
void tst_QLibrary::fileName_data()
{
QTest::addColumn<QString>("libName");
QTest::addColumn<QString>("expectedFilename");
QTest::newRow( "ok02" ) << sys_qualifiedLibraryName(QLatin1String("mylib"))
<< sys_qualifiedLibraryName(QLatin1String("mylib"));
#if defined(Q_OS_WIN)
QTest::newRow( "ok03" ) << "user32"
<< "USER32.dll";
#endif
}
void tst_QLibrary::fileName()
{
QFETCH( QString, libName);
QFETCH( QString, expectedFilename);
QLibrary lib(libName);
bool ok = lib.load();
QVERIFY2(ok, qPrintable(lib.errorString()));
#if defined(Q_OS_WIN)
QCOMPARE(lib.fileName().toLower(), expectedFilename.toLower());
#else
QCOMPARE(lib.fileName(), expectedFilename);
#endif
QVERIFY(lib.unload());
}
void tst_QLibrary::multipleInstancesForOneLibrary()
{
QString lib = directory + "/mylib";
{
QLibrary lib1(lib);
QLibrary lib2(lib);
QCOMPARE(lib1.isLoaded(), false);
QCOMPARE(lib2.isLoaded(), false);
lib1.load();
QCOMPARE(lib1.isLoaded(), true);
QCOMPARE(lib2.isLoaded(), true);
QCOMPARE(lib1.unload(), true);
QCOMPARE(lib1.isLoaded(), false);
QCOMPARE(lib2.isLoaded(), false);
lib1.load();
lib2.load();
QCOMPARE(lib1.isLoaded(), true);
QCOMPARE(lib2.isLoaded(), true);
QCOMPARE(lib1.unload(), false);
QCOMPARE(lib1.isLoaded(), true);
QCOMPARE(lib2.isLoaded(), true);
QCOMPARE(lib2.unload(), true);
QCOMPARE(lib1.isLoaded(), false);
QCOMPARE(lib2.isLoaded(), false);
// 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)
#include "tst_qlibrary.moc"

View File

@ -0,0 +1,42 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
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)

View File

@ -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)

View File

@ -0,0 +1,14 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtPlugin>
#include <QObject>
class DebugPlugin : public QObject
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "SomeIID")
public:
DebugPlugin() {}
};
#include "main.moc"

View File

@ -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)

View File

@ -0,0 +1,25 @@
// Copyright (C) 2018 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#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', ' ',
't', 'e', 's', 't', 'f', 'i', 'l', 'e'
};
extern "C" {
const void *qt_plugin_query_metadata()
{
return pluginMetaData;
}
Q_DECL_EXPORT void *qt_plugin_instance()
{
return nullptr;
}
}

View File

@ -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)

View File

@ -0,0 +1,14 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtPlugin>
#include <QObject>
class ReleasePlugin : public QObject
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "SomeIID")
public:
ReleasePlugin() {}
};
#include "main.moc"

View File

@ -0,0 +1,238 @@
// Copyright (C) 2020 The Qt Company Ltd.
// Copyright (C) 2021 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#include <QCoreApplication>
#include <QDebug>
#include <QDir>
#include <qplugin.h>
#include <QPluginLoader>
#include <private/qplugin_p.h>
class tst_QPlugin : public QObject
{
Q_OBJECT
QDir dir;
public:
tst_QPlugin();
private slots:
void initTestCase();
void loadDebugPlugin();
void loadReleasePlugin();
void scanInvalidPlugin_data();
void scanInvalidPlugin();
};
tst_QPlugin::tst_QPlugin()
{
// 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()
{
QVERIFY2(dir.exists(),
qPrintable(QString::fromLatin1("Cannot find the 'plugins' directory starting from '%1'").
arg(QDir::toNativeSeparators(QDir::currentPath()))));
}
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)
// 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
QVERIFY(!loader.load());
# else
// debug build, we can load debug plugins
QVERIFY(loader.load());
QObject *object = loader.instance();
QVERIFY(object != 0);
# endif
#endif
}
}
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)
// 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
QVERIFY(loader.load());
QObject *object = loader.instance();
QVERIFY(object != 0);
# else
// debug build, we cannot load debug plugins
QVERIFY(!loader.load());
# endif
#endif
}
}
void tst_QPlugin::scanInvalidPlugin_data()
{
QTest::addColumn<QByteArray>("metadata");
QTest::addColumn<bool>("loads");
QTest::addColumn<QString>("errMsg");
// CBOR metadata
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;
m.insert(int(QtPluginMetaDataKeys::IID), QLatin1String("org.qt-project.tst_qplugin"));
m.insert(int(QtPluginMetaDataKeys::ClassName), QLatin1String("tst"));
m.insert(int(QtPluginMetaDataKeys::MetaData), QCborMap());
return QCborValue(m).toCbor();
}();
QTest::newRow("cbor-control") << (cprefix + cborValid) << true << "";
cprefix[MagicLen + 1] = QT_VERSION_MAJOR + 1;
QTest::newRow("cbor-major-too-new") << (cprefix + cborValid) << false << "";
cprefix[MagicLen + 1] = QT_VERSION_MAJOR - 1;
QTest::newRow("cbor-major-too-old") << (cprefix + cborValid) << false << "";
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";
static qsizetype locateMetadata(const uchar *data, qsizetype len)
{
const uchar *dataend = data + len - strlen(invalidPluginSignature);
for (const uchar *ptr = data; ptr < dataend; ++ptr) {
if (*ptr != invalidPluginSignature[0])
continue;
int r = memcmp(ptr, invalidPluginSignature, strlen(invalidPluginSignature));
if (r)
continue;
return ptr - data;
}
return -1;
}
void tst_QPlugin::scanInvalidPlugin()
{
#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);
QTemporaryDir tmpdir;
QVERIFY(tmpdir.isValid());
QString newName = tmpdir.path() + '/' + fn.fileName();
QVERIFY(QFile::copy(invalidPluginName, newName));
{
QFile f(newName);
QVERIFY(f.open(QIODevice::ReadWrite | QIODevice::Unbuffered));
QVERIFY(f.size() > qint64(strlen(invalidPluginSignature)));
uchar *data = f.map(0, f.size());
QVERIFY(data);
static const qsizetype offset = locateMetadata(data, f.size());
QVERIFY(offset > 0);
QFETCH(QByteArray, metadata);
// sanity check
QVERIFY(metadata.size() < 512);
// replace the data
memcpy(data + offset, metadata.constData(), metadata.size());
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)
loader.unload();
}
QTEST_MAIN(tst_QPlugin)
#include "tst_qplugin.moc"

View File

@ -0,0 +1,2 @@
[loadMachO]
macos cmake

View File

@ -0,0 +1,13 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
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()

View File

@ -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)

View File

@ -0,0 +1,11 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/QString>
#include "almostplugin.h"
#include <QtCore/qplugin.h>
QString AlmostPlugin::pluginName() const
{
unresolvedSymbol();
return QLatin1String("Plugin ok");
}

View File

@ -0,0 +1,21 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef ALMOSTPLUGIN_H
#define ALMOSTPLUGIN_H
#include <QObject>
#include <QtPlugin>
#include "../theplugin/plugininterface.h"
class AlmostPlugin : public QObject, public PluginInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.autotests.plugininterface" FILE "../empty.json")
Q_INTERFACES(PluginInterface)
public:
QString pluginName() const override;
void unresolvedSymbol() const;
};
#endif // ALMOSTPLUGIN_H

View File

@ -0,0 +1 @@
{}

View File

@ -0,0 +1,57 @@
// Copyright (C) 2021 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef QT_VERSION_MAJOR
# include <QtCore/qglobal.h>
#endif
extern "C" void *qt_plugin_instance()
{
return nullptr;
}
#ifdef QT_DEBUG
static constexpr bool IsDebug = true;
#else
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

View File

@ -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"
)

View File

@ -0,0 +1,28 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <qglobal.h>
#if defined(Q_CC_MSVC) || defined(Q_CC_MSVC_NET) || defined(Q_CC_BOR)
#define LIB_EXPORT __declspec(dllexport)
#else
#define LIB_EXPORT
#endif
#if defined(Q_CC_BOR)
# define BORLAND_STDCALL __stdcall
#else
# define BORLAND_STDCALL
#endif
static int pluginVariable = 0xc0ffee;
LIB_EXPORT int *pointerAddress()
{
return &pluginVariable;
}
LIB_EXPORT int BORLAND_STDCALL version()
{
return 1;
}

View File

@ -0,0 +1,171 @@
#!/usr/bin/perl
# 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;
use constant MH_MAGIC => 0xfeedface;
use constant MH_MAGIC_64 => 0xfeedfacf;
use constant CPU_TYPE_X86 => 7;
use constant CPU_TYPE_X86_64 => CPU_TYPE_X86 | 0x01000000;
use constant CPU_SUBTYPE_I386_ALL => 3;
use constant MH_DYLIB => 6;
use constant LC_SEGMENT => 1;
use constant LC_SEGMENT_64 => 0x19;
my $good = pack("(L7 L2 Z16 L8 Z16 Z16 L9 . L)>",
MH_MAGIC, CPU_TYPE_X86, CPU_SUBTYPE_I386_ALL, MH_DYLIB, # 0-3
1, # 4: ncmds
4 * (37 - 6), # 5: sizeofcmds
0, # 6: flags
LC_SEGMENT, # 7: cmd
4 * (37 - 6), # 8: cmdsize
'__TEXT', # 9-12: segname
0, # 13: vmaddr
0x1000, # 14: vmsize
0, # 15: fileoff
0x204, # 16: filesize
7, # 17: maxprot (rwx)
5, # 18: initprot (r-x)
1, # 19: nsects
0, # 20: flags
'qtmetadata', # 21-24: sectname
'__TEXT', # 25-28: segname
0x200, # 29: addr
4, # 30: size
0x200, # 31: offset
2, # 32: align (2^2)
0, # 33: reloff
0, # 34: nreloc
0, # 35: flags
0, # 36: reserved1
0, # 37: reserved2
0x200,
0xc0ffee # data
);
my $good64 = pack("(L8 L2 Z16 Q4 L4 Z16 Z16 Q2 L8 . Q)>",
MH_MAGIC_64, CPU_TYPE_X86_64, CPU_SUBTYPE_I386_ALL, MH_DYLIB, # 0-3
1, # 4: ncmds
4 * (45 - 7), # 5: sizeofcmds
0, # 6: flags
0, # 7: reserved
LC_SEGMENT_64, # 8: cmd
4 * (45 - 7), # 9: cmdsize
'__TEXT', # 10-13: segname
0, # 14-15: vmaddr
0x1000, # 16-17: vmsize
0, # 18-19: fileoff
0x208, # 20-21: filesize
7, # 22: maxprot (rwx)
5, # 23: initprot (r-x)
1, # 24: nsects
0, # 25: flags
'qtmetadata', # 26-29: sectname
'__TEXT', # 30-33: segname
0x200, # 34-35: addr
4, # 36-37: size
0x200, # 38: offset
3, # 39: align (2^3)
0, # 40: reloff
0, # 41: nreloc
0, # 42: flags
0, # 43: reserved1
0, # 44: reserved2
0, # 45: reserved3
0x200,
0xc0ffeec0ffee # data
);
my $fat = pack("L>*",
FAT_MAGIC, # 1: magic
2, # 2: nfat_arch
CPU_TYPE_X86, # 3: cputype
CPU_SUBTYPE_I386_ALL, # 4: cpusubtype
0x1000, # 5: offset
0x1000, # 6: size
12, # 7: align (2^12)
CPU_TYPE_X86_64, # 8: cputype
CPU_SUBTYPE_I386_ALL, # 9: cpusubtype
0x2000, # 10: offset
0x1000, # 11: size
12, # 12: align (2^12)
);
my $buffer;
our $badcount = 1;
sub generate($) {
open OUT, ">", "bad$badcount.dylib" or die("Could not open file bad$badcount.dylib: $!\n");
binmode OUT;
print OUT $_[0];
close OUT;
++$badcount;
}
# Bad file 1-2
# Except that the cmdsize fields are null
$buffer = $good;
vec($buffer, 5, 32) = 0;
generate $buffer;
$buffer = $good;
vec($buffer, 8, 32) = 0;
generate $buffer;
# Bad file 3-4: same as above but 64-bit
$buffer = $good64;
vec($buffer, 5, 32) = 0;
generate $buffer;
$buffer = $good64;
vec($buffer, 9, 32) = 0;
generate $buffer;
# Bad file 5-8: same as 1-4, but set cmdsize to bigger than file
$buffer = $good;
vec($buffer, 5, 32) = 0x1000;
generate $buffer;
$buffer = $good;
vec($buffer, 8, 32) = 0x1000;
generate $buffer;
$buffer = $good64;
vec($buffer, 5, 32) = 0x1000;
generate $buffer;
$buffer = $good64;
vec($buffer, 9, 32) = 0x1000;
generate $buffer;
# Bad file 9-10: overflow size+offset
$buffer = $good;
vec($buffer, 30, 32) = 0xffffffe0;
generate $buffer;
$buffer = $good64;
vec($buffer, 36, 32) = 0xffffffff;
vec($buffer, 37, 32) = 0xffffffe0;
generate $buffer;
# Bad file 11: FAT binary with just the header
generate $fat;
# Bad file 12: FAT binary where the Mach contents don't match the FAT directory
$buffer = pack("a4096 a4096 a4096", $fat, $good64, $good);
generate $buffer;
# Bad file 13: FAT binary with overflowing size
$buffer = pack("a4096 a4096 a4096", $fat, $good, $good64);
vec($buffer, 5, 32) = 0xfffffffe0;
vec($buffer, 10, 32) = 0xfffffffe0;
generate $buffer;

View File

@ -0,0 +1,74 @@
#!/usr/bin/perl
# Copyright (C) 2016 Intel Corporation.
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
# 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);

View File

@ -0,0 +1 @@
void dummy() {}

View File

@ -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)

View File

@ -0,0 +1,14 @@
// Copyright (C) 2018 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#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"

View File

@ -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()

View File

@ -0,0 +1,22 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef PLUGININTERFACE_H
#define PLUGININTERFACE_H
#include <QtCore/QtGlobal>
struct PluginInterface {
virtual ~PluginInterface() {}
virtual QString pluginName() const = 0;
};
QT_BEGIN_NAMESPACE
#define PluginInterface_iid "org.qt-project.Qt.autotests.plugininterface"
Q_DECLARE_INTERFACE(PluginInterface, PluginInterface_iid)
QT_END_NAMESPACE
#endif // PLUGININTERFACE_H

View File

@ -0,0 +1,80 @@
// Copyright (C) 2021 Intel Corporation.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#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)

View File

@ -0,0 +1,21 @@
// Copyright (C) 2021 Intel Corportaion.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#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

View File

@ -0,0 +1,16 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/QString>
#include "theplugin.h"
#include <QtCore/qplugin.h>
QString ThePlugin::pluginName() const
{
return QLatin1String("Plugin ok");
}
static int pluginVariable = 0xc0ffee;
extern "C" Q_DECL_EXPORT int *pointerAddress()
{
return &pluginVariable;
}

View File

@ -0,0 +1,21 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#ifndef THEPLUGIN_H
#define THEPLUGIN_H
#include <QObject>
#include <QtPlugin>
#include "plugininterface.h"
class ThePlugin : public QObject, public PluginInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.qt-project.Qt.autotests.plugininterface" FILE "../utf8_data.json")
Q_INTERFACES(PluginInterface)
public:
virtual QString pluginName() const override;
};
#endif // THEPLUGIN_H

View File

@ -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
)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
{
"KPlugin": {
"Name": "WindowGeometry",
"Name[mr]": "चौकट भूमिती",
"Name[pa]": "ਵਿੰਡੋਜੁਮੈਟਰੀ",
"Name[th]": "มิติขนาดของหน้าต่าง",
"Name[uk]": "Розміри вікна",
"Name[zh_CN]": "窗口形状",
"Name[zh_TW]": "視窗位置",
"ServiceTypes": [
"KCModule"
]
},
"X-KDE-ParentComponents": [
"windowgeometry"
]
}

View File

@ -0,0 +1,5 @@
# Copyright (C) 2022 The Qt Company Ltd.
# SPDX-License-Identifier: BSD-3-Clause
add_subdirectory(testProcessUniqueness)
add_subdirectory(test)

View File

@ -0,0 +1,26 @@
# 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
)
## 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()

View File

@ -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)

View File

@ -0,0 +1,21 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <stdio.h>
#include <QUuid>
// This is a testcase for QTBUG-11213
int main(int argc, char **argv)
{
Q_UNUSED(argc);
Q_UNUSED(argv);
// Now print a few uuids.
printf("%s", qPrintable(QUuid::createUuid().toString()));
printf("%s", qPrintable(QUuid::createUuid().toString()));
printf("%s", qPrintable(QUuid::createUuid().toString()));
// Done
return 0;
}

View File

@ -0,0 +1,488 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QTest>
#if QT_CONFIG(process)
#include <QProcess>
#endif
#include <qcoreapplication.h>
#include <quuid.h>
class tst_QUuid : public QObject
{
Q_OBJECT
private slots:
void initTestCase();
void fromChar();
void toString();
void fromString_data();
void fromString();
void toByteArray();
void fromByteArray();
void toRfc4122();
void fromRfc4122();
void createUuidV3OrV5();
void check_QDataStream();
void isNull();
void equal();
void notEqual();
void cpp11();
// Only in Qt > 3.2.x
void generate();
void less();
void more();
void variants();
void versions();
void threadUniqueness();
void processUniqueness();
void hash();
void qvariant();
void qvariant_conversion();
void darwinTypes();
public:
// Variables
QUuid uuidNS;
QUuid uuidA;
QUuid uuidB;
QUuid uuidC;
QUuid uuidD;
};
void tst_QUuid::initTestCase()
{
//It's NameSpace_DNS in RFC4122
//"{6ba7b810-9dad-11d1-80b4-00c04fd430c8}";
uuidNS = QUuid(0x6ba7b810, 0x9dad, 0x11d1, 0x80, 0xb4, 0x00, 0xc0, 0x4f, 0xd4, 0x30, 0xc8);
//"{fc69b59e-cc34-4436-a43c-ee95d128b8c5}";
uuidA = QUuid(0xfc69b59e, 0xcc34, 0x4436, 0xa4, 0x3c, 0xee, 0x95, 0xd1, 0x28, 0xb8, 0xc5);
//"{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}";
uuidB = QUuid(0x1ab6e93a, 0xb1cb, 0x4a87, 0xba, 0x47, 0xec, 0x7e, 0x99, 0x03, 0x9a, 0x7b);
#if QT_CONFIG(process)
// chdir to the directory containing our testdata, then refer to it with relative paths
#ifdef Q_OS_ANDROID
QString testdata_dir = QCoreApplication::applicationDirPath();
#else // !Q_OS_ANDROID
QString testdata_dir = QFileInfo(QFINDTESTDATA("testProcessUniqueness")).absolutePath();
#endif
QVERIFY2(QDir::setCurrent(testdata_dir), qPrintable("Could not chdir to " + testdata_dir));
#endif
//"{3d813cbb-47fb-32ba-91df-831e1593ac29}"; http://www.rfc-editor.org/errata_search.php?rfc=4122&eid=1352
uuidC = QUuid(0x3d813cbb, 0x47fb, 0x32ba, 0x91, 0xdf, 0x83, 0x1e, 0x15, 0x93, 0xac, 0x29);
//"{21f7f8de-8051-5b89-8680-0195ef798b6a}";
uuidD = QUuid(0x21f7f8de, 0x8051, 0x5b89, 0x86, 0x80, 0x01, 0x95, 0xef, 0x79, 0x8b, 0x6a);
}
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}")));
}
void tst_QUuid::toString()
{
QCOMPARE(uuidA.toString(), QString("{fc69b59e-cc34-4436-a43c-ee95d128b8c5}"));
QCOMPARE(uuidA.toString(QUuid::WithoutBraces),
QString("fc69b59e-cc34-4436-a43c-ee95d128b8c5"));
QCOMPARE(uuidA.toString(QUuid::Id128),
QString("fc69b59ecc344436a43cee95d128b8c5"));
QCOMPARE(uuidB.toString(), QString("{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}"));
QCOMPARE(uuidB.toString(QUuid::WithoutBraces),
QString("1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b"));
QCOMPARE(uuidB.toString(QUuid::Id128),
QString("1ab6e93ab1cb4a87ba47ec7e99039a7b"));
}
void tst_QUuid::fromString_data()
{
QTest::addColumn<QUuid>("expected");
QTest::addColumn<QString>("input");
QUuid invalid = {};
#define ROW(which, string) \
QTest::addRow("%-38s -> %s", string, #which) << which << string
ROW(uuidA, "{fc69b59e-cc34-4436-a43c-ee95d128b8c5}");
ROW(uuidA, "fc69b59e-cc34-4436-a43c-ee95d128b8c5}");
ROW(uuidA, "{fc69b59e-cc34-4436-a43c-ee95d128b8c5" );
ROW(uuidA, "fc69b59e-cc34-4436-a43c-ee95d128b8c5" );
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(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
ROW(invalid, "{fc69b59e-cc34-4436-a4yc-ee95d128b8c5}"); // non-hex digit in 4th group
ROW(invalid, "{fc69b59e-cc34-4436-a43c-ee95d128j8c5}"); // non-hex digit in last group
ROW(invalid, "(fc69b59e-cc34-4436-a43c-ee95d128b8c5}"); // wrong initial character
ROW(invalid, "{fc69b59e+cc34-4436-a43c-ee95d128b8c5}"); // wrong 1st separator
ROW(invalid, "{fc69b59e-cc34*4436-a43c-ee95d128b8c5}"); // wrong 2nd separator
ROW(invalid, "{fc69b59e-cc34-44366a43c-ee95d128b8c5}"); // wrong 3rd separator
ROW(invalid, "{fc69b59e-cc34-4436-a43c\303\244ee95d128b8c5}"); // wrong 4th separator (&auml;)
ROW(uuidA, "{fc69b59e-cc34-4436-a43c-ee95d128b8c5)"); // wrong final character (not an error!)
ROW(uuidB, "{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}");
#undef ROW
}
void tst_QUuid::fromString()
{
QFETCH(const QUuid, expected);
QFETCH(const QString, input);
const auto inputL1 = input.toLatin1();
const auto inputU8 = input.toUtf8();
QCOMPARE(expected, QUuid(input));
QCOMPARE(expected, QUuid(inputU8));
QCOMPARE(expected, QUuid(inputL1));
QCOMPARE(expected, QUuid::fromString(input));
// 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));
// 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());
QCOMPARE(expected, QUuid::fromString(inputU8S));
}
void tst_QUuid::toByteArray()
{
QCOMPARE(uuidA.toByteArray(), QByteArray("{fc69b59e-cc34-4436-a43c-ee95d128b8c5}"));
QCOMPARE(uuidA.toByteArray(QUuid::WithoutBraces),
QByteArray("fc69b59e-cc34-4436-a43c-ee95d128b8c5"));
QCOMPARE(uuidA.toByteArray(QUuid::Id128),
QByteArray("fc69b59ecc344436a43cee95d128b8c5"));
QCOMPARE(uuidB.toByteArray(), QByteArray("{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}"));
QCOMPARE(uuidB.toByteArray(QUuid::WithoutBraces),
QByteArray("1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b"));
QCOMPARE(uuidB.toByteArray(QUuid::Id128),
QByteArray("1ab6e93ab1cb4a87ba47ec7e99039a7b"));
}
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")));
QCOMPARE(uuidB, QUuid(QByteArray("{1ab6e93a-b1cb-4a87-ba47-ec7e99039a7b}")));
}
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")));
QCOMPARE(uuidB, QUuid::fromRfc4122(QByteArray::fromHex("1ab6e93ab1cb4a87ba47ec7e99039a7b")));
}
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")));
QCOMPARE(uuidD, QUuid::createUuidV5(uuidNS, QByteArray("www.widgets.com")));
QCOMPARE(uuidD, QUuid::createUuidV5(uuidNS, QString("www.widgets.com")));
}
void tst_QUuid::check_QDataStream()
{
QUuid tmp;
QByteArray ar;
{
QDataStream out(&ar,QIODevice::WriteOnly);
out.setByteOrder(QDataStream::BigEndian);
out << uuidA;
}
{
QDataStream in(&ar,QIODevice::ReadOnly);
in.setByteOrder(QDataStream::BigEndian);
in >> tmp;
QCOMPARE(uuidA, tmp);
}
{
QDataStream out(&ar,QIODevice::WriteOnly);
out.setByteOrder(QDataStream::LittleEndian);
out << uuidA;
}
{
QDataStream in(&ar,QIODevice::ReadOnly);
in.setByteOrder(QDataStream::LittleEndian);
in >> tmp;
QCOMPARE(uuidA, tmp);
}
}
void tst_QUuid::isNull()
{
QVERIFY( !uuidA.isNull() );
QUuid should_be_null_uuid;
QVERIFY( should_be_null_uuid.isNull() );
}
void tst_QUuid::equal()
{
QVERIFY( !(uuidA == uuidB) );
QUuid copy(uuidA);
QCOMPARE(uuidA, copy);
QUuid assigned;
assigned = uuidA;
QCOMPARE(uuidA, assigned);
}
void tst_QUuid::notEqual()
{
QVERIFY( uuidA != uuidB );
}
void tst_QUuid::cpp11() {
#ifdef Q_COMPILER_UNIFORM_INIT
// "{fc69b59e-cc34-4436-a43c-ee95d128b8c5}" cf, initTestCase
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
QSKIP("This compiler is not in C++11 mode or it doesn't support uniform initialization");
#endif
}
void tst_QUuid::generate()
{
QUuid shouldnt_be_null_uuidA = QUuid::createUuid();
QUuid shouldnt_be_null_uuidB = QUuid::createUuid();
QVERIFY( !shouldnt_be_null_uuidA.isNull() );
QVERIFY( !shouldnt_be_null_uuidB.isNull() );
QVERIFY( shouldnt_be_null_uuidA != shouldnt_be_null_uuidB );
}
void tst_QUuid::less()
{
QVERIFY( uuidB < uuidA);
QVERIFY( uuidB <= uuidA);
QVERIFY(!(uuidA < uuidB) );
QVERIFY(!(uuidA <= uuidB));
QUuid null_uuid;
QVERIFY(null_uuid < uuidA); // Null uuid is always less than a valid one
QVERIFY(null_uuid <= uuidA);
QVERIFY(null_uuid <= null_uuid);
QVERIFY(uuidA <= uuidA);
}
void tst_QUuid::more()
{
QVERIFY( uuidA > uuidB);
QVERIFY( uuidA >= uuidB);
QVERIFY(!(uuidB > uuidA));
QVERIFY(!(uuidB >= uuidA));
QUuid null_uuid;
QVERIFY(!(null_uuid > uuidA)); // Null uuid is always less than a valid one
QVERIFY(!(null_uuid >= uuidA));
QVERIFY(null_uuid >= null_uuid);
QVERIFY(uuidA >= uuidA);
}
void tst_QUuid::variants()
{
QVERIFY( uuidA.variant() == QUuid::DCE );
QVERIFY( uuidB.variant() == QUuid::DCE );
QUuid NCS("{3a2f883c-4000-000d-0000-00fb40000000}");
QVERIFY( NCS.variant() == QUuid::NCS );
}
void tst_QUuid::versions()
{
QVERIFY( uuidA.version() == QUuid::Random );
QVERIFY( uuidB.version() == QUuid::Random );
QUuid DCE_time("{406c45a0-3b7e-11d0-80a3-0000c08810a7}");
QVERIFY( DCE_time.version() == QUuid::Time );
QUuid NCS("{3a2f883c-4000-000d-0000-00fb40000000}");
QVERIFY( NCS.version() == QUuid::VerUnknown );
}
class UuidThread : public QThread
{
public:
QUuid uuid;
void run() override
{
uuid = QUuid::createUuid();
}
};
void tst_QUuid::threadUniqueness()
{
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.size(); ++i)
threads[i]->start();
for (int i = 0; i < threads.size(); ++i)
QVERIFY(threads[i]->wait(1000));
for (int i = 1; i < threads.size(); ++i)
QVERIFY(threads[0]->uuid != threads[i]->uuid);
qDeleteAll(threads);
}
void tst_QUuid::processUniqueness()
{
#if !QT_CONFIG(process)
QSKIP("No qprocess support", SkipAll);
#else
#ifdef Q_OS_ANDROID
QSKIP("This test crashes on Android");
#endif
QProcess process;
QString processOneOutput;
QString processTwoOutput;
// Start it once
#ifdef Q_OS_MAC
process.start("testProcessUniqueness/testProcessUniqueness.app");
#elif defined(Q_OS_ANDROID)
process.start("libtestProcessUniqueness.so");
#else
process.start("testProcessUniqueness/testProcessUniqueness");
#endif
QVERIFY(process.waitForFinished());
processOneOutput = process.readAllStandardOutput();
// Start it twice
#ifdef Q_OS_MAC
process.start("testProcessUniqueness/testProcessUniqueness.app");
#elif defined(Q_OS_ANDROID)
process.start("libtestProcessUniqueness.so");
#else
process.start("testProcessUniqueness/testProcessUniqueness");
#endif
QVERIFY(process.waitForFinished());
processTwoOutput = process.readAllStandardOutput();
// They should be *different*!
QVERIFY(processOneOutput != processTwoOutput);
#endif
}
void tst_QUuid::hash()
{
size_t h = qHash(uuidA);
QCOMPARE(qHash(uuidA), h);
QCOMPARE(qHash(QUuid(uuidA.toString())), h);
}
void tst_QUuid::qvariant()
{
QUuid uuid = QUuid::createUuid();
QVariant v = QVariant::fromValue(uuid);
QVERIFY(!v.isNull());
QCOMPARE(v.metaType(), QMetaType(QMetaType::QUuid));
QUuid uuid2 = v.value<QUuid>();
QVERIFY(!uuid2.isNull());
QCOMPARE(uuid, uuid2);
}
void tst_QUuid::qvariant_conversion()
{
QUuid uuid = QUuid::createUuid();
QVariant v = QVariant::fromValue(uuid);
// QUuid -> QString
QVERIFY(v.canConvert<QString>());
QCOMPARE(v.toString(), uuid.toString());
QCOMPARE(v.value<QString>(), uuid.toString());
// QUuid -> QByteArray
QVERIFY(v.canConvert<QByteArray>());
QCOMPARE(v.toByteArray(), uuid.toByteArray());
QCOMPARE(v.value<QByteArray>(), uuid.toByteArray());
QVERIFY(!v.canConvert<int>());
QVERIFY(!v.canConvert<QStringList>());
// try reverse conversion QString -> QUuid
QVariant sv = QVariant::fromValue(uuid.toString());
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.metaType(), QMetaType(QMetaType::QByteArray));
QVERIFY(sv.canConvert<QUuid>());
QCOMPARE(sv.value<QUuid>(), uuid);
}
}
void tst_QUuid::darwinTypes()
{
#ifndef Q_OS_DARWIN
QSKIP("This is a Darwin-only test");
#else
extern void tst_QUuid_darwinTypes(); // in tst_quuid_darwin.mm
tst_QUuid_darwinTypes();
#endif
}
QTEST_MAIN(tst_QUuid)
#include "tst_quuid.moc"

View File

@ -0,0 +1,54 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
#include <QtCore/QUuid>
#include <QTest>
#include <QtCore/private/qcore_mac_p.h>
#include <CoreFoundation/CoreFoundation.h>
#include <Foundation/Foundation.h>
void tst_QUuid_darwinTypes()
{
// QUuid <-> CFUUID
{
const auto qtUuid = QUuid::fromString(QLatin1String("0f7169cc-5711-4af9-99d9-fecb2329fdef"));
const CFUUIDRef cfuuid = qtUuid.toCFUUID();
QCOMPARE(QUuid::fromCFUUID(cfuuid), qtUuid);
CFStringRef cfstring = CFUUIDCreateString(0, cfuuid);
QCOMPARE(QString::fromCFString(cfstring), qtUuid.toString().mid(1, 36).toUpper());
CFRelease(cfstring);
CFRelease(cfuuid);
}
{
auto qtUuid = QUuid::fromString(QLatin1String("0f7169cc-5711-4af9-99d9-fecb2329fdef"));
const CFUUIDRef cfuuid = qtUuid.toCFUUID();
QUuid qtUuidCopy(qtUuid);
qtUuid = QUuid::fromString(QLatin1String("93eec131-13c5-4d13-aaea-e456b4c57efa")); // modify
QCOMPARE(QUuid::fromCFUUID(cfuuid), qtUuidCopy);
CFStringRef cfstring = CFUUIDCreateString(0, cfuuid);
QCOMPARE(QString::fromCFString(cfstring), qtUuidCopy.toString().mid(1, 36).toUpper());
CFRelease(cfstring);
CFRelease(cfuuid);
}
// QUuid <-> NSUUID
{
QMacAutoReleasePool pool;
const auto qtUuid = QUuid::fromString(QLatin1String("0f7169cc-5711-4af9-99d9-fecb2329fdef"));
const NSUUID *nsuuid = qtUuid.toNSUUID();
QCOMPARE(QUuid::fromNSUUID(nsuuid), qtUuid);
QCOMPARE(QString::fromNSString([nsuuid UUIDString]), qtUuid.toString().mid(1, 36).toUpper());
}
{
QMacAutoReleasePool pool;
auto qtUuid = QUuid::fromString(QLatin1String("0f7169cc-5711-4af9-99d9-fecb2329fdef"));
const NSUUID *nsuuid = qtUuid.toNSUUID();
QUuid qtUuidCopy(qtUuid);
qtUuid = QUuid::fromString(QLatin1String("93eec131-13c5-4d13-aaea-e456b4c57efa")); // modify
QCOMPARE(QUuid::fromNSUUID(nsuuid), qtUuidCopy);
QCOMPARE(QString::fromNSString([nsuuid UUIDString]), qtUuidCopy.toString().mid(1, 36).toUpper());
}
}