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 <QtQuick1/private/qdeclarativeimage_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: Failed to get image from 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 1.0\nImage { source: \"" + source + "\"; "
227 + (async ? "asynchronous: true; " : "")
229 QDeclarativeComponent component(&engine);
230 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
231 QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
235 QTRY_VERIFY(obj->status() == QDeclarative1Image::Loading);
237 QCOMPARE(obj->source(), QUrl(source));
239 if (error.isEmpty()) {
241 QTRY_VERIFY(obj->status() == QDeclarative1Image::Ready);
243 QVERIFY(obj->status() == QDeclarative1Image::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->pixmap().width(), size.width());
252 QCOMPARE(obj->pixmap().height(), size.height());
253 QCOMPARE(obj->fillMode(), QDeclarative1Image::Stretch);
254 QCOMPARE(obj->progress(), 1.0);
257 QTRY_VERIFY(obj->status() == QDeclarative1Image::Error);
259 QVERIFY(obj->status() == QDeclarative1Image::Error);
265 void tst_qdeclarativeimageprovider::requestImage_sync_data()
267 fillRequestTestsData("qimage|sync");
270 void tst_qdeclarativeimageprovider::requestImage_sync()
272 bool deleteWatch = false;
273 runTest(false, new TestQImageProvider(&deleteWatch));
274 QVERIFY(deleteWatch);
277 void tst_qdeclarativeimageprovider::requestImage_async_data()
279 fillRequestTestsData("qimage|async");
282 void tst_qdeclarativeimageprovider::requestImage_async()
284 bool deleteWatch = false;
285 runTest(true, new TestQImageProvider(&deleteWatch));
286 QVERIFY(deleteWatch);
289 void tst_qdeclarativeimageprovider::requestPixmap_sync_data()
291 fillRequestTestsData("qpixmap");
294 void tst_qdeclarativeimageprovider::requestPixmap_sync()
296 bool deleteWatch = false;
297 runTest(false, new TestQPixmapProvider(&deleteWatch));
298 QVERIFY(deleteWatch);
301 void tst_qdeclarativeimageprovider::requestPixmap_async()
303 QDeclarativeEngine engine;
304 QDeclarativeImageProvider *provider = new TestQPixmapProvider();
306 engine.addImageProvider("test", provider);
307 QVERIFY(engine.imageProvider("test") != 0);
309 // pixmaps are loaded synchronously regardless of 'asynchronous' value
310 QString componentStr = "import QtQuick 1.0\nImage { asynchronous: true; source: \"image://test/pixmap-async-test.png\" }";
311 QDeclarativeComponent component(&engine);
312 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
313 QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
319 void tst_qdeclarativeimageprovider::removeProvider_data()
321 QTest::addColumn<QDeclarativeImageProvider*>("provider");
323 QTest::newRow("qimage") << static_cast<QDeclarativeImageProvider*>(new TestQImageProvider);
324 QTest::newRow("qpixmap") << static_cast<QDeclarativeImageProvider*>(new TestQPixmapProvider);
327 void tst_qdeclarativeimageprovider::removeProvider()
329 QFETCH(QDeclarativeImageProvider*, provider);
331 QDeclarativeEngine engine;
333 engine.addImageProvider("test", provider);
334 QVERIFY(engine.imageProvider("test") != 0);
336 // add provider, confirm it works
337 QString componentStr = "import QtQuick 1.0\nImage { source: \"" + newImageFileName() + "\" }";
338 QDeclarativeComponent component(&engine);
339 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
340 QDeclarative1Image *obj = qobject_cast<QDeclarative1Image*>(component.create());
343 QCOMPARE(obj->status(), QDeclarative1Image::Ready);
345 // remove the provider and confirm
346 QString fileName = newImageFileName();
347 QString error("file::2:1: QML Image: Failed to get image from provider: " + fileName);
348 QTest::ignoreMessage(QtWarningMsg, error.toUtf8());
350 engine.removeImageProvider("test");
352 obj->setSource(QUrl(fileName));
353 QCOMPARE(obj->status(), QDeclarative1Image::Error);
358 class TestThreadProvider : public QDeclarativeImageProvider
361 TestThreadProvider() : QDeclarativeImageProvider(Image), ok(false) {}
363 ~TestThreadProvider() {}
365 QImage requestImage(const QString &id, QSize *size, const QSize& requestedSize)
372 for (int i = 0; i < 10000; i++)
373 v.prepend(i); //do some computation
374 QImage image(50,50, QImage::Format_RGB32);
375 image.fill(QColor(id).rgb());
377 *size = image.size();
378 if (requestedSize.isValid())
379 image = image.scaled(requestedSize);
389 void tst_qdeclarativeimageprovider::threadTest()
391 QDeclarativeEngine engine;
393 TestThreadProvider *provider = new TestThreadProvider;
395 engine.addImageProvider("test_thread", provider);
396 QVERIFY(engine.imageProvider("test_thread") != 0);
398 QString componentStr = "import QtQuick 1.0\nItem { \n"
399 "Image { source: \"image://test_thread/blue\"; asynchronous: true; }\n"
400 "Image { source: \"image://test_thread/red\"; asynchronous: true; }\n"
401 "Image { source: \"image://test_thread/green\"; asynchronous: true; }\n"
402 "Image { source: \"image://test_thread/yellow\"; asynchronous: true; }\n"
404 QDeclarativeComponent component(&engine);
405 component.setData(componentStr.toLatin1(), QUrl::fromLocalFile(""));
406 QObject *obj = component.create();
409 QList<QDeclarative1Image *> images = obj->findChildren<QDeclarative1Image *>();
410 QCOMPARE(images.count(), 4);
412 foreach(QDeclarative1Image *img, images) {
413 QCOMPARE(img->status(), QDeclarative1Image::Loading);
416 provider->cond.wakeAll();
418 foreach(QDeclarative1Image *img, images) {
419 QTRY_VERIFY(img->status() == QDeclarative1Image::Ready);
424 QTEST_MAIN(tst_qdeclarativeimageprovider)
426 #include "tst_qdeclarativeimageprovider.moc"