/*
* Copyright (C) 2016 Canonical, Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
Q_DECLARE_METATYPE(QQuickImage::Status)
class ImageCacheTest : public QObject
{
Q_OBJECT
private:
void setUpImage(const QString &name, const QSize &sourceSize = QSize())
{
QString url = "image://unity8imagecache/file://" + sourceFile(name);
image->setProperty("sourceSize", sourceSize);
image->setProperty("source", url);
}
void waitForImage(QQuickImage::Status status = QQuickImage::Ready)
{
QTRY_COMPARE(image->property("status"), QVariant((int)status));
}
QSize cachedImageSize(const QString &filename)
{
QImageReader reader(filename);
return reader.size();
}
QString sourceFile(const QString &name)
{
return testDataDir() + "/" TEST_DIR "/graphics/" + name;
}
QString cachedFile(bool isPath, const QString &name)
{
if (isPath)
return home->path() + "/.cache/unity8/imagecache/paths" + sourceFile(name);
else
return home->path() + "/.cache/unity8/imagecache/names/" + name;
}
void createCachedImage(const QString &name, const QString &cachePath, const QSize &cacheSize, time_t mtime_in = 0)
{
QString origPath = sourceFile(name);
QImageReader origImage(origPath);
origImage.setScaledSize(cacheSize);
auto format = origImage.format(); // can't get this after reading
QImage cacheImage(origImage.read());
QVERIFY(!cacheImage.isNull());
QFileInfo(cachePath).dir().mkpath(QStringLiteral("."));
QVERIFY(cacheImage.save(cachePath, format, 100));
// Make file a few seconds old, so we can more easily tell if it gets updated
auto mtime = mtime_in == 0 ? QFileInfo(cachePath).lastModified().toTime_t() - 5 : mtime_in;
struct utimbuf timebuffer;
timebuffer.modtime = mtime;
timebuffer.actime = timebuffer.modtime;
QCOMPARE(utime(cachePath.toUtf8().data(), &timebuffer), 0);
}
private Q_SLOTS:
void init()
{
home = new QTemporaryDir();
QVERIFY(home->isValid());
qputenv("HOME", home->path().toUtf8());
view = new QQuickView();
view->setSource(QUrl::fromLocalFile(testDataDir() + "/" TEST_DIR "/test.qml"));
image = view->rootObject();
view->show();
QTest::qWaitForWindowExposed(view);
waitForImage(QQuickImage::Null);
}
void cleanup()
{
delete view;
delete home;
}
void testFileNotFound()
{
setUpImage("NOTHERE");
waitForImage(QQuickImage::Error);
QVERIFY(!QFile::exists(cachedFile(true, "NOTHERE")));
}
void testNoSourceSize()
{
setUpImage("wide.jpg");
waitForImage();
QVERIFY(!QFile::exists(cachedFile(true, "wide.jpg")));
}
void testNoScalingUp()
{
setUpImage("wide.jpg", QSize(1000, 1000));
waitForImage();
QVERIFY(!QFile::exists(cachedFile(true, "wide.jpg")));
}
void testFullSourceSize()
{
setUpImage("wide.jpg", QSize(100, 100));
waitForImage();
QCOMPARE(cachedImageSize(cachedFile(true, "wide.jpg")), QSize(100, 100));
}
void testWidthSourceSize()
{
setUpImage("wide.jpg", QSize(100, 0));
waitForImage();
// wide.jpg is 500x200
QCOMPARE(cachedImageSize(cachedFile(true, "wide.jpg")), QSize(100, 40));
}
void testHeightSourceSize()
{
setUpImage("wide.jpg", QSize(0, 100));
waitForImage();
// wide.jpg is 500x200
QCOMPARE(cachedImageSize(cachedFile(true, "wide.jpg")), QSize(250, 100));
}
void testNameArg()
{
setUpImage("wide.jpg?name=foo", QSize(0, 100));
waitForImage();
QVERIFY(!QFile::exists(cachedFile(true, ""))); // check for dir itself
QVERIFY(QFile::exists(cachedFile(false, "foo")));
}
void testLoadCache()
{
auto cacheName = cachedFile(false, "foo");
createCachedImage("wide.jpg", cacheName, QSize(250, 100));
auto mtime = QFileInfo(cacheName).lastModified();
auto now = time(NULL);
QVERIFY(QFileInfo(cacheName).lastModified().toTime_t() < now); // sanity check
setUpImage("wide.jpg?name=foo", QSize(0, 100));
waitForImage();
QCOMPARE(QFileInfo(cacheName).lastModified(), mtime); // wasn't recreated
}
void testDifferentSize()
{
auto cacheName = cachedFile(false, "foo");
createCachedImage("wide.jpg", cacheName, QSize(250, 100));
auto now = time(NULL);
QVERIFY(QFileInfo(cacheName).lastModified().toTime_t() < now); // sanity check
setUpImage("wide.jpg?name=foo", QSize(100, 0));
waitForImage();
QVERIFY(QFileInfo(cacheName).lastModified().toTime_t() >= now); // was recreated
}
void testStaleCache()
{
auto sourceName = sourceFile("wide.jpg");
auto mtime = QFileInfo(sourceName).lastModified().toTime_t() - 5;
auto cacheName = cachedFile(false, "foo");
createCachedImage("wide.jpg", cacheName, QSize(250, 100), mtime);
auto now = time(NULL);
QVERIFY(QFileInfo(cacheName).lastModified().toTime_t() < now); // sanity check
setUpImage("wide.jpg?name=foo", QSize(0, 100));
waitForImage();
QVERIFY(QFileInfo(cacheName).lastModified().toTime_t() >= now); // was recreated
}
private:
QQuickView *view;
QObject *image;
QTemporaryDir *home;
};
QTEST_MAIN(ImageCacheTest)
#include "test.moc"