Warning, file /graphics/krita/sdk/tests/filestest.h was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*
0002  * SPDX-FileCopyrightText: 2007 Cyrille Berger <cberger@cberger.net>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 #ifndef FILESTEST
0007 #define FILESTEST
0008 
0009 #include <testutil.h>
0010 #include "testui.h"
0011 
0012 #include <QDir>
0013 
0014 #include <kaboutdata.h>
0015 #include <klocalizedstring.h>
0016 #include <kis_debug.h>
0017 
0018 #include <KisImportExportManager.h>
0019 
0020 #include <KisDocument.h>
0021 #include <KisPart.h>
0022 #include <kis_image.h>
0023 #include <KoColorSpace.h>
0024 #include <KoColorSpaceRegistry.h>
0025 
0026 #include <QTemporaryFile>
0027 #include <QFileInfo>
0028 #include <QApplication>
0029 #include <QFile>
0030 #include <QFileDevice>
0031 #include <QIODevice>
0032 
0033 #ifdef Q_OS_UNIX
0034 #   include <unistd.h>
0035 #endif
0036 
0037 namespace TestUtil
0038 {
0039 
0040 void testFiles(const QString& _dirname, const QStringList& exclusions, const QString &resultSuffix = QString(), int fuzzy = 0, int maxNumFailingPixels = 0, bool showDebug = true)
0041 {
0042     QDir dirSources(_dirname);
0043     QStringList failuresFileInfo;
0044     QStringList failuresDocImage;
0045     QStringList failuresCompare;
0046 
0047     Q_FOREACH (QFileInfo sourceFileInfo, dirSources.entryInfoList()) {
0048         qDebug() << sourceFileInfo.fileName();
0049         if (exclusions.indexOf(sourceFileInfo.fileName()) > -1) {
0050             continue;
0051         }
0052         if (!sourceFileInfo.isHidden() && !sourceFileInfo.isDir()) {
0053             QFileInfo resultFileInfo(QString(FILES_DATA_DIR) + "/results/" + sourceFileInfo.fileName() + resultSuffix + ".png");
0054 
0055             if (!resultFileInfo.exists()) {
0056                 failuresFileInfo << resultFileInfo.fileName();
0057                 continue;
0058             }
0059 
0060             KisDocument *doc = qobject_cast<KisDocument*>(KisPart::instance()->createDocument());
0061 
0062             KisImportExportManager manager(doc);
0063             doc->setFileBatchMode(true);
0064 
0065             KisImportExportErrorCode status = manager.importDocument(sourceFileInfo.absoluteFilePath(), QString());
0066             Q_UNUSED(status);
0067 
0068             if (!doc->image()) {
0069                 failuresDocImage << sourceFileInfo.fileName();
0070                 continue;
0071             }
0072 
0073             QString id = doc->image()->colorSpace()->id();
0074             if (id != "GRAYA" && id != "GRAYAU16" && id != "RGBA" && id != "RGBA16") {
0075                 dbgKrita << "Images need conversion";
0076                 doc->image()->convertImageColorSpace(KoColorSpaceRegistry::instance()->rgb8(),
0077                                                     KoColorConversionTransformation::IntentAbsoluteColorimetric,
0078                                                     KoColorConversionTransformation::NoOptimization);
0079                 doc->image()->waitForDone();
0080             }
0081 
0082             qApp->processEvents();
0083             doc->image()->waitForDone();
0084             QImage sourceImage = doc->image()->projection()->convertToQImage(0, doc->image()->bounds());
0085 
0086 
0087 
0088             QImage resultImage(resultFileInfo.absoluteFilePath());
0089             resultImage = resultImage.convertToFormat(QImage::Format_ARGB32);
0090             sourceImage = sourceImage.convertToFormat(QImage::Format_ARGB32);
0091 
0092             QPoint pt;
0093 
0094             if (!TestUtil::compareQImages(pt, resultImage, sourceImage, fuzzy, fuzzy, maxNumFailingPixels, showDebug)) {
0095                 failuresCompare << sourceFileInfo.fileName() + ": " + QString("Pixel (%1,%2) has different values").arg(pt.x()).arg(pt.y()).toLatin1();
0096                 sourceImage.save(sourceFileInfo.fileName() + ".png");
0097                 resultImage.save(resultFileInfo.fileName() + ".expected.png");
0098                 continue;
0099             }
0100 
0101             delete doc;
0102         }
0103     }
0104     if (failuresCompare.isEmpty() && failuresDocImage.isEmpty() && failuresFileInfo.isEmpty()) {
0105         return;
0106     }
0107     qWarning() << "Comparison failures: " << failuresCompare;
0108     qWarning() << "No image failures: " << failuresDocImage;
0109     qWarning() << "No comparison image: " <<  failuresFileInfo;
0110 
0111     QFAIL("Failed testing files");
0112 }
0113 
0114 
0115 void prepareFile(QFileInfo sourceFileInfo, bool removePermissionToWrite, bool removePermissionToRead)
0116 {
0117 
0118     QFileDevice::Permissions permissionsBefore;
0119     if (sourceFileInfo.exists()) {
0120         permissionsBefore = QFile::permissions(sourceFileInfo.absoluteFilePath());
0121         ENTER_FUNCTION() << permissionsBefore;
0122     } else {
0123         QFile file(sourceFileInfo.absoluteFilePath());
0124         bool opened = file.open(QIODevice::ReadWrite);
0125         if (!opened) {
0126             qDebug() << "The file cannot be opened/created: " << file.error() << file.errorString();
0127         }
0128         permissionsBefore = file.permissions();
0129         file.close();
0130     }
0131     QFileDevice::Permissions permissionsNow = permissionsBefore;
0132     if (removePermissionToRead) {
0133         permissionsNow = permissionsBefore &
0134                 (~QFileDevice::ReadUser & ~QFileDevice::ReadOwner
0135                  & ~QFileDevice::ReadGroup & ~QFileDevice::ReadOther);
0136     }
0137     if (removePermissionToWrite) {
0138         permissionsNow = permissionsBefore &
0139                 (~QFileDevice::WriteUser & ~QFileDevice::WriteOwner
0140                  & ~QFileDevice::WriteGroup & ~QFileDevice::WriteOther);
0141     }
0142 
0143     bool success = QFile::setPermissions(sourceFileInfo.absoluteFilePath(), permissionsNow);
0144     if (!success) {
0145         qWarning() << "prepareFile(): Failed to set permission of file" << sourceFileInfo.absoluteFilePath()
0146                    << "from" << permissionsBefore << "to" << permissionsNow;
0147     }
0148 }
0149 
0150 void restorePermissionsToReadAndWrite(QFileInfo sourceFileInfo)
0151 {
0152     QFileDevice::Permissions permissionsNow = sourceFileInfo.permissions();
0153     QFileDevice::Permissions permissionsAfter = permissionsNow
0154             | (QFileDevice::ReadUser | QFileDevice::ReadOwner
0155             | QFileDevice::ReadGroup | QFileDevice::ReadOther)
0156             | (QFileDevice::WriteUser | QFileDevice::WriteOwner
0157             | QFileDevice::WriteGroup | QFileDevice::WriteOther);
0158     bool success = QFile::setPermissions(sourceFileInfo.absoluteFilePath(), permissionsAfter);
0159     if (!success) {
0160         qWarning() << "restorePermissionsToReadAndWrite(): Failed to set permission of file" << sourceFileInfo.absoluteFilePath()
0161                    << "from" << permissionsNow << "to" << permissionsAfter;
0162     }
0163 }
0164 
0165 const QString &impexTempFilesDir() {
0166     static const QString s_path = []() {
0167         const QString path = QDir::cleanPath(
0168                 QStandardPaths::writableLocation(QStandardPaths::CacheLocation) + "/impex_test") + '/';
0169         QDir(path).mkpath(QStringLiteral("."));
0170         return path;
0171     }();
0172     return s_path;
0173 }
0174 
0175 
0176 void testImportFromWriteonly(QString mimetype)
0177 {
0178 #ifdef Q_OS_WIN
0179     /// on Windows one cannot create a write-only file, so just skip this test
0180     /// (but keep it compiled to avoid compilation issues)
0181     QSKIP("Cannot test write-only file on Windows.");
0182 #endif
0183 
0184 #ifdef Q_OS_UNIX
0185     if (geteuid() == 0) {
0186         QSKIP("Test is being run as root; removing read permission has no effect.");
0187     }
0188 #endif
0189 
0190     QString writeonlyFilename = impexTempFilesDir() + "writeonlyFile.txt";
0191     QFileInfo sourceFileInfo(writeonlyFilename);
0192 
0193     prepareFile(sourceFileInfo, false, true);
0194 
0195     KisDocument *doc = qobject_cast<KisDocument*>(KisPart::instance()->createDocument());
0196 
0197     KisImportExportManager manager(doc);
0198     doc->setFileBatchMode(true);
0199 
0200     KisImportExportErrorCode status = manager.importDocument(sourceFileInfo.absoluteFilePath(), mimetype);
0201     qDebug() << "import result = " << status;
0202 
0203     QString failMessage = "";
0204     bool fail = false;
0205 
0206     if (status == ImportExportCodes::FileFormatIncorrect) {
0207         qDebug() << "Make sure you set the correct mimetype in the test case.";
0208         failMessage = "Incorrect status.";
0209         fail = true;
0210     }
0211 
0212     qApp->processEvents();
0213 
0214     if (doc->image()) {
0215         doc->image()->waitForDone();
0216     }
0217 
0218     delete doc;
0219 
0220     if (fail || status.isOk()) {
0221         qDebug() << "The file permission is:" << QFile::permissions(sourceFileInfo.absoluteFilePath());
0222     }
0223 
0224     restorePermissionsToReadAndWrite(sourceFileInfo);
0225 
0226     QVERIFY(!status.isOk());
0227     if (fail) {
0228         QFAIL(failMessage.toUtf8());
0229     }
0230 
0231 }
0232 
0233 
0234 void testExportToReadonly(QString mimetype)
0235 {
0236 #ifdef Q_OS_UNIX
0237     if (geteuid() == 0) {
0238         QSKIP("Test is being run as root; removing write permission has no effect.");
0239     }
0240 #endif
0241 
0242     QString readonlyFilename = impexTempFilesDir() + "readonlyFile.txt";
0243 
0244     QFileInfo sourceFileInfo(readonlyFilename);
0245     prepareFile(sourceFileInfo, true, false);
0246 
0247     KisDocument *doc = qobject_cast<KisDocument*>(KisPart::instance()->createDocument());
0248 
0249     KisImportExportManager manager(doc);
0250     doc->setFileBatchMode(true);
0251 
0252     KisImportExportErrorCode status = ImportExportCodes::OK;
0253     QString failMessage = "";
0254     bool fail = false;
0255 
0256     {
0257     MaskParent p;
0258     ENTER_FUNCTION() << doc->image();
0259 
0260     doc->setCurrentImage(p.image);
0261 
0262     bool result = doc->exportDocumentSync(sourceFileInfo.absoluteFilePath(), mimetype.toUtf8());
0263     status = result ? ImportExportCodes::OK : ImportExportCodes::Failure;
0264 
0265     qDebug() << "export result = " << status;
0266 
0267     qApp->processEvents();
0268 
0269     if (doc->image()) {
0270         doc->image()->waitForDone();
0271     }
0272 
0273     }
0274     delete doc;
0275 
0276     if (status.isOk()) {
0277         qDebug() << "The file permission is:" << QFile::permissions(sourceFileInfo.absoluteFilePath());
0278     }
0279 
0280     restorePermissionsToReadAndWrite(sourceFileInfo);
0281 
0282     QVERIFY(!status.isOk());
0283     if (fail) {
0284         QFAIL(failMessage.toUtf8());
0285     }
0286 }
0287 
0288 
0289 
0290 void testImportIncorrectFormat(QString mimetype)
0291 {
0292     QString incorrectFormatFilename = impexTempFilesDir() + "incorrectFormatFile.txt";
0293     QFileInfo sourceFileInfo(incorrectFormatFilename);
0294 
0295     prepareFile(sourceFileInfo, false, false);
0296 
0297     KisDocument *doc = qobject_cast<KisDocument*>(KisPart::instance()->createDocument());
0298 
0299     KisImportExportManager manager(doc);
0300     doc->setFileBatchMode(true);
0301 
0302     KisImportExportErrorCode status = manager.importDocument(sourceFileInfo.absoluteFilePath(), mimetype);
0303     qDebug() << "import result = " << status;
0304 
0305     qApp->processEvents();
0306 
0307     if (doc->image()) {
0308         doc->image()->waitForDone();
0309     }
0310 
0311     delete doc;
0312 
0313     QVERIFY(!status.isOk());
0314     QVERIFY(status == KisImportExportErrorCode(ImportExportCodes::FileFormatIncorrect)
0315             || status == KisImportExportErrorCode(ImportExportCodes::ErrorWhileReading)); // in case the filter doesn't know if it can't read or just parse
0316 
0317 }
0318 
0319 
0320 void testExportToColorSpace(QString mimetype, const KoColorSpace* space, KisImportExportErrorCode expected)
0321 {
0322     QString colorspaceFilename = impexTempFilesDir() + "colorspace.txt";
0323 
0324     QFileInfo sourceFileInfo(colorspaceFilename);
0325     prepareFile(sourceFileInfo, true, true);
0326     restorePermissionsToReadAndWrite(sourceFileInfo);
0327 
0328     KisDocument *doc = qobject_cast<KisDocument*>(KisPart::instance()->createDocument());
0329 
0330     KisImportExportManager manager(doc);
0331     doc->setFileBatchMode(true);
0332 
0333     KisImportExportErrorCode statusExport = ImportExportCodes::OK;
0334     KisImportExportErrorCode statusImport = ImportExportCodes::OK;
0335 
0336     QString failMessage = "";
0337     bool fail = false;
0338 
0339     {
0340     MaskParent p;
0341 
0342     doc->setCurrentImage(p.image);
0343     doc->image()->convertImageColorSpace(space, KoColorConversionTransformation::Intent::IntentPerceptual, KoColorConversionTransformation::ConversionFlag::Empty);
0344     doc->image()->waitForDone();
0345 
0346     bool result = doc->exportDocumentSync(QString(colorspaceFilename), mimetype.toUtf8());
0347     statusExport = result ? ImportExportCodes::OK : ImportExportCodes::Failure;
0348 
0349     statusImport = manager.importDocument(colorspaceFilename, mimetype.toUtf8());
0350     if (!(statusImport == ImportExportCodes::OK)) {
0351         fail = true;
0352         failMessage = "Incorrect status";
0353     }
0354 
0355     bool mismatch = (*(doc->image()->colorSpace()) != *space) || (doc->image()->colorSpace()->profile() != space->profile());
0356     if (mismatch) {
0357         qDebug() << "Document color space = " << (doc->image()->colorSpace())->id();
0358         qDebug() << "Saved color space = " << space->id();
0359         fail = true;
0360         failMessage = "Mismatch of color spaces";
0361     }
0362 
0363     qApp->processEvents();
0364 
0365     if (doc->image()) {
0366         doc->image()->waitForDone();
0367     }
0368 
0369     }
0370     delete doc;
0371 
0372     QFile::remove(colorspaceFilename);
0373 
0374     if (fail) {
0375         QFAIL(failMessage.toUtf8());
0376     }
0377 
0378     QVERIFY(statusExport.isOk());
0379     QVERIFY(statusExport == expected);
0380 }
0381 
0382 
0383 
0384 
0385 
0386 
0387 }
0388 #endif