@@ -0,0 +1,214 @@
2+ * Copyright (C) 2016 Canonical, Ltd.
4+ * This program is free software; you can redistribute it and/or modify
5+ * it under the terms of the GNU General Public License as published by
6+ * the Free Software Foundation; version 3.
8+ * This program is distributed in the hope that it will be useful,
9+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
10+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+ * GNU General Public License for more details.
13+ * You should have received a copy of the GNU General Public License
14+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
17+#include <QCoreApplication>
19+#include <QImageReader>
21+#include <QTemporaryDir>
23+#include <private/qquickimage_p.h>
27+Q_DECLARE_METATYPE(QQuickImage::Status)
29+class ImageCacheTest : public QObject
35+ void setUpImage(const QString &name, const QSize &sourceSize = QSize())
37+ QString url = "image://unity8imagecache/file://" + sourceFile(name);
38+ image->setProperty("sourceSize", sourceSize);
39+ image->setProperty("source", url);
42+ void waitForImage(QQuickImage::Status status = QQuickImage::Ready)
44+ QTRY_COMPARE(image->property("status"), QVariant::fromValue(status));
47+ QSize cachedImageSize(const QString &filename)
49+ QImageReader reader(filename);
50+ return reader.size();
53+ QString sourceFile(const QString &name)
55+ return CURRENT_SOURCE_DIR "/graphics/" + name;
58+ QString cachedFile(bool isPath, const QString &name)
61+ return home->path() + "/.cache/unity8/imagecache/paths" + sourceFile(name);
63+ return home->path() + "/.cache/unity8/imagecache/names/" + name;
66+ void createCachedImage(const QString &name, const QString &cachePath, const QSize &cacheSize, time_t mtime_in = 0)
68+ QString origPath = sourceFile(name);
69+ QImageReader origImage(origPath);
70+ origImage.setScaledSize(cacheSize);
71+ auto format = origImage.format(); // can't get this after reading
73+ QImage cacheImage(origImage.read());
74+ QVERIFY(!cacheImage.isNull());
76+ QFileInfo(cachePath).dir().mkpath(QStringLiteral("."));
77+ QVERIFY(cacheImage.save(cachePath, format, 100));
79+ // Make file a few seconds old, so we can more easily tell if it gets updated
80+ auto mtime = mtime_in == 0 ? QFileInfo(cachePath).lastModified().toTime_t() - 5 : mtime_in;
81+ struct utimbuf timebuffer;
82+ timebuffer.modtime = mtime;
83+ timebuffer.actime = timebuffer.modtime;
84+ QCOMPARE(utime(cachePath.toUtf8().data(), &timebuffer), 0);
91+ home = new QTemporaryDir();
92+ QVERIFY(home->isValid());
93+ qputenv("HOME", home->path().toUtf8());
95+ view = new QQuickView();
96+ view->setSource(QUrl::fromLocalFile(CURRENT_SOURCE_DIR "/test.qml"));
97+ image = view->rootObject();
100+ QTest::qWaitForWindowExposed(view);
102+ waitForImage(QQuickImage::Null);
111+ void testFileNotFound()
113+ setUpImage("NOTHERE");
114+ waitForImage(QQuickImage::Error);
115+ QVERIFY(!QFile::exists(cachedFile(true, "NOTHERE")));
118+ void testNoSourceSize()
120+ setUpImage("wide.jpg");
122+ QVERIFY(!QFile::exists(cachedFile(true, "wide.jpg")));
125+ void testNoScalingUp()
127+ setUpImage("wide.jpg", QSize(1000, 1000));
129+ QVERIFY(!QFile::exists(cachedFile(true, "wide.jpg")));
132+ void testFullSourceSize()
134+ setUpImage("wide.jpg", QSize(100, 100));
136+ QCOMPARE(cachedImageSize(cachedFile(true, "wide.jpg")), QSize(100, 100));
139+ void testWidthSourceSize()
141+ setUpImage("wide.jpg", QSize(100, 0));
143+ // wide.jpg is 500x200
144+ QCOMPARE(cachedImageSize(cachedFile(true, "wide.jpg")), QSize(100, 40));
147+ void testHeightSourceSize()
149+ setUpImage("wide.jpg", QSize(0, 100));
151+ // wide.jpg is 500x200
152+ QCOMPARE(cachedImageSize(cachedFile(true, "wide.jpg")), QSize(250, 100));
157+ setUpImage("wide.jpg?name=foo", QSize(0, 100));
159+ QVERIFY(!QFile::exists(cachedFile(true, ""))); // check for dir itself
160+ QVERIFY(QFile::exists(cachedFile(false, "foo")));
163+ void testLoadCache()
165+ auto cacheName = cachedFile(false, "foo");
166+ createCachedImage("wide.jpg", cacheName, QSize(250, 100));
167+ auto mtime = QFileInfo(cacheName).lastModified();
169+ auto now = time(NULL);
170+ QVERIFY(QFileInfo(cacheName).lastModified().toTime_t() < now); // sanity check
172+ setUpImage("wide.jpg?name=foo", QSize(0, 100));
174+ QCOMPARE(QFileInfo(cacheName).lastModified(), mtime); // wasn't recreated
177+ void testDifferentSize()
179+ auto cacheName = cachedFile(false, "foo");
180+ createCachedImage("wide.jpg", cacheName, QSize(250, 100));
182+ auto now = time(NULL);
183+ QVERIFY(QFileInfo(cacheName).lastModified().toTime_t() < now); // sanity check
185+ setUpImage("wide.jpg?name=foo", QSize(100, 0));
187+ QVERIFY(QFileInfo(cacheName).lastModified().toTime_t() >= now); // was recreated
190+ void testStaleCache()
192+ auto sourceName = sourceFile("wide.jpg");
193+ auto mtime = QFileInfo(sourceName).lastModified().toTime_t() - 5;
195+ auto cacheName = cachedFile(false, "foo");
196+ createCachedImage("wide.jpg", cacheName, QSize(250, 100), mtime);
198+ auto now = time(NULL);
199+ QVERIFY(QFileInfo(cacheName).lastModified().toTime_t() < now); // sanity check
201+ setUpImage("wide.jpg?name=foo", QSize(0, 100));
203+ QVERIFY(QFileInfo(cacheName).lastModified().toTime_t() >= now); // was recreated
209+ QTemporaryDir *home;
212+QTEST_MAIN(ImageCacheTest)