#include "../../shared/testhttpserver.h"
#include "../../shared/util.h"
-#define SERVER_ADDR "http://127.0.0.1:14450"
-#define SERVER_PORT 14450
+#define SERVER_ADDR "http://127.0.0.1:14456"
+#define SERVER_PORT 14456
+// Note: this test does not use module identifier directives in the qmldir files, because
+// it would result in repeated attempts to insert types into the same namespace.
+// This occurs because type registration is process-global, while the test
+// cases should really be run in proper per-process isolation.
class tst_qqmlmoduleplugin : public QQmlDataTest
{
void implicitQmldir_data();
void importsNested();
void importsNested_data();
+ void importLocalModule();
+ void importLocalModule_data();
+ void importStrictModule();
+ void importStrictModule_data();
private:
QString m_importsDirectory;
+ QString m_dataImportsDirectory;
};
void tst_qqmlmoduleplugin::initTestCase()
{
QQmlDataTest::initTestCase();
- m_importsDirectory = directory() + QStringLiteral("/imports");
+ m_importsDirectory = QFINDTESTDATA(QStringLiteral("imports"));
QVERIFY2(QFileInfo(m_importsDirectory).isDir(),
qPrintable(QString::fromLatin1("Imports directory '%1' does not exist.").arg(m_importsDirectory)));
+ m_dataImportsDirectory = directory() + QStringLiteral("/imports");
+ QVERIFY2(QFileInfo(m_dataImportsDirectory).isDir(),
+ qPrintable(QString::fromLatin1("Imports directory '%1' does not exist.").arg(m_dataImportsDirectory)));
}
#define VERIFY_ERRORS(errorfile) \
engine.addImportPath(m_importsDirectory);
QTest::ignoreMessage(QtWarningMsg, "plugin created");
QTest::ignoreMessage(QtWarningMsg, "import worked");
+ QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFileUrl(QStringLiteral("works.qml")));
foreach (QQmlError err, component.errors())
qWarning() << err;
engine.addImportPath(m_importsDirectory);
QTest::ignoreMessage(QtWarningMsg, "plugin2 created");
QTest::ignoreMessage(QtWarningMsg, "import2 worked");
+ QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFileUrl(QStringLiteral("works2.qml")));
foreach (QQmlError err, component.errors())
qWarning() << err;
engine.addImportPath(m_importsDirectory);
QTest::ignoreMessage(QtWarningMsg, "plugin2.1 created");
QTest::ignoreMessage(QtWarningMsg, "import2.1 worked");
+ QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
QQmlComponent component(&engine, testFileUrl(QStringLiteral("works21.qml")));
foreach (QQmlError err, component.errors())
qWarning() << err;
QQmlEngine engine;
engine.addImportPath(path);
+ QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestPluginWithQmlFile' does not contain a module identifier directive - it cannot be protected from external registrations.");
+
QQmlComponent component(&engine, testFileUrl(QStringLiteral("pluginWithQmlFile.qml")));
foreach (QQmlError err, component.errors())
qWarning() << err;
{
TestHTTPServer server(SERVER_PORT);
QVERIFY(server.isValid());
- server.serveDirectory(m_importsDirectory);
+ server.serveDirectory(m_dataImportsDirectory);
QQmlEngine engine;
QQmlComponent component(&engine);
- component.setData("import \"http://127.0.0.1:14450/com/nokia/PureQmlModule\" \nComponentA { width: 300; ComponentB{} }", QUrl());
+ component.setData("import \"" SERVER_ADDR "/com/nokia/PureQmlModule\" \nComponentA { width: 300; ComponentB{} }", QUrl());
QTRY_COMPARE(component.status(), QQmlComponent::Ready);
QObject *object = component.create();
{
TestHTTPServer server(SERVER_PORT);
QVERIFY(server.isValid());
- server.serveDirectory(m_importsDirectory);
+ server.serveDirectory(m_dataImportsDirectory);
QQmlEngine engine;
- engine.addImportPath(m_importsDirectory);
+ engine.addImportPath(m_dataImportsDirectory);
QQmlComponent component(&engine);
component.setData("import com.nokia.PureQmlModule 1.0 \nComponentA { width: 300; ComponentB{} }", QUrl());
QQmlEngine engine;
engine.addImportPath(m_importsDirectory);
+ QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlMixedPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
+
{
QQmlComponent component(&engine, testFileUrl(QStringLiteral("importsMixedQmlCppPlugin.qml")));
QQmlEngine engine;
engine.addImportPath(m_importsDirectory);
+ static int count = 0;
+ if (++count == 1)
+ QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlVersionPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
+
QQmlComponent component(&engine, testFileUrl(file));
VERIFY_ERRORS(errorFile.toLatin1().constData());
}
QTest::ignoreMessage(QtWarningMsg, "QQmlComponent: Component is not ready");
}
+ static int count = 0;
+ if (++count == 1)
+ QTest::ignoreMessage(QtWarningMsg, "Module 'com.nokia.AutoTestQmlNestedPluginType' does not contain a module identifier directive - it cannot be protected from external registrations.");
+
QQmlComponent component(&engine, testFile(file));
QObject *obj = component.create();
}
}
+void tst_qqmlmoduleplugin::importLocalModule()
+{
+ QFETCH(QString, qml);
+ QFETCH(int, majorVersion);
+ QFETCH(int, minorVersion);
+
+ QQmlEngine engine;
+ QQmlComponent component(&engine);
+ component.setData(qml.toUtf8(), testFileUrl("empty.qml"));
+
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != 0);
+ QCOMPARE(object->property("majorVersion").value<int>(), majorVersion);
+ QCOMPARE(object->property("minorVersion").value<int>(), minorVersion);
+}
+
+void tst_qqmlmoduleplugin::importLocalModule_data()
+{
+ QTest::addColumn<QString>("qml");
+ QTest::addColumn<int>("majorVersion");
+ QTest::addColumn<int>("minorVersion");
+
+ QTest::newRow("default version")
+ << "import \"localModule\"\n"
+ "TestComponent {}"
+ << 2 << 0;
+
+ QTest::newRow("specific version")
+ << "import \"localModule\" 1.1\n"
+ "TestComponent {}"
+ << 1 << 1;
+
+ QTest::newRow("lesser version")
+ << "import \"localModule\" 1.0\n"
+ "TestComponent {}"
+ << 1 << 0;
+
+ // Note: this does not match the behaviour of installed modules, which fail for this case:
+ QTest::newRow("nonexistent version")
+ << "import \"localModule\" 1.3\n"
+ "TestComponent {}"
+ << 1 << 1;
+
+ QTest::newRow("high version")
+ << "import \"localModule\" 2.0\n"
+ "TestComponent {}"
+ << 2 << 0;
+}
+
+void tst_qqmlmoduleplugin::importStrictModule()
+{
+ QFETCH(QString, qml);
+ QFETCH(QString, warning);
+ QFETCH(QString, error);
+
+ if (!warning.isEmpty())
+ QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
+
+ QQmlEngine engine;
+ engine.addImportPath(m_importsDirectory);
+
+ QUrl url(testFileUrl("empty.qml"));
+
+ QQmlComponent component(&engine);
+ component.setData(qml.toUtf8(), url);
+
+ if (error.isEmpty()) {
+ QScopedPointer<QObject> object(component.create());
+ QVERIFY(object != 0);
+ } else {
+ QVERIFY(!component.isReady());
+ QCOMPARE(component.errors().count(), 1);
+ QCOMPARE(component.errors().first().toString(), url.toString() + error);
+ }
+}
+
+void tst_qqmlmoduleplugin::importStrictModule_data()
+{
+ QTest::addColumn<QString>("qml");
+ QTest::addColumn<QString>("warning");
+ QTest::addColumn<QString>("error");
+
+ QTest::newRow("success")
+ << "import com.nokia.StrictModule 1.0\n"
+ "MyPluginType {}"
+ << QString()
+ << QString();
+
+ QTest::newRow("wrong target")
+ << "import com.nokia.InvalidStrictModule 1.0\n"
+ "MyPluginType {}"
+ << QString()
+ << ":1:1: plugin cannot be loaded for module \"com.nokia.InvalidStrictModule\": Cannot install element 'MyPluginType' into unregistered namespace 'com.nokia.SomeOtherModule'";
+
+ QTest::newRow("non-strict clash")
+ << "import com.nokia.NonstrictModule 1.0\n"
+ "MyPluginType {}"
+ << "Module 'com.nokia.NonstrictModule' does not contain a module identifier directive - it cannot be protected from external registrations."
+ << ":1:1: plugin cannot be loaded for module \"com.nokia.NonstrictModule\": Cannot install element 'MyPluginType' into protected namespace 'com.nokia.StrictModule'";
+
+ QTest::newRow("non-strict preemption")
+ << "import com.nokia.PreemptiveModule 1.0\n"
+ "import com.nokia.PreemptedStrictModule 1.0\n"
+ "MyPluginType {}"
+ << "Module 'com.nokia.PreemptiveModule' does not contain a module identifier directive - it cannot be protected from external registrations."
+ << ":2:1: plugin cannot be loaded for module \"com.nokia.PreemptedStrictModule\": Namespace 'com.nokia.PreemptedStrictModule' has already been used for type registration";
+
+ QTest::newRow("invalid namespace")
+ << "import com.nokia.InvalidNamespaceModule 1.0\n"
+ "MyPluginType {}"
+ << QString()
+ << ":1:1: plugin cannot be loaded for module \"com.nokia.InvalidNamespaceModule\": Module namespace 'com.nokia.AwesomeModule' does not match import URI 'com.nokia.InvalidNamespaceModule'";
+
+ QTest::newRow("module directive must be first")
+ << "import com.nokia.InvalidFirstCommandModule 1.0\n"
+ "MyPluginType {}"
+ << QString()
+ << ":1:1: module identifier directive must be the first command in a qmldir file";
+}
+
QTEST_MAIN(tst_qqmlmoduleplugin)
#include "tst_qqmlmoduleplugin.moc"