Warning, file /frameworks/kcoreaddons/autotests/kpluginloadertest.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002     SPDX-FileCopyrightText: 2014 Alex Merry <alex.merry@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include <QFileInfo>
0008 #include <QTest>
0009 
0010 #include "kcoreaddons_debug.h"
0011 #include <kpluginloader.h>
0012 #include <kpluginmetadata.h>
0013 
0014 class LibraryPathRestorer
0015 {
0016 public:
0017     explicit LibraryPathRestorer(const QStringList &paths)
0018         : mPaths(paths)
0019     {
0020     }
0021     ~LibraryPathRestorer()
0022     {
0023         QCoreApplication::setLibraryPaths(mPaths);
0024     }
0025 
0026 private:
0027     QStringList mPaths;
0028 };
0029 
0030 class KPluginLoaderTest : public QObject
0031 {
0032     Q_OBJECT
0033 
0034 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 86)
0035 private Q_SLOTS:
0036     void testFindPlugin_missing()
0037     {
0038         const QString location = KPluginLoader::findPlugin(QStringLiteral("idonotexist"));
0039         QVERIFY2(location.isEmpty(), qPrintable(location));
0040     }
0041 
0042     void testFindPlugin()
0043     {
0044         const QString location = KPluginLoader::findPlugin(QStringLiteral("jsonplugin"));
0045         QVERIFY2(!location.isEmpty(), qPrintable(location));
0046     }
0047 
0048 #if KCOREADDONS_BUILD_DEPRECATED_SINCE(5, 84)
0049     void testPluginVersion()
0050     {
0051         KPluginLoader vplugin(QStringLiteral("versionedplugin"));
0052         QCOMPARE(vplugin.pluginVersion(), quint32(5));
0053 
0054         KPluginLoader vplugin2(QStringLiteral("versionedplugin"));
0055         QCOMPARE(vplugin2.pluginVersion(), quint32(5));
0056 
0057         KPluginLoader uplugin(QStringLiteral("unversionedplugin"));
0058         QCOMPARE(uplugin.pluginVersion(), quint32(-1));
0059 
0060         KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
0061         QCOMPARE(jplugin.pluginVersion(), quint32(-1));
0062 
0063         KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
0064         QCOMPARE(eplugin.pluginVersion(), quint32(-1));
0065 
0066         KPluginLoader noplugin(QStringLiteral("idonotexist"));
0067         QCOMPARE(noplugin.pluginVersion(), quint32(-1));
0068     }
0069 #endif
0070 
0071     void testPluginName()
0072     {
0073         KPluginLoader vplugin(QStringLiteral("versionedplugin"));
0074         QCOMPARE(vplugin.pluginName(), QString::fromLatin1("versionedplugin"));
0075 
0076         KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
0077         QCOMPARE(jplugin.pluginName(), QString::fromLatin1("jsonplugin"));
0078 
0079         KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
0080         QVERIFY2(eplugin.pluginName().isEmpty(), qPrintable(eplugin.pluginName()));
0081 
0082         KPluginLoader noplugin(QStringLiteral("idonotexist"));
0083         QCOMPARE(noplugin.pluginName(), QString::fromLatin1("idonotexist"));
0084     }
0085 
0086     void testFactory()
0087     {
0088         KPluginLoader vplugin(QStringLiteral("versionedplugin"));
0089         QVERIFY(vplugin.factory());
0090 
0091         KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
0092         QVERIFY(jplugin.factory());
0093 
0094         KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
0095         QVERIFY(!eplugin.factory());
0096 
0097         KPluginLoader noplugin(QStringLiteral("idonotexist"));
0098         QVERIFY(!noplugin.factory());
0099     }
0100 
0101     void testErrorString()
0102     {
0103         KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
0104         QCOMPARE(eplugin.errorString(), QString::fromLatin1("there was an error"));
0105     }
0106 
0107     void testFileName()
0108     {
0109         KPluginLoader vplugin(QStringLiteral("versionedplugin"));
0110         QCOMPARE(QFileInfo(vplugin.fileName()).canonicalFilePath(), QFileInfo(QStringLiteral(VERSIONEDPLUGIN_FILE)).canonicalFilePath());
0111 
0112         KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
0113         QCOMPARE(QFileInfo(jplugin.fileName()).canonicalFilePath(), QFileInfo(QStringLiteral(JSONPLUGIN_FILE)).canonicalFilePath());
0114 
0115         KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
0116         QVERIFY2(eplugin.fileName().isEmpty(), qPrintable(eplugin.fileName()));
0117 
0118         KPluginLoader noplugin(QStringLiteral("idonotexist"));
0119         QVERIFY2(noplugin.fileName().isEmpty(), qPrintable(noplugin.fileName()));
0120     }
0121 
0122     void testInstance()
0123     {
0124         KPluginLoader vplugin(QStringLiteral("versionedplugin"));
0125         QVERIFY(vplugin.instance());
0126 
0127         KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
0128         QVERIFY(jplugin.instance());
0129 
0130         KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
0131         QVERIFY(!eplugin.instance());
0132 
0133         KPluginLoader noplugin(QStringLiteral("idonotexist"));
0134         QVERIFY(!noplugin.instance());
0135     }
0136 
0137     void testIsLoaded()
0138     {
0139         KPluginLoader vplugin(QStringLiteral("versionedplugin"));
0140         QVERIFY(!vplugin.isLoaded());
0141         QVERIFY(vplugin.load());
0142         QVERIFY(vplugin.isLoaded());
0143 
0144         KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
0145         QVERIFY(!jplugin.isLoaded());
0146         QVERIFY(jplugin.load());
0147         QVERIFY(jplugin.isLoaded());
0148 
0149         KPluginLoader aplugin(QStringLiteral("alwaysunloadplugin"));
0150         QVERIFY(!aplugin.isLoaded());
0151         QVERIFY(aplugin.load());
0152         QVERIFY(aplugin.isLoaded());
0153         if (aplugin.unload()) {
0154             QVERIFY(!aplugin.isLoaded());
0155         } else {
0156             qCDebug(KCOREADDONS_DEBUG) << "Could not unload alwaysunloadplugin:" << aplugin.errorString();
0157         }
0158 
0159         KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
0160         QVERIFY(!eplugin.isLoaded());
0161         QVERIFY(!eplugin.load());
0162         QVERIFY(!eplugin.isLoaded());
0163 
0164         KPluginLoader noplugin(QStringLiteral("idonotexist"));
0165         QVERIFY(!noplugin.isLoaded());
0166         QVERIFY(!noplugin.load());
0167         QVERIFY(!noplugin.isLoaded());
0168     }
0169 
0170     void testLoad()
0171     {
0172         KPluginLoader vplugin(QStringLiteral("versionedplugin"));
0173         QVERIFY(vplugin.load());
0174 
0175         KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
0176         QVERIFY(jplugin.load());
0177 
0178         KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
0179         QVERIFY(!eplugin.load());
0180 
0181         KPluginLoader noplugin(QStringLiteral("idonotexist"));
0182         QVERIFY(!noplugin.load());
0183     }
0184 
0185     void testLoadHints()
0186     {
0187         KPluginLoader aplugin(QStringLiteral("alwaysunloadplugin"));
0188         aplugin.setLoadHints(QLibrary::ResolveAllSymbolsHint);
0189         QCOMPARE(aplugin.loadHints(), QLibrary::ResolveAllSymbolsHint);
0190     }
0191 
0192     void testMetaData()
0193     {
0194         KPluginLoader aplugin(QStringLiteral("alwaysunloadplugin"));
0195         QJsonObject ametadata = aplugin.metaData();
0196         QVERIFY(!ametadata.isEmpty());
0197         QVERIFY(ametadata.keys().contains(QLatin1String("IID")));
0198         QJsonValue ametadata_metadata = ametadata.value(QStringLiteral("MetaData"));
0199         QVERIFY(ametadata_metadata.toObject().isEmpty());
0200         QVERIFY(!aplugin.isLoaded()); // didn't load anything
0201 
0202         KPluginLoader jplugin(KPluginName(QStringLiteral("jsonplugin")));
0203         QJsonObject jmetadata = jplugin.metaData();
0204         QVERIFY(!jmetadata.isEmpty());
0205         QJsonValue jmetadata_metadata = jmetadata.value(QStringLiteral("MetaData"));
0206         QVERIFY(jmetadata_metadata.isObject());
0207         QJsonObject jmetadata_obj = jmetadata_metadata.toObject();
0208         QVERIFY(!jmetadata_obj.isEmpty());
0209         QJsonValue comment = jmetadata_obj.value(QStringLiteral("KPlugin")).toObject().value(QStringLiteral("Description"));
0210         QVERIFY(comment.isString());
0211         QCOMPARE(comment.toString(), QString::fromLatin1("This is a plugin"));
0212 
0213         KPluginLoader eplugin(KPluginName::fromErrorString(QStringLiteral("there was an error")));
0214         QVERIFY(eplugin.metaData().isEmpty());
0215 
0216         KPluginLoader noplugin(QStringLiteral("idonotexist"));
0217         QVERIFY(noplugin.metaData().isEmpty());
0218     }
0219 
0220     void testUnload()
0221     {
0222         KPluginLoader aplugin(QStringLiteral("alwaysunloadplugin"));
0223         QVERIFY(aplugin.load());
0224         // may need QEXPECT_FAIL on some platforms...
0225         QVERIFY(aplugin.unload());
0226     }
0227 
0228     void testInstantiatePlugins()
0229     {
0230         const QString plugin1Path = KPluginLoader::findPlugin(QStringLiteral("jsonplugin"));
0231         QVERIFY2(!plugin1Path.isEmpty(), qPrintable(plugin1Path));
0232         const QString plugin2Path = KPluginLoader::findPlugin(QStringLiteral("unversionedplugin"));
0233         QVERIFY2(!plugin2Path.isEmpty(), qPrintable(plugin2Path));
0234         const QString plugin3Path = KPluginLoader::findPlugin(QStringLiteral("jsonplugin2"));
0235         QVERIFY2(!plugin3Path.isEmpty(), qPrintable(plugin3Path));
0236 
0237         QTemporaryDir temp;
0238         QVERIFY(temp.isValid());
0239         QDir dir(temp.path());
0240         QVERIFY2(QFile::copy(plugin1Path, dir.absoluteFilePath(QFileInfo(plugin1Path).fileName())),
0241                  qPrintable(dir.absoluteFilePath(QFileInfo(plugin1Path).fileName())));
0242         QVERIFY2(QFile::copy(plugin2Path, dir.absoluteFilePath(QFileInfo(plugin2Path).fileName())),
0243                  qPrintable(dir.absoluteFilePath(QFileInfo(plugin2Path).fileName())));
0244         QVERIFY2(QFile::copy(plugin3Path, dir.absoluteFilePath(QFileInfo(plugin3Path).fileName())),
0245                  qPrintable(dir.absoluteFilePath(QFileInfo(plugin3Path).fileName())));
0246 
0247         // only jsonplugin, since unversionedplugin has no json metadata
0248         QList<QObject *> plugins = KPluginLoader::instantiatePlugins(temp.path());
0249         QCOMPARE(plugins.size(), 2);
0250         QStringList classNames = QStringList() << QString::fromLatin1(plugins[0]->metaObject()->className())
0251                                                << QString::fromLatin1(plugins[1]->metaObject()->className());
0252         classNames.sort();
0253         QCOMPARE(classNames[0], QStringLiteral("jsonplugin2"));
0254         QCOMPARE(classNames[1], QStringLiteral("jsonpluginfa"));
0255         qDeleteAll(plugins);
0256 
0257         // try filter
0258         plugins = KPluginLoader::instantiatePlugins(temp.path(), [](const KPluginMetaData &md) {
0259             return md.pluginId() == QLatin1String("jsonplugin");
0260         });
0261         QCOMPARE(plugins.size(), 1);
0262         QCOMPARE(plugins[0]->metaObject()->className(), "jsonpluginfa");
0263         qDeleteAll(plugins);
0264 
0265         plugins = KPluginLoader::instantiatePlugins(temp.path(), [](const KPluginMetaData &md) {
0266             return md.pluginId() == QLatin1String("unversionedplugin");
0267         });
0268         QCOMPARE(plugins.size(), 0);
0269 
0270         plugins = KPluginLoader::instantiatePlugins(temp.path(), [](const KPluginMetaData &md) {
0271             return md.pluginId() == QLatin1String("foobar"); // ID does not match file name, is set in JSON
0272         });
0273         QCOMPARE(plugins.size(), 1);
0274         QCOMPARE(plugins[0]->metaObject()->className(), "jsonplugin2");
0275         qDeleteAll(plugins);
0276 
0277         // check that parent gets set
0278         plugins = KPluginLoader::instantiatePlugins(
0279             temp.path(),
0280             [](const KPluginMetaData &) {
0281                 return true;
0282             },
0283             this);
0284         QCOMPARE(plugins.size(), 2);
0285         QCOMPARE(plugins[0]->parent(), this);
0286         QCOMPARE(plugins[1]->parent(), this);
0287         qDeleteAll(plugins);
0288 
0289         const QString subDirName = dir.dirName();
0290         QVERIFY(dir.cdUp()); // should now point to /tmp on Linux
0291         LibraryPathRestorer restorer(QCoreApplication::libraryPaths());
0292         // instantiate using relative path
0293         // make sure library path is set up correctly
0294         QCoreApplication::setLibraryPaths(QStringList() << dir.absolutePath());
0295         QVERIFY(!QDir::isAbsolutePath(subDirName));
0296         plugins = KPluginLoader::instantiatePlugins(subDirName);
0297         QCOMPARE(plugins.size(), 2);
0298         classNames = QStringList() << QString::fromLatin1(plugins[0]->metaObject()->className()) << QString::fromLatin1(plugins[1]->metaObject()->className());
0299         classNames.sort();
0300         QCOMPARE(classNames[0], QStringLiteral("jsonplugin2"));
0301         QCOMPARE(classNames[1], QStringLiteral("jsonpluginfa"));
0302         qDeleteAll(plugins);
0303     }
0304 
0305     void testForEachPlugin()
0306     {
0307         const QString jsonPluginSrc = KPluginLoader::findPlugin(QStringLiteral("jsonplugin"));
0308         QVERIFY2(!jsonPluginSrc.isEmpty(), qPrintable(jsonPluginSrc));
0309         const QString unversionedPluginSrc = KPluginLoader::findPlugin(QStringLiteral("unversionedplugin"));
0310         QVERIFY2(!unversionedPluginSrc.isEmpty(), qPrintable(unversionedPluginSrc));
0311         const QString jsonPlugin2Src = KPluginLoader::findPlugin(QStringLiteral("jsonplugin2"));
0312         QVERIFY2(!jsonPlugin2Src.isEmpty(), qPrintable(jsonPlugin2Src));
0313 
0314         QTemporaryDir temp;
0315         QVERIFY(temp.isValid());
0316         QDir dir(temp.path());
0317         QVERIFY(dir.mkdir(QStringLiteral("for-each-plugin")));
0318         QVERIFY(dir.cd(QStringLiteral("for-each-plugin")));
0319         const QString jsonPluginDest = dir.absoluteFilePath(QFileInfo(jsonPluginSrc).fileName());
0320         QVERIFY2(QFile::copy(jsonPluginSrc, jsonPluginDest), qPrintable(jsonPluginDest));
0321         const QString unversionedPluginDest = dir.absoluteFilePath(QFileInfo(unversionedPluginSrc).fileName());
0322         QVERIFY2(QFile::copy(unversionedPluginSrc, unversionedPluginDest), qPrintable(unversionedPluginDest));
0323         // copy jsonplugin2 to a "for-each-plugin" subdirectory in a different directory
0324         QTemporaryDir temp2;
0325         QVERIFY(temp2.isValid());
0326         QDir dir2(temp2.path());
0327         QVERIFY(dir2.mkdir(QStringLiteral("for-each-plugin")));
0328         QVERIFY(dir2.cd(QStringLiteral("for-each-plugin")));
0329         const QString jsonPlugin2Dest = dir2.absoluteFilePath(QFileInfo(jsonPlugin2Src).fileName());
0330         QVERIFY2(QFile::copy(jsonPlugin2Src, jsonPlugin2Dest), qPrintable(jsonPlugin2Dest));
0331 
0332         QStringList foundPlugins;
0333         QStringList expectedPlugins;
0334         const auto addToFoundPlugins = [&](const QString &path) {
0335             QVERIFY(!path.isEmpty());
0336             foundPlugins.append(path);
0337         };
0338 
0339         // test finding with absolute path
0340         expectedPlugins = QStringList() << jsonPluginDest << unversionedPluginDest;
0341         expectedPlugins.sort();
0342         KPluginLoader::forEachPlugin(dir.path(), addToFoundPlugins);
0343         foundPlugins.sort();
0344         QCOMPARE(foundPlugins, expectedPlugins);
0345 
0346         expectedPlugins = QStringList() << jsonPlugin2Dest;
0347         expectedPlugins.sort();
0348         foundPlugins.clear();
0349         KPluginLoader::forEachPlugin(dir2.path(), addToFoundPlugins);
0350         foundPlugins.sort();
0351         QCOMPARE(foundPlugins, expectedPlugins);
0352 
0353         // now test relative paths
0354 
0355         LibraryPathRestorer restorer(QCoreApplication::libraryPaths());
0356         QCoreApplication::setLibraryPaths(QStringList() << temp.path());
0357         expectedPlugins = QStringList() << jsonPluginDest << unversionedPluginDest;
0358         expectedPlugins.sort();
0359         foundPlugins.clear();
0360         KPluginLoader::forEachPlugin(QStringLiteral("for-each-plugin"), addToFoundPlugins);
0361         foundPlugins.sort();
0362         QCOMPARE(foundPlugins, expectedPlugins);
0363 
0364         QCoreApplication::setLibraryPaths(QStringList() << temp2.path());
0365         expectedPlugins = QStringList() << jsonPlugin2Dest;
0366         expectedPlugins.sort();
0367         foundPlugins.clear();
0368         KPluginLoader::forEachPlugin(QStringLiteral("for-each-plugin"), addToFoundPlugins);
0369         foundPlugins.sort();
0370         QCOMPARE(foundPlugins, expectedPlugins);
0371 
0372         QCoreApplication::setLibraryPaths(QStringList() << temp.path() << temp2.path());
0373         expectedPlugins = QStringList() << jsonPluginDest << unversionedPluginDest << jsonPlugin2Dest;
0374         expectedPlugins.sort();
0375         foundPlugins.clear();
0376         KPluginLoader::forEachPlugin(QStringLiteral("for-each-plugin"), addToFoundPlugins);
0377         foundPlugins.sort();
0378         QCOMPARE(foundPlugins, expectedPlugins);
0379     }
0380 #endif
0381 };
0382 
0383 QTEST_MAIN(KPluginLoaderTest)
0384 
0385 #include "kpluginloadertest.moc"