Files
qt-creator/tests/auto/extensionsystem/pluginspec/tst_pluginspec.cpp
Marcus Tillmanns ef8455f270 ExtensionSystem: Rename PluginSpecImpl to CppPluginSpec
Since we now have multiple classes inheriting from PluginSpec it makes sense
to rename PluginSpecImpl to the more accurate CppPluginSpec as it deals with
compiled plugins only.

Amends b39b192518

Change-Id: Icae9daed2be5a258a9918731a881c72cbe4f0fa4
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
2024-04-19 11:26:03 +00:00

346 lines
12 KiB
C++

// 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 <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginmanager_p.h>
#include <extensionsystem/pluginspec.h>
#include <QJsonDocument>
#include <QJsonObject>
#include <QObject>
#include <QMetaObject>
#include <QtTest>
#include <QDir>
using namespace ExtensionSystem;
static QJsonObject metaData(const QString &fileName)
{
QFile f(fileName);
if (!f.open(QIODevice::ReadOnly)) {
qWarning() << "Could not open" << fileName;
return {};
}
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(f.readAll(), &error);
if (error.error != QJsonParseError::NoError) {
qWarning() << "Could not parse" << fileName << ":" << error.errorString();
return {};
}
return doc.object();
}
static QString libraryName(const QString &basename)
{
#if defined(Q_OS_MACOS)
return QLatin1String("lib") + basename + QLatin1String("_debug.dylib");
#elif defined(Q_OS_UNIX)
return QLatin1String("lib") + basename + QLatin1String(".so");
#else
return basename + QLatin1String(DLL_INFIX ".dll");
#endif
}
class tst_PluginSpec : public QObject
{
Q_OBJECT
private slots:
void read();
void readError();
void isValidVersion();
void versionCompare();
void provides();
void experimental();
void locationAndPath();
void resolveDependencies();
void loadLibrary();
void initializePlugin();
void initializeExtensions();
void init();
void initTestCase();
void cleanupTestCase();
private:
PluginManager *pm;
};
void tst_PluginSpec::init()
{
QVERIFY(QDir::setCurrent(QLatin1String(PLUGINSPEC_DIR)));
}
void tst_PluginSpec::initTestCase()
{
pm = new PluginManager;
PluginManager::setPluginIID(QLatin1String("plugin"));
}
void tst_PluginSpec::cleanupTestCase()
{
delete pm;
pm = 0;
}
void tst_PluginSpec::read()
{
CppPluginSpec spec;
QCOMPARE(spec.state(), PluginSpec::Invalid);
QVERIFY(spec.readMetaData(metaData("testspecs/spec1.json")));
QVERIFY(!spec.hasError());
QVERIFY(spec.errorString().isEmpty());
QCOMPARE(spec.name(), QString("test"));
QCOMPARE(spec.version(), QString("1.0.1"));
QCOMPARE(spec.compatVersion(), QString("1.0.0"));
QCOMPARE(spec.isRequired(), false);
QCOMPARE(spec.isExperimental(), false);
QCOMPARE(spec.isEnabledBySettings(), true);
QCOMPARE(spec.vendor(), QString("The Qt Company Ltd"));
QCOMPARE(spec.copyright(), QString("(C) 2015 The Qt Company Ltd"));
QCOMPARE(spec.license(), QString("This is a default license bla\nblubbblubb\nend of terms"));
QCOMPARE(spec.description(), QString("This plugin is just a test."));
QCOMPARE(
spec.longDescription(),
QString(
"This plugin is just a test.\n it demonstrates the great use of the plugin spec."));
QCOMPARE(spec.url(), QString("http://www.qt.io"));
PluginDependency dep1;
dep1.name = QString("SomeOtherPlugin");
dep1.version = QString("2.3.0_2");
PluginDependency dep2;
dep2.name = QString("EvenOther");
dep2.version = QString("1.0.0");
QCOMPARE(spec.dependencies(), QVector<PluginDependency>() << dep1 << dep2);
// test missing compatVersion behavior
// and 'required' attribute
QVERIFY(spec.readMetaData(metaData("testspecs/spec2.json")));
QCOMPARE(spec.version(), QString("3.1.4_10"));
QCOMPARE(spec.compatVersion(), QString("3.1.4_10"));
QCOMPARE(spec.isRequired(), true);
}
void tst_PluginSpec::readError()
{
CppPluginSpec spec;
QCOMPARE(spec.state(), PluginSpec::Invalid);
QVERIFY(!spec.readMetaData(metaData("non-existing-file.json")));
QCOMPARE(spec.state(), PluginSpec::Invalid);
QVERIFY(!spec.hasError());
QVERIFY(spec.errorString().isEmpty());
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong2.json")));
QCOMPARE(spec.state(), PluginSpec::Invalid);
QVERIFY(spec.hasError());
QVERIFY(!spec.errorString().isEmpty());
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong3.json")));
QCOMPARE(spec.state(), PluginSpec::Invalid);
QVERIFY(spec.hasError());
QVERIFY(!spec.errorString().isEmpty());
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong4.json")));
QCOMPARE(spec.state(), PluginSpec::Invalid);
QVERIFY(spec.hasError());
QVERIFY(!spec.errorString().isEmpty());
QVERIFY(spec.readMetaData(metaData("testspecs/spec_wrong5.json")));
QCOMPARE(spec.state(), PluginSpec::Invalid);
QVERIFY(spec.hasError());
QVERIFY(!spec.errorString().isEmpty());
}
void tst_PluginSpec::isValidVersion()
{
QVERIFY(PluginSpec::isValidVersion("2"));
QVERIFY(PluginSpec::isValidVersion("53"));
QVERIFY(PluginSpec::isValidVersion("52_1"));
QVERIFY(PluginSpec::isValidVersion("3.12"));
QVERIFY(PluginSpec::isValidVersion("31.1_12"));
QVERIFY(PluginSpec::isValidVersion("31.1.0"));
QVERIFY(PluginSpec::isValidVersion("1.0.2_1"));
QVERIFY(!PluginSpec::isValidVersion(""));
QVERIFY(!PluginSpec::isValidVersion("1..0"));
QVERIFY(!PluginSpec::isValidVersion("1.0_"));
QVERIFY(!PluginSpec::isValidVersion("1.0.0.0"));
}
void tst_PluginSpec::versionCompare()
{
QVERIFY(PluginSpec::versionCompare("3", "3") == 0);
QVERIFY(PluginSpec::versionCompare("3.0.0", "3") == 0);
QVERIFY(PluginSpec::versionCompare("3.0", "3") == 0);
QVERIFY(PluginSpec::versionCompare("3.0.0_1", "3_1") == 0);
QVERIFY(PluginSpec::versionCompare("3.0_21", "3_21") == 0);
QVERIFY(PluginSpec::versionCompare("3", "1") > 0);
QVERIFY(PluginSpec::versionCompare("3", "1.0_12") > 0);
QVERIFY(PluginSpec::versionCompare("3_1", "3") > 0);
QVERIFY(PluginSpec::versionCompare("3.1.0_23", "3.1") > 0);
QVERIFY(PluginSpec::versionCompare("3.1_23", "3.1_12") > 0);
QVERIFY(PluginSpec::versionCompare("1", "3") < 0);
QVERIFY(PluginSpec::versionCompare("1.0_12", "3") < 0);
QVERIFY(PluginSpec::versionCompare("3", "3_1") < 0);
QVERIFY(PluginSpec::versionCompare("3.1", "3.1.0_23") < 0);
QVERIFY(PluginSpec::versionCompare("3.1_12", "3.1_23") < 0);
}
void tst_PluginSpec::provides()
{
CppPluginSpec spec;
QVERIFY(spec.readMetaData(metaData("testspecs/simplespec.json")));
QVERIFY(!spec.provides("SomeOtherPlugin", "2.2.3_9"));
QVERIFY(!spec.provides("MyPlugin", "2.2.3_10"));
QVERIFY(!spec.provides("MyPlugin", "2.2.4"));
QVERIFY(!spec.provides("MyPlugin", "2.3.11_1"));
QVERIFY(!spec.provides("MyPlugin", "2.3"));
QVERIFY(!spec.provides("MyPlugin", "3.0"));
QVERIFY(!spec.provides("MyPlugin", "1.9.9_99"));
QVERIFY(!spec.provides("MyPlugin", "1.9"));
QVERIFY(!spec.provides("MyPlugin", "0.9"));
QVERIFY(!spec.provides("MyPlugin", "1"));
QVERIFY(spec.provides("myplugin", "2.2.3_9"));
QVERIFY(spec.provides("MyPlugin", "2.2.3_9"));
QVERIFY(spec.provides("MyPlugin", "2.2.3_8"));
QVERIFY(spec.provides("MyPlugin", "2.2.3"));
QVERIFY(spec.provides("MyPlugin", "2.2.2"));
QVERIFY(spec.provides("MyPlugin", "2.1.2_10"));
QVERIFY(spec.provides("MyPlugin", "2.0_10"));
QVERIFY(spec.provides("MyPlugin", "2"));
}
void tst_PluginSpec::experimental()
{
CppPluginSpec spec;
QVERIFY(spec.readMetaData(metaData("testspecs/simplespec_experimental.json")));
QCOMPARE(spec.isExperimental(), true);
QCOMPARE(spec.isEnabledBySettings(), false);
}
void tst_PluginSpec::locationAndPath()
{
Utils::expected_str<PluginSpec *> ps = readCppPluginSpec(
QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
+ libraryName(QLatin1String("test")));
QVERIFY(ps);
CppPluginSpec *spec = static_cast<CppPluginSpec *>(ps.value());
QCOMPARE(spec->location(), QString(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin")));
QCOMPARE(spec->filePath(),
QString(QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
+ libraryName(QLatin1String("test"))));
}
void tst_PluginSpec::resolveDependencies()
{
QVector<PluginSpec *> specs;
PluginSpec *spec1 = new CppPluginSpec();
specs.append(spec1);
spec1->readMetaData(metaData("testdependencies/spec1.json"));
spec1->setState(PluginSpec::Read); // fake read state for plugin resolving
PluginSpec *spec2 = new CppPluginSpec();
specs.append(spec2);
spec2->readMetaData(metaData("testdependencies/spec2.json"));
spec2->setState(PluginSpec::Read); // fake read state for plugin resolving
PluginSpec *spec3 = new CppPluginSpec();
specs.append(spec3);
spec3->readMetaData(metaData("testdependencies/spec3.json"));
spec3->setState(PluginSpec::Read); // fake read state for plugin resolving
PluginSpec *spec4 = new CppPluginSpec();
specs.append(spec4);
spec4->readMetaData(metaData("testdependencies/spec4.json"));
spec4->setState(PluginSpec::Read); // fake read state for plugin resolving
PluginSpec *spec5 = new CppPluginSpec();
specs.append(spec5);
spec5->readMetaData(metaData("testdependencies/spec5.json"));
spec5->setState(PluginSpec::Read); // fake read state for plugin resolving
QVERIFY(spec1->resolveDependencies(specs));
QCOMPARE(spec1->dependencySpecs().size(), 2);
QVERIFY(!spec1->dependencySpecs().key(spec2).name.isEmpty());
QVERIFY(!spec1->dependencySpecs().key(spec3).name.isEmpty());
QCOMPARE(spec1->state(), PluginSpec::Resolved);
QVERIFY(!spec4->resolveDependencies(specs));
QVERIFY(spec4->hasError());
QCOMPARE(spec4->state(), PluginSpec::Read);
}
void tst_PluginSpec::loadLibrary()
{
Utils::expected_str<PluginSpec *> ps = readCppPluginSpec(
QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
+ libraryName(QLatin1String("test")));
QVERIFY(ps);
CppPluginSpec *spec = static_cast<CppPluginSpec *>(ps.value());
QVERIFY(spec->resolveDependencies(QVector<PluginSpec *>()));
QVERIFY2(spec->loadLibrary(), qPrintable(spec->errorString()));
QVERIFY(spec->plugin() != 0);
QVERIFY(QLatin1String(spec->plugin()->metaObject()->className())
== QLatin1String("MyPlugin::MyPluginImpl"));
QCOMPARE(spec->state(), PluginSpec::Loaded);
QVERIFY(!spec->hasError());
delete *ps;
}
void tst_PluginSpec::initializePlugin()
{
Utils::expected_str<PluginSpec *> ps = readCppPluginSpec(
QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
+ libraryName(QLatin1String("test")));
QVERIFY(ps);
CppPluginSpec *spec = static_cast<CppPluginSpec *>(ps.value());
QVERIFY(spec->resolveDependencies(QVector<PluginSpec *>()));
QVERIFY2(spec->loadLibrary(), qPrintable(spec->errorString()));
bool isInitialized;
QMetaObject::invokeMethod(spec->plugin(),
"isInitialized",
Qt::DirectConnection,
Q_RETURN_ARG(bool, isInitialized));
QVERIFY(!isInitialized);
QVERIFY(spec->initializePlugin());
QCOMPARE(spec->state(), PluginSpec::Initialized);
QVERIFY(!spec->hasError());
QMetaObject::invokeMethod(spec->plugin(),
"isInitialized",
Qt::DirectConnection,
Q_RETURN_ARG(bool, isInitialized));
QVERIFY(isInitialized);
}
void tst_PluginSpec::initializeExtensions()
{
Utils::expected_str<PluginSpec *> ps = readCppPluginSpec(
QLatin1String(PLUGIN_DIR) + QLatin1String("/testplugin/")
+ libraryName(QLatin1String("test")));
QVERIFY(ps);
CppPluginSpec *spec = static_cast<CppPluginSpec *>(ps.value());
QVERIFY(spec->resolveDependencies(QVector<PluginSpec *>()));
QVERIFY2(spec->loadLibrary(), qPrintable(spec->errorString()));
bool isExtensionsInitialized;
QVERIFY(spec->initializePlugin());
QMetaObject::invokeMethod(spec->plugin(),
"isExtensionsInitialized",
Qt::DirectConnection,
Q_RETURN_ARG(bool, isExtensionsInitialized));
QVERIFY(!isExtensionsInitialized);
QVERIFY(spec->initializeExtensions());
QCOMPARE(spec->state(), PluginSpec::Running);
QVERIFY(!spec->hasError());
QMetaObject::invokeMethod(spec->plugin(),
"isExtensionsInitialized",
Qt::DirectConnection,
Q_RETURN_ARG(bool, isExtensionsInitialized));
QVERIFY(isExtensionsInitialized);
}
QTEST_GUILESS_MAIN(tst_PluginSpec)
#include "tst_pluginspec.moc"