Some checks failed
Docker. / Ubuntu (push) Has been cancelled
User-agent updater. / User-agent (push) Failing after 15s
Lock Threads / lock (push) Failing after 10s
Waiting for answer. / waiting-for-answer (push) Failing after 22s
Close stale issues and PRs / stale (push) Successful in 13s
Needs user action. / needs-user-action (push) Failing after 8s
Can't reproduce. / cant-reproduce (push) Failing after 8s
390 lines
16 KiB
C++
390 lines
16 KiB
C++
/*
|
|
SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
|
|
|
|
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
|
*/
|
|
|
|
#include <QFileInfo>
|
|
#include <QTest>
|
|
|
|
#include "kcoreaddons_debug.h"
|
|
#include <kpluginloader.h>
|
|
#include <kpluginmetadata.h>
|
|
|
|
class LibraryPathRestorer
|
|
{
|
|
public:
|
|
explicit LibraryPathRestorer(const QStringList &paths)
|
|
: mPaths(paths)
|
|
{
|
|
}
|
|
~LibraryPathRestorer()
|
|
{
|
|
QCoreApplication::setLibraryPaths(mPaths);
|
|
}
|
|
|
|
private:
|
|
QStringList mPaths;
|
|
};
|
|
|
|
class KPluginLoaderTest : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
#if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 86)
|
|
private Q_SLOTS:
|
|
void testFindPlugin_missing()
|
|
{
|
|
const QString location = KPluginLoader::findPlugin(QStringLiteral("idonotexist"));
|
|
QVERIFY2(location.isEmpty(), qPrintable(location));
|
|
}
|
|
|
|
void testFindPlugin()
|
|
{
|
|
const QString location = KPluginLoader::findPlugin(QStringLiteral("jsonplugin"));
|
|
QVERIFY2(!location.isEmpty(), qPrintable(location));
|
|
}
|
|
|
|
#if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 84)
|
|
void testPluginVersion()
|
|
{
|
|
KPluginLoader vplugin(QStringLiteral("versionedplugin"));
|
|
QCOMPARE(vplugin.pluginVersion(), quint32(5));
|
|
|
|
KPluginLoader vplugin2(QStringLiteral("versionedplugin"));
|
|
QCOMPARE(vplugin2.pluginVersion(), quint32(5));
|
|
|
|
KPluginLoader uplugin(QStringLiteral("unversionedplugin"));
|
|
QCOMPARE(uplugin.pluginVersion(), quint32(-1));
|
|
|
|
KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
|
|
QCOMPARE(jplugin.pluginVersion(), quint32(-1));
|
|
|
|
KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
|
|
QCOMPARE(eplugin.pluginVersion(), quint32(-1));
|
|
|
|
KPluginLoader noplugin(QStringLiteral("idonotexist"));
|
|
QCOMPARE(noplugin.pluginVersion(), quint32(-1));
|
|
}
|
|
#endif
|
|
|
|
void testPluginName()
|
|
{
|
|
KPluginLoader vplugin(QStringLiteral("versionedplugin"));
|
|
QCOMPARE(vplugin.pluginName(), QString::fromLatin1("versionedplugin"));
|
|
|
|
KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
|
|
QCOMPARE(jplugin.pluginName(), QString::fromLatin1("jsonplugin"));
|
|
|
|
KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
|
|
QVERIFY2(eplugin.pluginName().isEmpty(), qPrintable(eplugin.pluginName()));
|
|
|
|
KPluginLoader noplugin(QStringLiteral("idonotexist"));
|
|
QCOMPARE(noplugin.pluginName(), QString::fromLatin1("idonotexist"));
|
|
}
|
|
|
|
void testFactory()
|
|
{
|
|
KPluginLoader vplugin(QStringLiteral("versionedplugin"));
|
|
QVERIFY(vplugin.factory());
|
|
|
|
KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
|
|
QVERIFY(jplugin.factory());
|
|
|
|
KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
|
|
QVERIFY(!eplugin.factory());
|
|
|
|
KPluginLoader noplugin(QStringLiteral("idonotexist"));
|
|
QVERIFY(!noplugin.factory());
|
|
}
|
|
|
|
void testErrorString()
|
|
{
|
|
KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
|
|
QCOMPARE(eplugin.errorString(), QString::fromLatin1("there was an error"));
|
|
}
|
|
|
|
void testFileName()
|
|
{
|
|
KPluginLoader vplugin(QStringLiteral("versionedplugin"));
|
|
QCOMPARE(QFileInfo(vplugin.fileName()).canonicalFilePath(), QFileInfo(QStringLiteral(VERSIONEDPLUGIN_FILE)).canonicalFilePath());
|
|
|
|
KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
|
|
QCOMPARE(QFileInfo(jplugin.fileName()).canonicalFilePath(), QFileInfo(QStringLiteral(JSONPLUGIN_FILE)).canonicalFilePath());
|
|
|
|
KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
|
|
QVERIFY2(eplugin.fileName().isEmpty(), qPrintable(eplugin.fileName()));
|
|
|
|
KPluginLoader noplugin(QStringLiteral("idonotexist"));
|
|
QVERIFY2(noplugin.fileName().isEmpty(), qPrintable(noplugin.fileName()));
|
|
}
|
|
|
|
void testInstance()
|
|
{
|
|
KPluginLoader vplugin(QStringLiteral("versionedplugin"));
|
|
QVERIFY(vplugin.instance());
|
|
|
|
KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
|
|
QVERIFY(jplugin.instance());
|
|
|
|
KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
|
|
QVERIFY(!eplugin.instance());
|
|
|
|
KPluginLoader noplugin(QStringLiteral("idonotexist"));
|
|
QVERIFY(!noplugin.instance());
|
|
}
|
|
|
|
void testIsLoaded()
|
|
{
|
|
KPluginLoader vplugin(QStringLiteral("versionedplugin"));
|
|
QVERIFY(!vplugin.isLoaded());
|
|
QVERIFY(vplugin.load());
|
|
QVERIFY(vplugin.isLoaded());
|
|
|
|
KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
|
|
QVERIFY(!jplugin.isLoaded());
|
|
QVERIFY(jplugin.load());
|
|
QVERIFY(jplugin.isLoaded());
|
|
|
|
KPluginLoader aplugin(QStringLiteral("alwaysunloadplugin"));
|
|
QVERIFY(!aplugin.isLoaded());
|
|
QVERIFY(aplugin.load());
|
|
QVERIFY(aplugin.isLoaded());
|
|
if (aplugin.unload()) {
|
|
QVERIFY(!aplugin.isLoaded());
|
|
} else {
|
|
qCDebug(KCOREADDONS_DEBUG) << "Could not unload alwaysunloadplugin:" << aplugin.errorString();
|
|
}
|
|
|
|
KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
|
|
QVERIFY(!eplugin.isLoaded());
|
|
QVERIFY(!eplugin.load());
|
|
QVERIFY(!eplugin.isLoaded());
|
|
|
|
KPluginLoader noplugin(QStringLiteral("idonotexist"));
|
|
QVERIFY(!noplugin.isLoaded());
|
|
QVERIFY(!noplugin.load());
|
|
QVERIFY(!noplugin.isLoaded());
|
|
}
|
|
|
|
void testLoad()
|
|
{
|
|
KPluginLoader vplugin(QStringLiteral("versionedplugin"));
|
|
QVERIFY(vplugin.load());
|
|
|
|
KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
|
|
QVERIFY(jplugin.load());
|
|
|
|
KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
|
|
QVERIFY(!eplugin.load());
|
|
|
|
KPluginLoader noplugin(QStringLiteral("idonotexist"));
|
|
QVERIFY(!noplugin.load());
|
|
}
|
|
|
|
void testLoadHints()
|
|
{
|
|
KPluginLoader aplugin(QStringLiteral("alwaysunloadplugin"));
|
|
QCOMPARE(aplugin.loadHints(), QLibrary::PreventUnloadHint);
|
|
aplugin.setLoadHints(QLibrary::ResolveAllSymbolsHint);
|
|
// setLoadHints merges in this scenario in the patch collection [1] but not in raw Qt5
|
|
// [1] https://invent.kde.org/qt/qt/qtbase/-/merge_requests/285
|
|
QVERIFY(aplugin.loadHints() == (QLibrary::ResolveAllSymbolsHint | QLibrary::PreventUnloadHint)
|
|
|| aplugin.loadHints() == QLibrary::ResolveAllSymbolsHint);
|
|
}
|
|
|
|
void testMetaData()
|
|
{
|
|
KPluginLoader aplugin(QStringLiteral("alwaysunloadplugin"));
|
|
QJsonObject ametadata = aplugin.metaData();
|
|
QVERIFY(!ametadata.isEmpty());
|
|
QVERIFY(ametadata.keys().contains(QLatin1String("IID")));
|
|
QJsonValue ametadata_metadata = ametadata.value(QStringLiteral("MetaData"));
|
|
QVERIFY(ametadata_metadata.toObject().isEmpty());
|
|
QVERIFY(!aplugin.isLoaded()); // didn't load anything
|
|
|
|
KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
|
|
QJsonObject jmetadata = jplugin.metaData();
|
|
QVERIFY(!jmetadata.isEmpty());
|
|
QJsonValue jmetadata_metadata = jmetadata.value(QStringLiteral("MetaData"));
|
|
QVERIFY(jmetadata_metadata.isObject());
|
|
QJsonObject jmetadata_obj = jmetadata_metadata.toObject();
|
|
QVERIFY(!jmetadata_obj.isEmpty());
|
|
QJsonValue comment = jmetadata_obj.value(QStringLiteral("KPlugin")).toObject().value(QStringLiteral("Description"));
|
|
QVERIFY(comment.isString());
|
|
QCOMPARE(comment.toString(), QString::fromLatin1("This is a plugin"));
|
|
|
|
KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
|
|
QVERIFY(eplugin.metaData().isEmpty());
|
|
|
|
KPluginLoader noplugin(QStringLiteral("idonotexist"));
|
|
QVERIFY(noplugin.metaData().isEmpty());
|
|
}
|
|
|
|
void testUnload()
|
|
{
|
|
KPluginLoader aplugin(QStringLiteral("alwaysunloadplugin"));
|
|
QVERIFY(aplugin.load());
|
|
// may need QEXPECT_FAIL on some platforms...
|
|
QVERIFY(aplugin.unload());
|
|
}
|
|
|
|
void testInstantiatePlugins()
|
|
{
|
|
const QString plugin1Path = KPluginLoader::findPlugin(QStringLiteral("jsonplugin"));
|
|
QVERIFY2(!plugin1Path.isEmpty(), qPrintable(plugin1Path));
|
|
const QString plugin2Path = KPluginLoader::findPlugin(QStringLiteral("unversionedplugin"));
|
|
QVERIFY2(!plugin2Path.isEmpty(), qPrintable(plugin2Path));
|
|
const QString plugin3Path = KPluginLoader::findPlugin(QStringLiteral("jsonplugin2"));
|
|
QVERIFY2(!plugin3Path.isEmpty(), qPrintable(plugin3Path));
|
|
|
|
QTemporaryDir temp;
|
|
QVERIFY(temp.isValid());
|
|
QDir dir(temp.path());
|
|
QVERIFY2(QFile::copy(plugin1Path, dir.absoluteFilePath(QFileInfo(plugin1Path).fileName())),
|
|
qPrintable(dir.absoluteFilePath(QFileInfo(plugin1Path).fileName())));
|
|
QVERIFY2(QFile::copy(plugin2Path, dir.absoluteFilePath(QFileInfo(plugin2Path).fileName())),
|
|
qPrintable(dir.absoluteFilePath(QFileInfo(plugin2Path).fileName())));
|
|
QVERIFY2(QFile::copy(plugin3Path, dir.absoluteFilePath(QFileInfo(plugin3Path).fileName())),
|
|
qPrintable(dir.absoluteFilePath(QFileInfo(plugin3Path).fileName())));
|
|
|
|
// only jsonplugin, since unversionedplugin has no json metadata
|
|
QList<QObject *> plugins = KPluginLoader::instantiatePlugins(temp.path());
|
|
QCOMPARE(plugins.size(), 2);
|
|
QStringList classNames = QStringList() << QString::fromLatin1(plugins[0]->metaObject()->className())
|
|
<< QString::fromLatin1(plugins[1]->metaObject()->className());
|
|
classNames.sort();
|
|
QCOMPARE(classNames[0], QStringLiteral("jsonplugin2"));
|
|
QCOMPARE(classNames[1], QStringLiteral("jsonpluginfa"));
|
|
qDeleteAll(plugins);
|
|
|
|
// try filter
|
|
plugins = KPluginLoader::instantiatePlugins(temp.path(), [](const KPluginMetaData &md) {
|
|
return md.pluginId() == QLatin1String("jsonplugin");
|
|
});
|
|
QCOMPARE(plugins.size(), 1);
|
|
QCOMPARE(plugins[0]->metaObject()->className(), "jsonpluginfa");
|
|
qDeleteAll(plugins);
|
|
|
|
plugins = KPluginLoader::instantiatePlugins(temp.path(), [](const KPluginMetaData &md) {
|
|
return md.pluginId() == QLatin1String("unversionedplugin");
|
|
});
|
|
QCOMPARE(plugins.size(), 0);
|
|
|
|
plugins = KPluginLoader::instantiatePlugins(temp.path(), [](const KPluginMetaData &md) {
|
|
return md.pluginId() == QLatin1String("foobar"); // ID does not match file name, is set in JSON
|
|
});
|
|
QCOMPARE(plugins.size(), 1);
|
|
QCOMPARE(plugins[0]->metaObject()->className(), "jsonplugin2");
|
|
qDeleteAll(plugins);
|
|
|
|
// check that parent gets set
|
|
plugins = KPluginLoader::instantiatePlugins(
|
|
temp.path(),
|
|
[](const KPluginMetaData &) {
|
|
return true;
|
|
},
|
|
this);
|
|
QCOMPARE(plugins.size(), 2);
|
|
QCOMPARE(plugins[0]->parent(), this);
|
|
QCOMPARE(plugins[1]->parent(), this);
|
|
qDeleteAll(plugins);
|
|
|
|
const QString subDirName = dir.dirName();
|
|
QVERIFY(dir.cdUp()); // should now point to /tmp on Linux
|
|
LibraryPathRestorer restorer(QCoreApplication::libraryPaths());
|
|
// instantiate using relative path
|
|
// make sure library path is set up correctly
|
|
QCoreApplication::setLibraryPaths(QStringList() << dir.absolutePath());
|
|
QVERIFY(!QDir::isAbsolutePath(subDirName));
|
|
plugins = KPluginLoader::instantiatePlugins(subDirName);
|
|
QCOMPARE(plugins.size(), 2);
|
|
classNames = QStringList() << QString::fromLatin1(plugins[0]->metaObject()->className()) << QString::fromLatin1(plugins[1]->metaObject()->className());
|
|
classNames.sort();
|
|
QCOMPARE(classNames[0], QStringLiteral("jsonplugin2"));
|
|
QCOMPARE(classNames[1], QStringLiteral("jsonpluginfa"));
|
|
qDeleteAll(plugins);
|
|
}
|
|
|
|
void testForEachPlugin()
|
|
{
|
|
const QString jsonPluginSrc = KPluginLoader::findPlugin(QStringLiteral("jsonplugin"));
|
|
QVERIFY2(!jsonPluginSrc.isEmpty(), qPrintable(jsonPluginSrc));
|
|
const QString unversionedPluginSrc = KPluginLoader::findPlugin(QStringLiteral("unversionedplugin"));
|
|
QVERIFY2(!unversionedPluginSrc.isEmpty(), qPrintable(unversionedPluginSrc));
|
|
const QString jsonPlugin2Src = KPluginLoader::findPlugin(QStringLiteral("jsonplugin2"));
|
|
QVERIFY2(!jsonPlugin2Src.isEmpty(), qPrintable(jsonPlugin2Src));
|
|
|
|
QTemporaryDir temp;
|
|
QVERIFY(temp.isValid());
|
|
QDir dir(temp.path());
|
|
QVERIFY(dir.mkdir(QStringLiteral("for-each-plugin")));
|
|
QVERIFY(dir.cd(QStringLiteral("for-each-plugin")));
|
|
const QString jsonPluginDest = dir.absoluteFilePath(QFileInfo(jsonPluginSrc).fileName());
|
|
QVERIFY2(QFile::copy(jsonPluginSrc, jsonPluginDest), qPrintable(jsonPluginDest));
|
|
const QString unversionedPluginDest = dir.absoluteFilePath(QFileInfo(unversionedPluginSrc).fileName());
|
|
QVERIFY2(QFile::copy(unversionedPluginSrc, unversionedPluginDest), qPrintable(unversionedPluginDest));
|
|
// copy jsonplugin2 to a "for-each-plugin" subdirectory in a different directory
|
|
QTemporaryDir temp2;
|
|
QVERIFY(temp2.isValid());
|
|
QDir dir2(temp2.path());
|
|
QVERIFY(dir2.mkdir(QStringLiteral("for-each-plugin")));
|
|
QVERIFY(dir2.cd(QStringLiteral("for-each-plugin")));
|
|
const QString jsonPlugin2Dest = dir2.absoluteFilePath(QFileInfo(jsonPlugin2Src).fileName());
|
|
QVERIFY2(QFile::copy(jsonPlugin2Src, jsonPlugin2Dest), qPrintable(jsonPlugin2Dest));
|
|
|
|
QStringList foundPlugins;
|
|
QStringList expectedPlugins;
|
|
const auto addToFoundPlugins = [&](const QString &path) {
|
|
QVERIFY(!path.isEmpty());
|
|
foundPlugins.append(path);
|
|
};
|
|
|
|
// test finding with absolute path
|
|
expectedPlugins = QStringList() << jsonPluginDest << unversionedPluginDest;
|
|
expectedPlugins.sort();
|
|
KPluginLoader::forEachPlugin(dir.path(), addToFoundPlugins);
|
|
foundPlugins.sort();
|
|
QCOMPARE(foundPlugins, expectedPlugins);
|
|
|
|
expectedPlugins = QStringList() << jsonPlugin2Dest;
|
|
expectedPlugins.sort();
|
|
foundPlugins.clear();
|
|
KPluginLoader::forEachPlugin(dir2.path(), addToFoundPlugins);
|
|
foundPlugins.sort();
|
|
QCOMPARE(foundPlugins, expectedPlugins);
|
|
|
|
// now test relative paths
|
|
|
|
LibraryPathRestorer restorer(QCoreApplication::libraryPaths());
|
|
QCoreApplication::setLibraryPaths(QStringList() << temp.path());
|
|
expectedPlugins = QStringList() << jsonPluginDest << unversionedPluginDest;
|
|
expectedPlugins.sort();
|
|
foundPlugins.clear();
|
|
KPluginLoader::forEachPlugin(QStringLiteral("for-each-plugin"), addToFoundPlugins);
|
|
foundPlugins.sort();
|
|
QCOMPARE(foundPlugins, expectedPlugins);
|
|
|
|
QCoreApplication::setLibraryPaths(QStringList() << temp2.path());
|
|
expectedPlugins = QStringList() << jsonPlugin2Dest;
|
|
expectedPlugins.sort();
|
|
foundPlugins.clear();
|
|
KPluginLoader::forEachPlugin(QStringLiteral("for-each-plugin"), addToFoundPlugins);
|
|
foundPlugins.sort();
|
|
QCOMPARE(foundPlugins, expectedPlugins);
|
|
|
|
QCoreApplication::setLibraryPaths(QStringList() << temp.path() << temp2.path());
|
|
expectedPlugins = QStringList() << jsonPluginDest << unversionedPluginDest << jsonPlugin2Dest;
|
|
expectedPlugins.sort();
|
|
foundPlugins.clear();
|
|
KPluginLoader::forEachPlugin(QStringLiteral("for-each-plugin"), addToFoundPlugins);
|
|
foundPlugins.sort();
|
|
QCOMPARE(foundPlugins, expectedPlugins);
|
|
}
|
|
#endif
|
|
};
|
|
|
|
QTEST_MAIN(KPluginLoaderTest)
|
|
|
|
#include "kpluginloadertest.moc"
|