Merge branch 'master' into v8
[profile/ivi/qtdeclarative.git] / tests / auto / declarative / qdeclarativepixmapcache / tst_qdeclarativepixmapcache.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the test suite of the Qt Toolkit.
8 **
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.
17 **
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.
21 **
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.
29 **
30 ** Other Usage
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.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 #include <qtest.h>
42 #include <QtTest/QtTest>
43 #include <private/qdeclarativepixmapcache_p.h>
44 #include <QtDeclarative/qdeclarativeengine.h>
45 #include <QtDeclarative/qdeclarativeimageprovider.h>
46 #include <QNetworkReply>
47 #include "testhttpserver.h"
48 #include "../../../shared/util.h"
49
50 #ifndef QT_NO_CONCURRENT
51 #include <qtconcurrentrun.h>
52 #include <qfuture.h>
53 #endif
54
55 // These don't let normal people run tests!
56 //#include "../network-settings.h"
57
58 #ifdef Q_OS_SYMBIAN
59 // In Symbian OS test data is located in applications private dir
60 #define SRCDIR "."
61 #endif
62
63 class tst_qdeclarativepixmapcache : public QObject
64 {
65     Q_OBJECT
66 public:
67     tst_qdeclarativepixmapcache() :
68         thisfile(QUrl::fromLocalFile(__FILE__)),
69         server(14452)
70     {
71         server.serveDirectory(SRCDIR "/data/http");
72     }
73
74 private slots:
75     void single();
76     void single_data();
77     void parallel();
78     void parallel_data();
79     void massive();
80     void cancelcrash();
81     void shrinkcache();
82 #ifndef QT_NO_CONCURRENT
83     void networkCrash();
84 #endif
85 private:
86     QDeclarativeEngine engine;
87     QUrl thisfile;
88     TestHTTPServer server;
89 };
90
91
92 static int slotters=0;
93
94 class Slotter : public QObject
95 {
96     Q_OBJECT
97 public:
98     Slotter()
99     {
100         gotslot = false;
101         slotters++;
102     }
103     bool gotslot;
104
105 public slots:
106     void got()
107     {
108         gotslot = true;
109         --slotters;
110         if (slotters==0)
111             QTestEventLoop::instance().exitLoop();
112     }
113 };
114
115 #ifndef QT_NO_LOCALFILE_OPTIMIZED_QML
116 static const bool localfile_optimized = true;
117 #else
118 static const bool localfile_optimized = false;
119 #endif
120
121 void tst_qdeclarativepixmapcache::single_data()
122 {
123     // Note, since QDeclarativePixmapCache is shared, tests affect each other!
124     // so use different files fore all test functions.
125
126     QTest::addColumn<QUrl>("target");
127     QTest::addColumn<bool>("incache");
128     QTest::addColumn<bool>("exists");
129     QTest::addColumn<bool>("neterror");
130
131     // File URLs are optimized
132     QTest::newRow("local") << thisfile.resolved(QUrl("data/exists.png")) << localfile_optimized << true << false;
133     QTest::newRow("local") << thisfile.resolved(QUrl("data/notexists.png")) << localfile_optimized << false << false;
134     QTest::newRow("remote") << QUrl("http://127.0.0.1:14452/exists.png") << false << true << false;
135     QTest::newRow("remote") << QUrl("http://127.0.0.1:14452/notexists.png") << false << false << true;
136 }
137
138 void tst_qdeclarativepixmapcache::single()
139 {
140     QFETCH(QUrl, target);
141     QFETCH(bool, incache);
142     QFETCH(bool, exists);
143     QFETCH(bool, neterror);
144
145     QString expectedError;
146     if (neterror) {
147         expectedError = "Error downloading " + target.toString() + " - server replied: Not found";
148     } else if (!exists) {
149         expectedError = "Cannot open: " + target.toString();
150     }
151
152     QDeclarativePixmap pixmap;
153     QVERIFY(pixmap.width() <= 0); // Check Qt assumption
154
155     pixmap.load(&engine, target);
156
157     if (incache) {
158         QCOMPARE(pixmap.error(), expectedError);
159         if (exists) {
160             QVERIFY(pixmap.status() == QDeclarativePixmap::Ready);
161             QVERIFY(pixmap.width() > 0);
162         } else {
163             QVERIFY(pixmap.status() == QDeclarativePixmap::Error);
164             QVERIFY(pixmap.width() <= 0);
165         }
166     } else {
167         QVERIFY(pixmap.width() <= 0);
168
169         Slotter getter;
170         pixmap.connectFinished(&getter, SLOT(got()));
171         QTestEventLoop::instance().enterLoop(10);
172         QVERIFY(!QTestEventLoop::instance().timeout());
173         QVERIFY(getter.gotslot);
174         if (exists) {
175             QVERIFY(pixmap.status() == QDeclarativePixmap::Ready);
176             QVERIFY(pixmap.width() > 0);
177         } else {
178             QVERIFY(pixmap.status() == QDeclarativePixmap::Error);
179             QVERIFY(pixmap.width() <= 0);
180         }
181         QCOMPARE(pixmap.error(), expectedError);
182     }
183 }
184
185 void tst_qdeclarativepixmapcache::parallel_data()
186 {
187     // Note, since QDeclarativePixmapCache is shared, tests affect each other!
188     // so use different files fore all test functions.
189
190     QTest::addColumn<QUrl>("target1");
191     QTest::addColumn<QUrl>("target2");
192     QTest::addColumn<int>("incache");
193     QTest::addColumn<int>("cancel"); // which one to cancel
194
195     QTest::newRow("local")
196             << thisfile.resolved(QUrl("data/exists1.png"))
197             << thisfile.resolved(QUrl("data/exists2.png"))
198             << (localfile_optimized ? 2 : 0)
199             << -1;
200
201     QTest::newRow("remote")
202             << QUrl("http://127.0.0.1:14452/exists2.png")
203             << QUrl("http://127.0.0.1:14452/exists3.png")
204             << 0
205             << -1;
206
207     QTest::newRow("remoteagain")
208             << QUrl("http://127.0.0.1:14452/exists2.png")
209             << QUrl("http://127.0.0.1:14452/exists3.png")
210             << 2
211             << -1;
212
213     QTest::newRow("remotecopy")
214             << QUrl("http://127.0.0.1:14452/exists4.png")
215             << QUrl("http://127.0.0.1:14452/exists4.png")
216             << 0
217             << -1;
218
219     QTest::newRow("remotecopycancel")
220             << QUrl("http://127.0.0.1:14452/exists5.png")
221             << QUrl("http://127.0.0.1:14452/exists5.png")
222             << 0
223             << 0;
224 }
225
226 void tst_qdeclarativepixmapcache::parallel()
227 {
228     QFETCH(QUrl, target1);
229     QFETCH(QUrl, target2);
230     QFETCH(int, incache);
231     QFETCH(int, cancel);
232
233     QList<QUrl> targets;
234     targets << target1 << target2;
235
236     QList<QDeclarativePixmap *> pixmaps;
237     QList<bool> pending;
238     QList<Slotter*> getters;
239
240     for (int i=0; i<targets.count(); ++i) {
241         QUrl target = targets.at(i);
242         QDeclarativePixmap *pixmap = new QDeclarativePixmap;
243
244         pixmap->load(&engine, target);
245
246         QVERIFY(pixmap->status() != QDeclarativePixmap::Error);
247         pixmaps.append(pixmap);
248         if (pixmap->isReady()) {
249             QVERIFY(pixmap->width() >  0);
250             getters.append(0);
251             pending.append(false);
252         } else {
253             QVERIFY(pixmap->width() <= 0);
254             getters.append(new Slotter);
255             pixmap->connectFinished(getters[i], SLOT(got()));
256             pending.append(true);
257         }
258     }
259
260     QCOMPARE(incache+slotters, targets.count());
261
262     if (cancel >= 0) {
263         pixmaps.at(cancel)->clear(getters[cancel]);
264         slotters--;
265     }
266
267     if (slotters) {
268         QTestEventLoop::instance().enterLoop(10);
269         QVERIFY(!QTestEventLoop::instance().timeout());
270     }
271
272     for (int i=0; i<targets.count(); ++i) {
273         QDeclarativePixmap *pixmap = pixmaps[i];
274
275         if (i == cancel) {
276             QVERIFY(!getters[i]->gotslot);
277         } else {
278             if (pending[i]) 
279                 QVERIFY(getters[i]->gotslot);
280
281             QVERIFY(pixmap->isReady());
282             QVERIFY(pixmap->width() > 0);
283             delete getters[i];
284         }
285     }
286
287     qDeleteAll(pixmaps);
288 }
289
290 void tst_qdeclarativepixmapcache::massive()
291 {
292     QDeclarativeEngine engine;
293     QUrl url = thisfile.resolved(QUrl("data/massive.png"));
294
295     // Confirm that massive images remain in the cache while they are
296     // in use by the application.
297     {
298     qint64 cachekey = 0;
299     QDeclarativePixmap p(&engine, url);
300     QVERIFY(p.isReady());
301     QVERIFY(p.pixmap().size() == QSize(10000, 1000));
302     cachekey = p.pixmap().cacheKey();
303
304     QDeclarativePixmap p2(&engine, url);
305     QVERIFY(p2.isReady());
306     QVERIFY(p2.pixmap().size() == QSize(10000, 1000));
307
308     QVERIFY(p2.pixmap().cacheKey() == cachekey);
309     }
310
311     // Confirm that massive images are removed from the cache when
312     // they become unused
313     {
314     qint64 cachekey = 0;
315     {
316         QDeclarativePixmap p(&engine, url);
317         QVERIFY(p.isReady());
318         QVERIFY(p.pixmap().size() == QSize(10000, 1000));
319         cachekey = p.pixmap().cacheKey();
320     }
321
322     QDeclarativePixmap p2(&engine, url);
323     QVERIFY(p2.isReady());
324     QVERIFY(p2.pixmap().size() == QSize(10000, 1000));
325
326     QVERIFY(p2.pixmap().cacheKey() != cachekey);
327     }
328 }
329
330 // QTBUG-12729
331 void tst_qdeclarativepixmapcache::cancelcrash()
332 {
333     QUrl url("http://127.0.0.1:14452/cancelcrash_notexist.png");
334     for (int ii = 0; ii < 1000; ++ii) {
335         QDeclarativePixmap pix(&engine, url);
336     }
337 }
338
339 class MyPixmapProvider : public QDeclarativeImageProvider
340 {
341 public:
342     MyPixmapProvider()
343     : QDeclarativeImageProvider(Pixmap) {}
344
345     virtual QPixmap requestPixmap(const QString &d, QSize *, const QSize &) {
346         Q_UNUSED(d)
347         QPixmap pix(800, 600);
348         pix.fill(Qt::red);
349         return pix;
350     }
351 };
352
353 // QTBUG-13345
354 void tst_qdeclarativepixmapcache::shrinkcache()
355 {
356     QDeclarativeEngine engine;
357     engine.addImageProvider(QLatin1String("mypixmaps"), new MyPixmapProvider);
358
359     for (int ii = 0; ii < 4000; ++ii) {
360         QUrl url("image://mypixmaps/" + QString::number(ii));
361         QDeclarativePixmap p(&engine, url);
362     }
363 }
364
365 #ifndef QT_NO_CONCURRENT
366
367 void createNetworkServer()
368 {
369    QEventLoop eventLoop;
370    TestHTTPServer server(14453);
371    server.serveDirectory(SRCDIR "/data/http");
372    QTimer::singleShot(100, &eventLoop, SLOT(quit()));
373    eventLoop.exec();
374 }
375
376 #ifndef QT_NO_CONCURRENT
377 // QT-3957
378 void tst_qdeclarativepixmapcache::networkCrash()
379 {
380     QFuture<void> future = QtConcurrent::run(createNetworkServer);
381     QDeclarativeEngine engine;
382     for (int ii = 0; ii < 100 ; ++ii) {
383         QDeclarativePixmap* pixmap = new QDeclarativePixmap;
384         pixmap->load(&engine,  QUrl(QString("http://127.0.0.1:14453/exists.png")));
385         QTest::qSleep(1);
386         pixmap->clear();
387         delete pixmap;
388     }
389     future.cancel();
390 }
391 #endif
392
393 #endif
394
395 QTEST_MAIN(tst_qdeclarativepixmapcache)
396
397 #include "tst_qdeclarativepixmapcache.moc"