File indexing completed on 2024-05-12 04:19:59

0001 /*
0002 Gwenview: an image viewer
0003 Copyright 2010 Aurélien Gâteau <agateau@kde.org>
0004 
0005 This program is free software; you can redistribute it and/or
0006 modify it under the terms of the GNU General Public License
0007 as published by the Free Software Foundation; either version 2
0008 of the License, or (at your option) any later version.
0009 
0010 This program is distributed in the hope that it will be useful,
0011 but WITHOUT ANY WARRANTY; without even the implied warranty of
0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0013 GNU General Public License for more details.
0014 
0015 You should have received a copy of the GNU General Public License
0016 along with this program; if not, write to the Free Software
0017 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
0018 
0019 */
0020 #include "testutils.h"
0021 
0022 // Qt
0023 #include <QStandardPaths>
0024 #include <QTimer>
0025 
0026 // KF
0027 #include <KIO/DeleteJob>
0028 #include <KIO/FileCopyJob>
0029 #include <KIO/MkdirJob>
0030 #include <KIO/StatJob>
0031 #include <KJobWidgets>
0032 
0033 QUrl setUpRemoteTestDir(const QString &testFile)
0034 {
0035     QWidget *authWindow = nullptr;
0036     if (qEnvironmentVariableIsEmpty("GV_REMOTE_TESTS_BASE_URL")) {
0037         qWarning() << "Environment variable GV_REMOTE_TESTS_BASE_URL not set: remote tests disabled";
0038         return {};
0039     }
0040 
0041     QUrl baseUrl(QString::fromLocal8Bit(qgetenv("GV_REMOTE_TESTS_BASE_URL")));
0042     baseUrl = baseUrl.adjusted(QUrl::StripTrailingSlash);
0043     baseUrl.setPath(baseUrl.path() + "/gwenview-remote-tests");
0044 
0045     auto statJob = KIO::stat(baseUrl, KIO::StatJob::DestinationSide, KIO::StatNoDetails);
0046     KJobWidgets::setWindow(statJob, authWindow);
0047 
0048     if (statJob->exec()) {
0049         KIO::DeleteJob *deleteJob = KIO::del(baseUrl);
0050         KJobWidgets::setWindow(deleteJob, authWindow);
0051         deleteJob->exec();
0052     }
0053 
0054     KIO::MkdirJob *mkdirJob = KIO::mkdir(baseUrl);
0055     KJobWidgets::setWindow(mkdirJob, authWindow);
0056     if (!mkdirJob->exec()) {
0057         qCritical() << "Could not create dir" << baseUrl << ":" << mkdirJob->errorString();
0058         return {};
0059     }
0060 
0061     if (!testFile.isEmpty()) {
0062         QUrl dstUrl = baseUrl;
0063         dstUrl = dstUrl.adjusted(QUrl::StripTrailingSlash);
0064         dstUrl.setPath(dstUrl.path() + '/' + testFile);
0065         KIO::FileCopyJob *copyJob = KIO::file_copy(urlForTestFile(testFile), dstUrl);
0066         KJobWidgets::setWindow(copyJob, authWindow);
0067         if (!copyJob->exec()) {
0068             qCritical() << "Could not copy" << testFile << "to" << dstUrl << ":" << copyJob->errorString();
0069             return {};
0070         }
0071     }
0072 
0073     return baseUrl;
0074 }
0075 
0076 void createEmptyFile(const QString &path)
0077 {
0078     QVERIFY(!QFile::exists(path));
0079     QFile file(path);
0080     bool ok = file.open(QIODevice::WriteOnly);
0081     QVERIFY(ok);
0082 }
0083 
0084 void waitForDeferredDeletes()
0085 {
0086     QCoreApplication::sendPostedEvents();
0087     QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
0088     QCoreApplication::processEvents();
0089 }
0090 
0091 namespace TestUtils
0092 {
0093 void purgeUserConfiguration()
0094 {
0095     QString confDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation);
0096     QVERIFY(confDir.endsWith(QStringLiteral(".qttest/share"))); // Better safe than sorry
0097     if (QFileInfo(confDir).isDir()) {
0098         KIO::DeleteJob *deleteJob = KIO::del(QUrl::fromLocalFile(confDir));
0099         QVERIFY(deleteJob->exec());
0100     }
0101 }
0102 
0103 static QImage simplifyFormats(const QImage &img)
0104 {
0105     switch (img.format()) {
0106     case QImage::Format_RGB32:
0107     case QImage::Format_ARGB32_Premultiplied:
0108         return img.convertToFormat(QImage::Format_ARGB32);
0109     default:
0110         return img;
0111     }
0112 }
0113 
0114 inline bool fuzzyColorComponentCompare(int c1, int c2, int delta)
0115 {
0116     return qAbs(c1 - c2) < delta;
0117 }
0118 
0119 bool fuzzyImageCompare(const QImage &img1_, const QImage &img2_, int delta)
0120 {
0121     if (img1_.size() != img2_.size()) {
0122         qWarning() << "Different sizes" << img1_.size() << "!=" << img2_.size();
0123         return false;
0124     }
0125     QImage img1 = simplifyFormats(img1_);
0126     QImage img2 = simplifyFormats(img2_);
0127     if (img1.format() != img2.format()) {
0128         qWarning() << "Different formats" << img1.format() << "!=" << img2.format();
0129         return false;
0130     }
0131 
0132     for (int posY = 0; posY < img1.height(); ++posY) {
0133         for (int posX = 0; posX < img2.width(); ++posX) {
0134             QColor col1 = img1.pixel(posX, posY);
0135             QColor col2 = img2.pixel(posX, posY);
0136             bool ok = fuzzyColorComponentCompare(col1.red(), col2.red(), delta) && fuzzyColorComponentCompare(col1.green(), col2.green(), delta)
0137                 && fuzzyColorComponentCompare(col1.blue(), col2.blue(), delta) && fuzzyColorComponentCompare(col1.alpha(), col2.alpha(), delta);
0138             if (!ok) {
0139                 qWarning() << "Different at" << QPoint(posX, posY) << col1.name() << "!=" << col2.name();
0140                 return false;
0141             }
0142         }
0143     }
0144     return true;
0145 }
0146 
0147 bool imageCompare(const QImage &img1, const QImage &img2)
0148 {
0149     return fuzzyImageCompare(img1, img2, 1);
0150 }
0151 
0152 SandBoxDir::SandBoxDir()
0153     : mTempDir(QDir::currentPath() + "/sandbox-")
0154 {
0155     setPath(mTempDir.path());
0156 }
0157 
0158 void SandBoxDir::fill(const QStringList &filePaths)
0159 {
0160     for (const QString &filePath : filePaths) {
0161         QFileInfo info(*this, filePath);
0162         mkpath(info.absolutePath());
0163         createEmptyFile(info.absoluteFilePath());
0164     }
0165 }
0166 
0167 TimedEventLoop::TimedEventLoop(int maxDuration)
0168     : mTimer(new QTimer(this))
0169 {
0170     mTimer->setSingleShot(true);
0171     mTimer->setInterval(maxDuration * 1000);
0172     connect(mTimer, &QTimer::timeout, this, &TimedEventLoop::fail);
0173 }
0174 
0175 int TimedEventLoop::exec(ProcessEventsFlags flags)
0176 {
0177     mTimer->start();
0178     return QEventLoop::exec(flags);
0179 }
0180 
0181 void TimedEventLoop::fail()
0182 {
0183     if (isRunning()) {
0184         qFatal("TimedEventLoop has been running for %d seconds. Aborting.", mTimer->interval() / 1000);
0185         exit(1);
0186     }
0187 }
0188 
0189 } // namespace TestUtils
0190 
0191 #include "moc_testutils.cpp"