fix warning
[kdegraphics.git] / gwenview / tests / documenttest.cpp
blob3d6b07ceabc398219c36336e675997bfc80e30a7
1 /*
2 Gwenview: an image viewer
3 Copyright 2007 Aurélien Gâteau <aurelien.gateau@free.fr>
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 // Qt
21 #include <QConicalGradient>
22 #include <QImage>
23 #include <QPainter>
25 // KDE
26 #include <kdebug.h>
27 #include <kio/netaccess.h>
28 #include <qtest_kde.h>
30 // Local
31 #include "../lib/abstractimageoperation.h"
32 #include "../lib/document/abstractdocumenteditor.h"
33 #include "../lib/document/documentfactory.h"
34 #include "../lib/imagemetainfomodel.h"
35 #include "../lib/imageutils.h"
36 #include "testutils.h"
38 #include <exiv2/exif.hpp>
40 #include "documenttest.moc"
42 QTEST_KDEMAIN( DocumentTest, GUI )
44 using namespace Gwenview;
47 static void waitUntilMetaInfoLoaded(Document::Ptr doc) {
48 while (doc->loadingState() < Document::MetaInfoLoaded) {
49 QTest::qWait(100);
54 void DocumentTest::initTestCase() {
55 qRegisterMetaType<KUrl>("KUrl");
59 void DocumentTest::init() {
60 DocumentFactory::instance()->clearCache();
64 void DocumentTest::testLoad() {
65 QFETCH(QString, fileName);
66 QFETCH(QByteArray, expectedFormat);
67 QFETCH(int, expectedKindInt);
68 QFETCH(bool, expectedIsAnimated);
69 QFETCH(QImage, expectedImage);
70 MimeTypeUtils::Kind expectedKind = MimeTypeUtils::Kind(expectedKindInt);
72 KUrl url = urlForTestFile(fileName);
73 QVERIFY2(!expectedImage.isNull(), "Could not load test image");
75 Document::Ptr doc = DocumentFactory::instance()->load(url);
76 QSignalSpy spy(doc.data(), SIGNAL(isAnimatedUpdated()));
77 doc->loadFullImage();
78 doc->waitUntilLoaded();
79 QCOMPARE(doc->loadingState(), Document::Loaded);
81 QCOMPARE(expectedKind, doc->kind());
82 QCOMPARE(expectedIsAnimated, doc->isAnimated());
83 QCOMPARE(spy.count(), doc->isAnimated() ? 1 : 0);
84 if (doc->kind() == MimeTypeUtils::KIND_RASTER_IMAGE) {
85 QCOMPARE(expectedImage, doc->image());
86 QCOMPARE(expectedFormat, doc->format());
90 #define NEW_ROW(fileName, format, kind, isAnimated) QTest::newRow(fileName) << fileName << QByteArray(format) << int(kind) << isAnimated << QImage(pathForTestFile(fileName))
91 void DocumentTest::testLoad_data() {
92 QTest::addColumn<QString>("fileName");
93 QTest::addColumn<QByteArray>("expectedFormat");
94 QTest::addColumn<int>("expectedKindInt");
95 QTest::addColumn<bool>("expectedIsAnimated");
96 QTest::addColumn<QImage>("expectedImage");
98 NEW_ROW("test.png",
99 "png", MimeTypeUtils::KIND_RASTER_IMAGE, false);
100 NEW_ROW("160216_no_size_before_decoding.eps",
101 "eps", MimeTypeUtils::KIND_RASTER_IMAGE, false);
102 NEW_ROW("160382_corrupted.jpeg",
103 "jpeg", MimeTypeUtils::KIND_RASTER_IMAGE, false);
104 NEW_ROW("test.svg",
105 "", MimeTypeUtils::KIND_SVG_IMAGE, false);
106 // FIXME: Test svgz
107 NEW_ROW("1x10k.png",
108 "png", MimeTypeUtils::KIND_RASTER_IMAGE, false);
109 NEW_ROW("1x10k.jpg",
110 "jpeg", MimeTypeUtils::KIND_RASTER_IMAGE, false);
111 NEW_ROW("4frames.gif",
112 "gif", MimeTypeUtils::KIND_RASTER_IMAGE, true);
114 #undef NEW_ROW
116 void DocumentTest::testLoadTwoPasses() {
117 KUrl url = urlForTestFile("test.png");
118 QImage image;
119 bool ok = image.load(url.path());
120 QVERIFY2(ok, "Could not load 'test.png'");
121 Document::Ptr doc = DocumentFactory::instance()->load(url);
122 waitUntilMetaInfoLoaded(doc);
123 QVERIFY2(doc->image().isNull(), "Image shouldn't have been loaded at this time");
124 QCOMPARE(doc->format().data(), "png");
125 doc->loadFullImage();
126 doc->waitUntilLoaded();
127 QCOMPARE(image, doc->image());
130 void DocumentTest::testLoadEmpty() {
131 KUrl url = urlForTestFile("empty.png");
132 Document::Ptr doc = DocumentFactory::instance()->load(url);
133 while (doc->loadingState() == Document::Loading) {
134 QTest::qWait(100);
136 QCOMPARE(doc->loadingState(), Document::LoadingFailed);
139 #define NEW_ROW(fileName) QTest::newRow(fileName) << fileName
140 void DocumentTest::testLoadDownSampled_data() {
141 QTest::addColumn<QString>("fileName");
143 NEW_ROW("orient6.jpg");
144 NEW_ROW("1x10k.jpg");
146 #undef NEW_ROW
148 void DocumentTest::testLoadDownSampled() {
149 // Note: for now we only support down sampling on jpeg, do not use test.png
150 // here
151 QFETCH(QString, fileName);
152 KUrl url = urlForTestFile(fileName);
153 QImage image;
154 bool ok = image.load(url.path());
155 QVERIFY2(ok, "Could not load test image");
156 Document::Ptr doc = DocumentFactory::instance()->load(url);
158 QSignalSpy downSampledImageReadySpy(doc.data(), SIGNAL(downSampledImageReady()));
159 QSignalSpy loadingFailedSpy(doc.data(), SIGNAL(loadingFailed(const KUrl&)));
160 QSignalSpy loadedSpy(doc.data(), SIGNAL(loaded(const KUrl&)));
161 bool ready = doc->prepareDownSampledImageForZoom(0.2);
162 QVERIFY2(!ready, "There should not be a down sampled image at this point");
164 while (downSampledImageReadySpy.count() == 0 && loadingFailedSpy.count() == 0 && loadedSpy.count() == 0) {
165 QTest::qWait(100);
167 QImage downSampledImage = doc->downSampledImageForZoom(0.2);
168 QVERIFY2(!downSampledImage.isNull(), "Down sampled image should not be null");
170 QCOMPARE(downSampledImage.size(), doc->size() / 4);
173 void DocumentTest::testLoadRemote() {
174 QString testTarGzPath = pathForTestFile("test.tar.gz");
175 KUrl url;
176 url.setProtocol("tar");
177 url.setPath(testTarGzPath + "/test.png");
179 QVERIFY2(KIO::NetAccess::exists(url, KIO::NetAccess::SourceSide, 0), "test archive not found");
181 Document::Ptr doc = DocumentFactory::instance()->load(url);
182 doc->loadFullImage();
183 doc->waitUntilLoaded();
184 QImage image = doc->image();
185 QCOMPARE(image.width(), 300);
186 QCOMPARE(image.height(), 200);
189 void DocumentTest::testLoadAnimated() {
190 KUrl srcUrl = urlForTestFile("40frames.gif");
191 Document::Ptr doc = DocumentFactory::instance()->load(srcUrl);
192 QSignalSpy spy(doc.data(), SIGNAL(imageRectUpdated(const QRect&)));
193 doc->loadFullImage();
194 doc->waitUntilLoaded();
195 QVERIFY(doc->isAnimated());
197 // Test we receive only one imageRectUpdated() until animation is started
198 // (the imageRectUpdated() is triggered by the loading of the first image)
199 QTest::qWait(1000);
200 QCOMPARE(spy.count(), 1);
202 // Test we now receive some imageRectUpdated()
203 doc->startAnimation();
204 QTest::qWait(1000);
205 int count = spy.count();
206 doc->stopAnimation();
207 QVERIFY2(count > 0, "No imageRectUpdated() signal received");
209 // Test we do not receive imageRectUpdated() anymore
210 QTest::qWait(1000);
211 QCOMPARE(count, spy.count());
213 // Start again, we should receive imageRectUpdated() again
214 doc->startAnimation();
215 QTest::qWait(1000);
216 QVERIFY2(spy.count() > count, "No imageRectUpdated() signal received after restarting");
219 void DocumentTest::testSaveRemote() {
220 KUrl srcUrl = urlForTestFile("test.png");
221 Document::Ptr doc = DocumentFactory::instance()->load(srcUrl);
222 doc->loadFullImage();
223 doc->waitUntilLoaded();
225 KUrl dstUrl;
226 dstUrl.setProtocol("trash");
227 dstUrl.setPath("/test.png");
228 QVERIFY(!doc->save(dstUrl, "png"));
230 if (qgetenv("REMOTE_SFTP_TEST").isEmpty()) {
231 kWarning() << "*** Define the environment variable REMOTE_SFTP_TEST to try saving an image to sftp://localhost/tmp/test.png";
232 } else {
233 dstUrl.setProtocol("sftp");
234 dstUrl.setHost("localhost");
235 dstUrl.setPath("/tmp/test.png");
236 QVERIFY(doc->save(dstUrl, "png"));
241 * Check that deleting a document while it is loading does not crash
243 void DocumentTest::testDeleteWhileLoading() {
245 KUrl url = urlForTestFile("test.png");
246 QImage image;
247 bool ok = image.load(url.path());
248 QVERIFY2(ok, "Could not load 'test.png'");
249 Document::Ptr doc = DocumentFactory::instance()->load(url);
251 DocumentFactory::instance()->clearCache();
252 // Wait two seconds. If the test fails we will get a segfault while waiting
253 QTest::qWait(2000);
256 void DocumentTest::testLoadRotated() {
257 KUrl url = urlForTestFile("orient6.jpg");
258 QImage image;
259 bool ok = image.load(url.path());
260 QVERIFY2(ok, "Could not load 'orient6.jpg'");
261 QMatrix matrix = ImageUtils::transformMatrix(ROT_90);
262 image = image.transformed(matrix);
264 Document::Ptr doc = DocumentFactory::instance()->load(url);
265 doc->loadFullImage();
266 doc->waitUntilLoaded();
267 QCOMPARE(image, doc->image());
271 * Checks that asking the DocumentFactory the same document twice in a row does
272 * not load it twice
274 void DocumentTest::testMultipleLoads() {
275 KUrl url = urlForTestFile("orient6.jpg");
276 Document::Ptr doc1 = DocumentFactory::instance()->load(url);
277 Document::Ptr doc2 = DocumentFactory::instance()->load(url);
279 QCOMPARE(doc1.data(), doc2.data());
282 void DocumentTest::testSave() {
283 KUrl url = urlForTestFile("orient6.jpg");
284 Document::Ptr doc = DocumentFactory::instance()->load(url);
285 doc->loadFullImage();
287 KUrl destUrl = urlForTestOutputFile("result.png");
288 QVERIFY(doc->save(destUrl, "png"));
289 QCOMPARE(doc->format().data(), "png");
291 QVERIFY2(doc->loadingState() == Document::Loaded,
292 "Document is supposed to finish loading before saving"
295 QImage image("result.png", "png");
296 QCOMPARE(doc->image(), image);
299 void DocumentTest::testLosslessSave() {
300 KUrl url1 = urlForTestFile("orient6.jpg");
301 Document::Ptr doc = DocumentFactory::instance()->load(url1);
302 doc->loadFullImage();
304 KUrl url2 = urlForTestOutputFile("orient1.jpg");
305 QVERIFY(doc->save(url2, "jpeg"));
307 QImage image1;
308 QVERIFY(image1.load(url1.path()));
310 QImage image2;
311 QVERIFY(image2.load(url2.path()));
313 QCOMPARE(image1, image2);
316 void DocumentTest::testLosslessRotate() {
317 // Generate test image
318 QImage image1(200, 96, QImage::Format_RGB32);
320 QPainter painter(&image1);
321 QConicalGradient gradient(QPointF(100, 48), 100);
322 gradient.setColorAt(0, Qt::white);
323 gradient.setColorAt(1, Qt::blue);
324 painter.fillRect(image1.rect(), gradient);
327 KUrl url1 = urlForTestOutputFile("lossless1.jpg");
328 QVERIFY(image1.save(url1.path(), "jpeg"));
330 // Load it as a Gwenview document
331 Document::Ptr doc = DocumentFactory::instance()->load(url1);
332 doc->loadFullImage();
333 doc->waitUntilLoaded();
335 // Rotate one time
336 QVERIFY(doc->editor());
337 doc->editor()->applyTransformation(ROT_90);
339 // Save it
340 KUrl url2 = urlForTestOutputFile("lossless2.jpg");
341 doc->save(url2, "jpeg");
343 // Load the saved image
344 doc = DocumentFactory::instance()->load(url2);
345 doc->loadFullImage();
346 doc->waitUntilLoaded();
348 // Rotate the other way
349 QVERIFY(doc->editor());
350 doc->editor()->applyTransformation(ROT_270);
351 doc->save(url2, "jpeg");
353 // Compare the saved images
354 QVERIFY(image1.load(url1.path()));
355 QImage image2;
356 QVERIFY(image2.load(url2.path()));
358 QCOMPARE(image1, image2);
361 void DocumentTest::testModify() {
362 class TestOperation : public AbstractImageOperation {
363 public:
364 void redo() {
365 QImage image(10, 10, QImage::Format_ARGB32);
366 image.fill(QColor(Qt::white).rgb());
367 document()->editor()->setImage(image);
371 KUrl url = urlForTestFile("orient6.jpg");
372 Document::Ptr doc = DocumentFactory::instance()->load(url);
373 doc->loadFullImage();
374 doc->waitUntilLoaded();
375 QVERIFY(!doc->isModified());
377 QVERIFY(doc->editor());
378 TestOperation* op = new TestOperation;
379 op->setDocument(doc);
380 doc->undoStack()->push(op);
381 QVERIFY(doc->isModified());
383 KUrl destUrl = urlForTestOutputFile("modify.png");
384 QVERIFY(doc->save(destUrl, "png"));
386 QVERIFY(!doc->isModified());
389 void DocumentTest::testMetaInfoJpeg() {
390 KUrl url = urlForTestFile("orient6.jpg");
391 Document::Ptr doc = DocumentFactory::instance()->load(url);
393 // We cleared the cache, so the document should not be loaded
394 Q_ASSERT(doc->loadingState() == Document::Loading);
396 // Wait until we receive the metaInfoUpdated() signal
397 QSignalSpy metaInfoUpdatedSpy(doc.data(), SIGNAL(metaInfoUpdated()));
398 while (metaInfoUpdatedSpy.count() == 0) {
399 QTest::qWait(100);
402 // Extract an exif key
403 QString value = doc->metaInfo()->getValueForKey("Exif.Image.Make");
404 QCOMPARE(value, QString::fromUtf8("Canon"));
408 void DocumentTest::testMetaInfoBmp() {
409 KUrl url = urlForTestOutputFile("metadata.bmp");
410 const int width = 200;
411 const int height = 100;
412 QImage image(width, height, QImage::Format_ARGB32);
413 image.fill(Qt::black);
414 image.save(url.path(), "BMP");
416 Document::Ptr doc = DocumentFactory::instance()->load(url);
417 QSignalSpy metaInfoUpdatedSpy(doc.data(), SIGNAL(metaInfoUpdated()));
418 waitUntilMetaInfoLoaded(doc);
420 Q_ASSERT(metaInfoUpdatedSpy.count() >= 1);
422 QString value = doc->metaInfo()->getValueForKey("General.ImageSize");
423 QString expectedValue = QString("%1x%2").arg(width).arg(height);
424 QCOMPARE(value, expectedValue);