1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the test suite of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtTest/QtTest>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativeimageprovider.h>
45 #include <private/qquickimage_p.h>
46 #include <QImageReader>
47 #include <QWaitCondition>
49 Q_DECLARE_METATYPE(QDeclarativeImageProvider*);
51 class tst_qdeclarativeimageprovider : public QObject
55 tst_qdeclarativeimageprovider()
60 void requestImage_sync_data();
61 void requestImage_sync();
62 void requestImage_async_data();
63 void requestImage_async();
65 void requestPixmap_sync_data();
66 void requestPixmap_sync();
67 void requestPixmap_async();
69 void removeProvider_data();
70 void removeProvider();
75 QString newImageFileName() const;
76 void fillRequestTestsData(const QString &id);
77 void runTest(bool async, QDeclarativeImageProvider *provider);
81 class TestQImageProvider : public QDeclarativeImageProvider
84 TestQImageProvider(bool *deleteWatch = 0)
85 : QDeclarativeImageProvider(Image), deleteWatch(deleteWatch)
95 QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize)
99 if (id == QLatin1String("no-such-file.png"))
104 QImage image(width, height, QImage::Format_RGB32);
106 *size = QSize(width, height);
107 if (requestedSize.isValid())
108 image = image.scaled(requestedSize);
115 Q_DECLARE_METATYPE(TestQImageProvider*);
118 class TestQPixmapProvider : public QDeclarativeImageProvider
121 TestQPixmapProvider(bool *deleteWatch = 0)
122 : QDeclarativeImageProvider(Pixmap), deleteWatch(deleteWatch)
126 ~TestQPixmapProvider()
132 QPixmap requestPixmap(const QString &id, QSize *size, const QSize& requestedSize)
136 if (id == QLatin1String("no-such-file.png"))
141 QPixmap image(width, height);
143 *size = QSize(width, height);
144 if (requestedSize.isValid())
145 image = image.scaled(requestedSize);
152 Q_DECLARE_METATYPE(TestQPixmapProvider*);
155 QString tst_qdeclarativeimageprovider::newImageFileName() const
157 // need to generate new filenames each time or else images are loaded
158 // from cache and we won't get loading status changes when testing
160 static int count = 0;
161 return QString("image://test/image-%1.png").arg(count++);
164 void tst_qdeclarativeimageprovider::fillRequestTestsData(const QString &id)
166 QTest::addColumn<QString>("source");
167 QTest::addColumn<QString>("imageId");
168 QTest::addColumn<QString>("properties");
169 QTest::addColumn<QSize>("size");
170 QTest::addColumn<QString>("error");
172 QString fileName = newImageFileName();
173 QTest::newRow(QTest::toString(id + " simple test"))
174 << "image://test/" + fileName << fileName << "" << QSize(100,100) << "";
176 fileName = newImageFileName();
177 QTest::newRow(QTest::toString(id + " simple test with capitalization"))//As it's a URL, should make no difference
178 << "image://Test/" + fileName << fileName << "" << QSize(100,100) << "";
180 fileName = newImageFileName();
181 QTest::newRow(QTest::toString(id + " url with no id"))
182 << "image://test/" + fileName << "" + fileName << "" << QSize(100,100) << "";
184 fileName = newImageFileName();
185 QTest::newRow(QTest::toString(id + " url with path"))
186 << "image://test/test/path" + fileName << "test/path" + fileName << "" << QSize(100,100) << "";
188 fileName = newImageFileName();
189 QTest::newRow(QTest::toString(id + " url with fragment"))
190 << "image://test/faq.html?#question13" + fileName << "faq.html?#question13" + fileName << "" << QSize(100,100) << "";
192 fileName = newImageFileName();
193 QTest::newRow(QTest::toString(id + " url with query"))
194 << "image://test/cgi-bin/drawgraph.cgi?type=pie&color=green" + fileName << "cgi-bin/drawgraph.cgi?type=pie&color=green" + fileName
195 << "" << QSize(100,100) << "";
197 fileName = newImageFileName();
198 QTest::newRow(QTest::toString(id + " scaled image"))
199 << "image://test/" + fileName << fileName << "sourceSize: \"80x30\"" << QSize(80,30) << "";
201 QTest::newRow(QTest::toString(id + " missing"))
202 << "image://test/no-such-file.png" << "no-such-file.png" << "" << QSize(100,100)
203 << "file::2:1: QML Image: Failed to get image from provider: image://test/no-such-file.png";
205 QTest::newRow(QTest::toString(id + " unknown provider"))
206 << "image://bogus/exists.png" << "" << "" << QSize()
207 << "file::2:1: QML Image: Invalid image provider: image://bogus/exists.png";
210 void tst_qdeclarativeimageprovider::runTest(bool async, QDeclarativeImageProvider *provider)
212 QFETCH(QString, source);
213 QFETCH(QString, imageId);
214 QFETCH(QString, properties);
216 QFETCH(QString, error);
218 if (!error.isEmpty())
219 QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
221 QDeclarativeEngine engine;
223 engine.addImageProvider("test", provider);
224 QVERIFY(engine.imageProvider("test") != 0);
226 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + source + "\"; "
227 + (async ? "asynchronous: true; " : "")
229 QDeclarativeComponent component(&engine);
230 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
231 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
235 QTRY_VERIFY(obj->status() == QQuickImage::Loading);
237 QCOMPARE(obj->source(), QUrl(source));
239 if (error.isEmpty()) {
241 QTRY_VERIFY(obj->status() == QQuickImage::Ready);
243 QVERIFY(obj->status() == QQuickImage::Ready);
244 if (QByteArray(QTest::currentDataTag()).startsWith("qimage"))
245 QCOMPARE(static_cast<TestQImageProvider*>(provider)->lastImageId, imageId);
247 QCOMPARE(static_cast<TestQPixmapProvider*>(provider)->lastImageId, imageId);
249 QCOMPARE(obj->width(), qreal(size.width()));
250 QCOMPARE(obj->height(), qreal(size.height()));
251 QCOMPARE(obj->fillMode(), QQuickImage::Stretch);
252 QCOMPARE(obj->progress(), 1.0);
255 QTRY_VERIFY(obj->status() == QQuickImage::Error);
257 QVERIFY(obj->status() == QQuickImage::Error);
263 void tst_qdeclarativeimageprovider::requestImage_sync_data()
265 fillRequestTestsData("qimage|sync");
268 void tst_qdeclarativeimageprovider::requestImage_sync()
270 bool deleteWatch = false;
271 runTest(false, new TestQImageProvider(&deleteWatch));
272 QVERIFY(deleteWatch);
275 void tst_qdeclarativeimageprovider::requestImage_async_data()
277 fillRequestTestsData("qimage|async");
280 void tst_qdeclarativeimageprovider::requestImage_async()
282 bool deleteWatch = false;
283 runTest(true, new TestQImageProvider(&deleteWatch));
284 QVERIFY(deleteWatch);
287 void tst_qdeclarativeimageprovider::requestPixmap_sync_data()
289 fillRequestTestsData("qpixmap");
292 void tst_qdeclarativeimageprovider::requestPixmap_sync()
294 bool deleteWatch = false;
295 runTest(false, new TestQPixmapProvider(&deleteWatch));
296 QVERIFY(deleteWatch);
299 void tst_qdeclarativeimageprovider::requestPixmap_async()
301 QDeclarativeEngine engine;
302 QDeclarativeImageProvider *provider = new TestQPixmapProvider();
304 engine.addImageProvider("test", provider);
305 QVERIFY(engine.imageProvider("test") != 0);
307 // pixmaps are loaded synchronously regardless of 'asynchronous' value
308 QString componentStr = "import QtQuick 2.0\nImage { asynchronous: true; source: \"image://test/pixmap-async-test.png\" }";
309 QDeclarativeComponent component(&engine);
310 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
311 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
317 void tst_qdeclarativeimageprovider::removeProvider_data()
319 QTest::addColumn<QDeclarativeImageProvider*>("provider");
321 QTest::newRow("qimage") << static_cast<QDeclarativeImageProvider*>(new TestQImageProvider);
322 QTest::newRow("qpixmap") << static_cast<QDeclarativeImageProvider*>(new TestQPixmapProvider);
325 void tst_qdeclarativeimageprovider::removeProvider()
327 QFETCH(QDeclarativeImageProvider*, provider);
329 QDeclarativeEngine engine;
331 engine.addImageProvider("test", provider);
332 QVERIFY(engine.imageProvider("test") != 0);
334 // add provider, confirm it works
335 QString componentStr = "import QtQuick 2.0\nImage { source: \"" + newImageFileName() + "\" }";
336 QDeclarativeComponent component(&engine);
337 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
338 QQuickImage *obj = qobject_cast<QQuickImage*>(component.create());
341 QCOMPARE(obj->status(), QQuickImage::Ready);
343 // remove the provider and confirm
344 QString fileName = newImageFileName();
345 QString error("file::2:1: QML Image: Invalid image provider: " + fileName);
346 QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
348 engine.removeImageProvider("test");
350 obj->setSource(QUrl(fileName));
351 QCOMPARE(obj->status(), QQuickImage::Error);
356 class TestThreadProvider : public QDeclarativeImageProvider
359 TestThreadProvider() : QDeclarativeImageProvider(Image), ok(false) {}
361 ~TestThreadProvider() {}
363 QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize)
370 for (int i = 0; i < 10000; i++)
371 v.prepend(i); //do some computation
372 QImage image(50,50, QImage::Format_RGB32);
373 image.fill(QColor(id).rgb());
375 *size = image.size();
376 if (requestedSize.isValid())
377 image = image.scaled(requestedSize);
387 void tst_qdeclarativeimageprovider::threadTest()
389 QDeclarativeEngine engine;
391 TestThreadProvider *provider = new TestThreadProvider;
393 engine.addImageProvider("test_thread", provider);
394 QVERIFY(engine.imageProvider("test_thread") != 0);
396 QString componentStr = "import QtQuick 2.0\nItem { \n"
397 "Image { source: \"image://test_thread/blue\"; asynchronous: true; }\n"
398 "Image { source: \"image://test_thread/red\"; asynchronous: true; }\n"
399 "Image { source: \"image://test_thread/green\"; asynchronous: true; }\n"
400 "Image { source: \"image://test_thread/yellow\"; asynchronous: true; }\n"
402 QDeclarativeComponent component(&engine);
403 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
404 QObject *obj = component.create();
407 QList<QQuickImage *> images = obj->findChildren<QQuickImage *>();
408 QCOMPARE(images.count(), 4);
410 foreach (QQuickImage *img, images) {
411 QCOMPARE(img->status(), QQuickImage::Loading);
414 provider->cond.wakeAll();
416 foreach (QQuickImage *img, images) {
417 QTRY_VERIFY(img->status() == QQuickImage::Ready);
422 QTEST_MAIN(tst_qdeclarativeimageprovider)
424 #include "tst_qdeclarativeimageprovider.moc"