1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativecomponent.h>
47 #include "../../shared/testhttpserver.h"
48 #include "../../shared/util.h"
50 #define SERVER_ADDR "http://127.0.0.1:14450"
51 #define SERVER_PORT 14450
54 class tst_qdeclarativemoduleplugin : public QDeclarativeDataTest
60 virtual void initTestCase();
62 void importsPlugin2();
63 void importsPlugin21();
64 void importsMixedQmlCppPlugin();
65 void incorrectPluginCase();
66 void importPluginWithQmlFile();
67 void remoteImportWithQuotedUrl();
68 void remoteImportWithUnquotedUri();
69 void versionNotInstalled();
70 void versionNotInstalled_data();
71 void implicitQmldir();
72 void implicitQmldir_data();
75 QString m_importsDirectory;
78 void tst_qdeclarativemoduleplugin::initTestCase()
80 QDeclarativeDataTest::initTestCase();
81 m_importsDirectory = directory() + QStringLiteral("/imports");
82 QVERIFY2(QFileInfo(m_importsDirectory).isDir(),
83 qPrintable(QString::fromLatin1("Imports directory '%1' does not exist.").arg(m_importsDirectory)));
86 #define VERIFY_ERRORS(errorfile) \
88 if (qgetenv("DEBUG") != "" && !component.errors().isEmpty()) \
89 qWarning() << "Unexpected Errors:" << component.errors(); \
90 QVERIFY(!component.isError()); \
91 QVERIFY(component.errors().isEmpty()); \
93 QString verify_errors_file_name = testFile(errorfile); \
94 QFile file(verify_errors_file_name); \
95 QVERIFY(file.open(QIODevice::ReadOnly | QIODevice::Text)); \
96 QByteArray data = file.readAll(); \
98 QList<QByteArray> expected = data.split('\n'); \
99 expected.removeAll(QByteArray("")); \
100 QList<QDeclarativeError> errors = component.errors(); \
101 QList<QByteArray> actual; \
102 for (int ii = 0; ii < errors.count(); ++ii) { \
103 const QDeclarativeError &error = errors.at(ii); \
104 QByteArray errorStr = QByteArray::number(error.line()) + ":" + \
105 QByteArray::number(error.column()) + ":" + \
106 error.description().toUtf8(); \
107 actual << errorStr; \
109 if (qgetenv("DEBUG") != "" && expected != actual) { \
110 qWarning() << "Expected:" << expected << "Actual:" << actual; \
112 if (qgetenv("QDECLARATIVELANGUAGE_UPDATEERRORS") != "" && expected != actual) {\
113 QFile file(testFile(errorfile)); \
114 QVERIFY(file.open(QIODevice::WriteOnly)); \
115 for (int ii = 0; ii < actual.count(); ++ii) { \
116 file.write(actual.at(ii)); file.write("\n"); \
120 QCOMPARE(expected, actual); \
124 void tst_qdeclarativemoduleplugin::importsPlugin()
126 QDeclarativeEngine engine;
127 engine.addImportPath(m_importsDirectory);
128 QTest::ignoreMessage(QtWarningMsg, "plugin created");
129 QTest::ignoreMessage(QtWarningMsg, "import worked");
130 QDeclarativeComponent component(&engine, testFileUrl(QStringLiteral("works.qml")));
131 foreach (QDeclarativeError err, component.errors())
134 QObject *object = component.create();
135 QVERIFY(object != 0);
136 QCOMPARE(object->property("value").toInt(),123);
140 void tst_qdeclarativemoduleplugin::importsPlugin2()
142 QDeclarativeEngine engine;
143 engine.addImportPath(m_importsDirectory);
144 QTest::ignoreMessage(QtWarningMsg, "plugin2 created");
145 QTest::ignoreMessage(QtWarningMsg, "import2 worked");
146 QDeclarativeComponent component(&engine, testFileUrl(QStringLiteral("works2.qml")));
147 foreach (QDeclarativeError err, component.errors())
150 QObject *object = component.create();
151 QVERIFY(object != 0);
152 QCOMPARE(object->property("value").toInt(),123);
156 void tst_qdeclarativemoduleplugin::importsPlugin21()
158 QDeclarativeEngine engine;
159 engine.addImportPath(m_importsDirectory);
160 QTest::ignoreMessage(QtWarningMsg, "plugin2.1 created");
161 QTest::ignoreMessage(QtWarningMsg, "import2.1 worked");
162 QDeclarativeComponent component(&engine, testFileUrl(QStringLiteral("works21.qml")));
163 foreach (QDeclarativeError err, component.errors())
166 QObject *object = component.create();
167 QVERIFY(object != 0);
168 QCOMPARE(object->property("value").toInt(),123);
172 void tst_qdeclarativemoduleplugin::incorrectPluginCase()
174 QDeclarativeEngine engine;
175 engine.addImportPath(m_importsDirectory);
177 QDeclarativeComponent component(&engine, testFileUrl(QStringLiteral("incorrectCase.qml")));
179 QList<QDeclarativeError> errors = component.errors();
180 QCOMPARE(errors.count(), 1);
182 #if defined(Q_OS_MAC) || defined(Q_OS_WIN32)
183 #if defined(Q_OS_MAC)
184 QString libname = "libPluGin.dylib";
185 #elif defined(Q_OS_WIN32)
186 QString libname = "PluGin.dll";
188 QString expectedError = QLatin1String("plugin cannot be loaded for module \"com.nokia.WrongCase\": File name case mismatch for \"") + QDir(m_importsDirectory).filePath("com/nokia/WrongCase/" + libname) + QLatin1String("\"");
190 QString expectedError = QLatin1String("module \"com.nokia.WrongCase\" plugin \"PluGin\" not found");
193 QCOMPARE(errors.at(0).description(), expectedError);
196 void tst_qdeclarativemoduleplugin::importPluginWithQmlFile()
198 QString path = m_importsDirectory;
200 // QTBUG-16885: adding an import path with a lower-case "c:" causes assert failure
201 // (this only happens if the plugin includes pure QML files)
203 QVERIFY(path.at(0).isUpper() && path.at(1) == QLatin1Char(':'));
204 path = path.at(0).toLower() + path.mid(1);
207 QDeclarativeEngine engine;
208 engine.addImportPath(path);
210 QDeclarativeComponent component(&engine, testFileUrl(QStringLiteral("pluginWithQmlFile.qml")));
211 foreach (QDeclarativeError err, component.errors())
214 QObject *object = component.create();
215 QVERIFY(object != 0);
219 void tst_qdeclarativemoduleplugin::remoteImportWithQuotedUrl()
221 TestHTTPServer server(SERVER_PORT);
222 QVERIFY(server.isValid());
223 server.serveDirectory(m_importsDirectory);
225 QDeclarativeEngine engine;
226 QDeclarativeComponent component(&engine);
227 component.setData("import \"http://127.0.0.1:14450/com/nokia/PureQmlModule\" \nComponentA { width: 300; ComponentB{} }", QUrl());
229 QTRY_COMPARE(component.status(), QDeclarativeComponent::Ready);
230 QObject *object = component.create();
231 QCOMPARE(object->property("width").toInt(), 300);
232 QVERIFY(object != 0);
235 foreach (QDeclarativeError err, component.errors())
240 void tst_qdeclarativemoduleplugin::remoteImportWithUnquotedUri()
242 TestHTTPServer server(SERVER_PORT);
243 QVERIFY(server.isValid());
244 server.serveDirectory(m_importsDirectory);
246 QDeclarativeEngine engine;
247 engine.addImportPath(m_importsDirectory);
248 QDeclarativeComponent component(&engine);
249 component.setData("import com.nokia.PureQmlModule 1.0 \nComponentA { width: 300; ComponentB{} }", QUrl());
252 QTRY_COMPARE(component.status(), QDeclarativeComponent::Ready);
253 QObject *object = component.create();
254 QVERIFY(object != 0);
255 QCOMPARE(object->property("width").toInt(), 300);
258 foreach (QDeclarativeError err, component.errors())
265 void tst_qdeclarativemoduleplugin::importsMixedQmlCppPlugin()
267 QDeclarativeEngine engine;
268 engine.addImportPath(m_importsDirectory);
271 QDeclarativeComponent component(&engine, testFileUrl(QStringLiteral("importsMixedQmlCppPlugin.qml")));
273 QObject *o = component.create();
274 QVERIFY2(o != 0, QDeclarativeDataTest::msgComponentError(component, &engine));
275 QCOMPARE(o->property("test").toBool(), true);
280 QDeclarativeComponent component(&engine, testFileUrl(QStringLiteral("importsMixedQmlCppPlugin.2.qml")));
282 QObject *o = component.create();
283 QVERIFY2(o != 0, QDeclarativeDataTest::msgComponentError(component, &engine));
284 QCOMPARE(o->property("test").toBool(), true);
285 QCOMPARE(o->property("test2").toBool(), true);
292 void tst_qdeclarativemoduleplugin::versionNotInstalled_data()
294 QTest::addColumn<QString>("file");
295 QTest::addColumn<QString>("errorFile");
297 QTest::newRow("versionNotInstalled") << "versionNotInstalled.qml" << "versionNotInstalled.errors.txt";
298 QTest::newRow("versionNotInstalled") << "versionNotInstalled.2.qml" << "versionNotInstalled.2.errors.txt";
301 void tst_qdeclarativemoduleplugin::versionNotInstalled()
303 QFETCH(QString, file);
304 QFETCH(QString, errorFile);
306 QDeclarativeEngine engine;
307 engine.addImportPath(m_importsDirectory);
309 QDeclarativeComponent component(&engine, testFileUrl(file));
310 VERIFY_ERRORS(errorFile.toLatin1().constData());
314 // test that errors are reporting correctly for plugin loading and qmldir parsing
315 void tst_qdeclarativemoduleplugin::implicitQmldir_data()
317 QTest::addColumn<QString>("directory");
318 QTest::addColumn<QString>("file");
319 QTest::addColumn<QString>("errorFile");
321 // parsing qmldir succeeds, but plugin specified in the qmldir file doesn't exist
322 QTest::newRow("implicitQmldir") << "implicit1" << "temptest.qml" << "implicitQmldir.errors.txt";
324 // parsing qmldir fails due to syntax errors, etc.
325 QTest::newRow("implicitQmldir2") << "implicit2" << "temptest2.qml" << "implicitQmldir.2.errors.txt";
327 void tst_qdeclarativemoduleplugin::implicitQmldir()
329 QFETCH(QString, directory);
330 QFETCH(QString, file);
331 QFETCH(QString, errorFile);
333 QString importPath = testFile(directory);
334 QString fileName = directory + QDir::separator() + file;
335 QString errorFileName = directory + QDir::separator() + errorFile;
336 QUrl testUrl = testFileUrl(fileName);
338 QDeclarativeEngine engine;
339 engine.addImportPath(importPath);
341 QDeclarativeComponent component(&engine, testUrl);
342 QList<QDeclarativeError> errors = component.errors();
343 VERIFY_ERRORS(errorFileName.toLatin1().constData());
344 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
345 QObject *obj = component.create();
351 QTEST_MAIN(tst_qdeclarativemoduleplugin)
353 #include "tst_qdeclarativemoduleplugin.moc"