Initial import from the monolithic Qt.
[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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
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     QUrl url = thisfile.resolved(QUrl("data/massive.png"));
293
294     // Confirm that massive images remain in the cache while they are
295     // in use by the application.
296     {
297     qint64 cachekey = 0;
298     QDeclarativePixmap p(0, url);
299     QVERIFY(p.isReady());
300     QVERIFY(p.pixmap().size() == QSize(10000, 1000));
301     cachekey = p.pixmap().cacheKey();
302
303     QDeclarativePixmap p2(0, url);
304     QVERIFY(p2.isReady());
305     QVERIFY(p2.pixmap().size() == QSize(10000, 1000));
306
307     QVERIFY(p2.pixmap().cacheKey() == cachekey);
308     }
309
310     // Confirm that massive images are removed from the cache when
311     // they become unused
312     {
313     qint64 cachekey = 0;
314     {
315         QDeclarativePixmap p(0, url);
316         QVERIFY(p.isReady());
317         QVERIFY(p.pixmap().size() == QSize(10000, 1000));
318         cachekey = p.pixmap().cacheKey();
319     }
320
321     QDeclarativePixmap p2(0, url);
322     QVERIFY(p2.isReady());
323     QVERIFY(p2.pixmap().size() == QSize(10000, 1000));
324
325     QVERIFY(p2.pixmap().cacheKey() != cachekey);
326     }
327 }
328
329 // QTBUG-12729
330 void tst_qdeclarativepixmapcache::cancelcrash()
331 {
332     QUrl url("http://127.0.0.1:14452/cancelcrash_notexist.png");
333     for (int ii = 0; ii < 1000; ++ii) {
334         QDeclarativePixmap pix(&engine, url);
335     }
336 }
337
338 class MyPixmapProvider : public QDeclarativeImageProvider
339 {
340 public:
341     MyPixmapProvider()
342     : QDeclarativeImageProvider(Pixmap) {}
343
344     virtual QPixmap requestPixmap(const QString &d, QSize *, const QSize &) {
345         Q_UNUSED(d)
346         QPixmap pix(800, 600);
347         pix.fill(Qt::red);
348         return pix;
349     }
350 };
351
352 // QTBUG-13345
353 void tst_qdeclarativepixmapcache::shrinkcache()
354 {
355     QDeclarativeEngine engine;
356     engine.addImageProvider(QLatin1String("mypixmaps"), new MyPixmapProvider);
357
358     for (int ii = 0; ii < 4000; ++ii) {
359         QUrl url("image://mypixmaps/" + QString::number(ii));
360         QDeclarativePixmap p(&engine, url);
361     }
362 }
363
364 #ifndef QT_NO_CONCURRENT
365
366 void createNetworkServer()
367 {
368    QEventLoop eventLoop;
369    TestHTTPServer server(14453);
370    server.serveDirectory(SRCDIR "/data/http");
371    QTimer::singleShot(100, &eventLoop, SLOT(quit()));
372    eventLoop.exec();
373 }
374
375 #ifndef QT_NO_CONCURRENT
376 // QT-3957
377 void tst_qdeclarativepixmapcache::networkCrash()
378 {
379     QFuture<void> future = QtConcurrent::run(createNetworkServer);
380     QDeclarativeEngine engine;
381     for (int ii = 0; ii < 100 ; ++ii) {
382         QDeclarativePixmap* pixmap = new QDeclarativePixmap;
383         pixmap->load(&engine,  QUrl(QString("http://127.0.0.1:14453/exists.png")));
384         QTest::qSleep(1);
385         pixmap->clear();
386         delete pixmap;
387     }
388     future.cancel();
389 }
390 #endif
391
392 #endif
393
394 QTEST_MAIN(tst_qdeclarativepixmapcache)
395
396 #include "tst_qdeclarativepixmapcache.moc"