File indexing completed on 2024-05-12 05:10:01

0001 /***************************************************************************
0002     Copyright (C) 2017 Robby Stephenson <robby@periapsis.org>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 #include <config.h>
0026 #include "imagejobtest.h"
0027 
0028 #include "../images/imagejob.h"
0029 #include "../images/imagefactory.h"
0030 #include "../images/imageinfo.h"
0031 
0032 #include <KLocalizedString>
0033 
0034 #include <QTest>
0035 #include <QEventLoop>
0036 #include <QTemporaryFile>
0037 #include <QNetworkInterface>
0038 #include <QSignalSpy>
0039 #include <QStandardPaths>
0040 
0041 QTEST_GUILESS_MAIN( ImageJobTest )
0042 
0043 static bool hasNetwork() {
0044 #ifdef ENABLE_NETWORK_TESTS
0045   foreach(const QNetworkInterface& net, QNetworkInterface::allInterfaces()) {
0046     if(net.flags().testFlag(QNetworkInterface::IsUp) && !net.flags().testFlag(QNetworkInterface::IsLoopBack)) {
0047       return true;
0048     }
0049   }
0050 #endif
0051   return false;
0052 }
0053 
0054 void ImageJobTest::initTestCase() {
0055   QStandardPaths::setTestModeEnabled(true);
0056   KLocalizedString::setApplicationDomain("tellico");
0057   Tellico::ImageFactory::init();
0058 }
0059 
0060 void ImageJobTest::cleanupTestCase() {
0061 }
0062 
0063 void ImageJobTest::init() {
0064   m_result = -1;
0065   m_imageId.clear();
0066 }
0067 
0068 void ImageJobTest::enterLoop() {
0069   QEventLoop eventLoop;
0070   connect(this, &ImageJobTest::exitLoop, &eventLoop, &QEventLoop::quit);
0071   eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
0072 }
0073 
0074 void ImageJobTest::slotGetResult(KJob* job) {
0075   m_result = job->error();
0076   if(m_result > 1 && !job->errorString().isEmpty()) qDebug() << job->errorString();
0077   emit exitLoop();
0078 }
0079 
0080 void ImageJobTest::slotAvailable(const QString& id_) {
0081   m_result = 0;
0082   m_imageId = id_;
0083   emit exitLoop();
0084 }
0085 
0086 void ImageJobTest::testInvalidUrl() {
0087   QUrl u;
0088 
0089   Tellico::ImageJob* job = new Tellico::ImageJob(u);
0090   connect(job, &KJob::result,
0091           this, &ImageJobTest::slotGetResult);
0092 
0093   enterLoop();
0094   QCOMPARE(m_result, int(KIO::ERR_MALFORMED_URL));
0095 }
0096 
0097 void ImageJobTest::testNonexistant() {
0098   QUrl u(QStringLiteral("file:///non-existent-location"));
0099 
0100   Tellico::ImageJob* job = new Tellico::ImageJob(u);
0101   connect(job, &KJob::result,
0102           this, &ImageJobTest::slotGetResult);
0103 
0104   enterLoop();
0105   QCOMPARE(m_result, int(KIO::ERR_CANNOT_OPEN_FOR_READING));
0106 }
0107 
0108 void ImageJobTest::testUnreadable() {
0109   QTemporaryFile tmpFile;
0110   QVERIFY(tmpFile.open());
0111   QVERIFY(!tmpFile.fileName().isEmpty());
0112   QVERIFY(tmpFile.setPermissions(QFileDevice::Permissions()));
0113   tmpFile.close();
0114   QVERIFY(!tmpFile.isReadable());
0115   QUrl u = QUrl::fromLocalFile(tmpFile.fileName());
0116 
0117   Tellico::ImageJob* job = new Tellico::ImageJob(u);
0118   connect(job, &KJob::result,
0119           this, &ImageJobTest::slotGetResult);
0120 
0121   enterLoop();
0122   // on the gitlab CI, QFileInfo(tmpFile).isReadable can still return true
0123   // so check for either result code
0124   QVERIFY(m_result == KIO::ERR_CANNOT_OPEN_FOR_READING ||
0125           m_result == KIO::ERR_UNKNOWN);
0126 
0127   const Tellico::Data::Image& img = job->image();
0128   QVERIFY(img.isNull());
0129 }
0130 
0131 void ImageJobTest::testImageInvalid() {
0132   // text file is an invalid image
0133   QUrl u = QUrl::fromLocalFile(QFINDTESTDATA("imagejobtest.cpp"));
0134 
0135   QPointer<Tellico::ImageJob> job = new Tellico::ImageJob(u);
0136   connect(job.data(), &KJob::result,
0137           this, &ImageJobTest::slotGetResult);
0138 
0139   enterLoop();
0140   QCOMPARE(m_result, int(KIO::ERR_UNKNOWN));
0141 
0142   const Tellico::Data::Image& img = job->image();
0143   QVERIFY(img.isNull());
0144   QCOMPARE(img.linkOnly(), false);
0145 }
0146 
0147 void ImageJobTest::testImageLoad() {
0148   QUrl u = QUrl::fromLocalFile(QFINDTESTDATA("../../icons/tellico.png"));
0149 
0150   QPointer<Tellico::ImageJob> job = new Tellico::ImageJob(u);
0151   connect(job.data(), &KJob::result,
0152           this, &ImageJobTest::slotGetResult);
0153 
0154   enterLoop();
0155   // success!
0156   QCOMPARE(m_result, 0);
0157 
0158   const Tellico::Data::Image& img = job->image();
0159   QVERIFY(!img.isNull());
0160   QCOMPARE(img.id(), QStringLiteral("dde5bf2cbd90fad8635a26dfb362e0ff.png"));
0161   QCOMPARE(img.format(), QByteArray("png"));
0162   QCOMPARE(img.linkOnly(), false);
0163 
0164   // check that the job is automatically deleted
0165   qApp->processEvents();
0166   QVERIFY(!job);
0167 }
0168 
0169 void ImageJobTest::testImageLoadWithId() {
0170   QUrl u = QUrl::fromLocalFile(QFINDTESTDATA("../../icons/tellico.png"));
0171 
0172   QPointer<Tellico::ImageJob> job = new Tellico::ImageJob(u, QStringLiteral("tellico-rocks"));
0173   connect(job.data(), &KJob::result,
0174           this, &ImageJobTest::slotGetResult);
0175 
0176   enterLoop();
0177   // success!
0178   QCOMPARE(m_result, 0);
0179 
0180   const Tellico::Data::Image& img = job->image();
0181   QVERIFY(!img.isNull());
0182   QCOMPARE(img.id(), QStringLiteral("tellico-rocks"));
0183   QCOMPARE(img.format(), QByteArray("png"));
0184   QCOMPARE(img.linkOnly(), false);
0185 }
0186 
0187 void ImageJobTest::testImageLink() {
0188   QUrl u = QUrl::fromLocalFile(QFINDTESTDATA("../../icons/tellico.png"));
0189 
0190   QPointer<Tellico::ImageJob> job = new Tellico::ImageJob(u,
0191                                                           QString() /* id */,
0192                                                           false /* quiet */);
0193   job->setLinkOnly(true);
0194   connect(job.data(), &KJob::result,
0195           this, &ImageJobTest::slotGetResult);
0196 
0197   enterLoop();
0198   // success!
0199   QCOMPARE(m_result, 0);
0200 
0201   const Tellico::Data::Image& img = job->image();
0202   QVERIFY(!img.isNull());
0203   // id is not the MD5 hash
0204   QVERIFY(img.id() != QStringLiteral("dde5bf2cbd90fad8635a26dfb362e0ff.png"));
0205   QCOMPARE(img.format(), QByteArray("png"));
0206   QCOMPARE(img.linkOnly(), true);
0207 }
0208 
0209 void ImageJobTest::testNetworkImage() {
0210   if(!hasNetwork()) QSKIP("This test requires network access", SkipSingle);
0211 
0212   QUrl u(QStringLiteral("https://tellico-project.org/wp-content/uploads/96-tellico.png"));
0213 
0214   QPointer<Tellico::ImageJob> job = new Tellico::ImageJob(u);
0215   connect(job.data(), &KJob::result,
0216           this, &ImageJobTest::slotGetResult);
0217 
0218   enterLoop();
0219   // success!
0220   QCOMPARE(m_result, 0);
0221 
0222   const Tellico::Data::Image& img = job->image();
0223   QVERIFY(!img.isNull());
0224   QCOMPARE(img.id(), QStringLiteral("ecaf5185c4016881aaabb4933211d5d6.png"));
0225   QCOMPARE(img.format(), QByteArray("png"));
0226   QCOMPARE(img.linkOnly(), false);
0227 
0228   // check that the job is automatically deleted
0229   qApp->processEvents();
0230   QVERIFY(!job);
0231 }
0232 
0233 void ImageJobTest::testNetworkImageLink() {
0234   if(!hasNetwork()) QSKIP("This test requires network access", SkipSingle);
0235 
0236   QUrl u(QStringLiteral("https://tellico-project.org/wp-content/uploads/96-tellico.png"));
0237 
0238   QPointer<Tellico::ImageJob> job = new Tellico::ImageJob(u,
0239                                                           QString() /* id */,
0240                                                           false /* quiet */);
0241   job->setLinkOnly(true);
0242   connect(job.data(), &KJob::result,
0243           this, &ImageJobTest::slotGetResult);
0244 
0245   enterLoop();
0246   // success!
0247   QCOMPARE(m_result, 0);
0248 
0249   const Tellico::Data::Image& img = job->image();
0250   QVERIFY(!img.isNull());
0251   QCOMPARE(img.id(), u.url());
0252   QCOMPARE(img.format(), QByteArray("png"));
0253   QCOMPARE(img.linkOnly(), true);
0254 }
0255 
0256 void ImageJobTest::testNetworkImageInvalid() {
0257   if(!hasNetwork()) QSKIP("This test requires network access", SkipSingle);
0258 
0259   QUrl u(QStringLiteral("https://tellico-project.org"));
0260 
0261   QPointer<Tellico::ImageJob> job = new Tellico::ImageJob(u);
0262   connect(job.data(), &KJob::result,
0263           this, &ImageJobTest::slotGetResult);
0264 
0265   enterLoop();
0266   QCOMPARE(m_result, int(KIO::ERR_UNKNOWN));
0267 
0268   const Tellico::Data::Image& img = job->image();
0269   QVERIFY(img.isNull());
0270 }
0271 
0272 void ImageJobTest::testFactoryRequestLocal() {
0273   QVERIFY(m_imageId.isEmpty());
0274   connect(Tellico::ImageFactory::self(), &Tellico::ImageFactory::imageAvailable,
0275           this, &ImageJobTest::slotAvailable);
0276 
0277   QUrl u = QUrl::fromLocalFile(QFINDTESTDATA("../../icons/tellico.png"));
0278   Tellico::ImageFactory::requestImageById(u.url());
0279 
0280   // don't need to enter loop since the image is local and signal fires immediately
0281   QVERIFY(!m_imageId.isEmpty());
0282   // success!
0283   QCOMPARE(m_result, 0);
0284 
0285   const Tellico::Data::Image& img = Tellico::ImageFactory::imageById(m_imageId);
0286   QVERIFY(!img.isNull());
0287   // id is not the MD5 hash
0288   QVERIFY(img.id() != QStringLiteral("dde5bf2cbd90fad8635a26dfb362e0ff.png"));
0289   QCOMPARE(img.format(), QByteArray("png"));
0290   QCOMPARE(img.linkOnly(), true);
0291 }
0292 
0293 void ImageJobTest::testFactoryRequestLocalInvalid() {
0294   QVERIFY(m_imageId.isEmpty());
0295   QSignalSpy spy(Tellico::ImageFactory::self(), &Tellico::ImageFactory::imageAvailable);
0296   connect(Tellico::ImageFactory::self(), &Tellico::ImageFactory::imageAvailable,
0297           this, &ImageJobTest::slotAvailable);
0298 
0299   // text file is an invalid image
0300   QUrl u = QUrl::fromLocalFile(QFINDTESTDATA("imagejobtest.cpp"));
0301   Tellico::ImageFactory::requestImageById(u.url());
0302 
0303   // it will be a null image, but a local url, so image is still loaded with immediate signal
0304   QCOMPARE(spy.count(), 1);
0305   // the available image id is the url
0306   QCOMPARE(m_imageId, u.url());
0307 
0308   // now try to load it
0309   const Tellico::Data::Image& img = Tellico::ImageFactory::imageById(m_imageId);
0310   QVERIFY(img.isNull());
0311   QCOMPARE(img.linkOnly(), false);
0312   // make sure the null image list is updated
0313   QVERIFY(Tellico::ImageFactory::self()->hasNullImage(m_imageId));
0314   // the image should not be in local memory now
0315   QVERIFY(!Tellico::ImageFactory::self()->hasImageInMemory(m_imageId));
0316   QVERIFY(!Tellico::ImageFactory::self()->hasImageInfo(m_imageId));
0317 }
0318 
0319 void ImageJobTest::testFactoryRequestNetwork() {
0320   if(!hasNetwork()) QSKIP("This test requires network access", SkipSingle);
0321 
0322   QVERIFY(m_imageId.isEmpty());
0323   connect(Tellico::ImageFactory::self(), &Tellico::ImageFactory::imageAvailable,
0324           this, &ImageJobTest::slotAvailable);
0325 
0326   QUrl u(QStringLiteral("https://tellico-project.org/wp-content/uploads/96-tellico.png"));
0327   Tellico::ImageFactory::requestImageById(u.url());
0328 
0329   enterLoop();
0330   QVERIFY(!m_imageId.isEmpty());
0331   // success!
0332   QCOMPARE(m_result, 0);
0333   // the image should be in local memory now
0334   QVERIFY(Tellico::ImageFactory::self()->hasImageInMemory(m_imageId));
0335   QVERIFY(Tellico::ImageFactory::self()->hasImageInfo(m_imageId));
0336 
0337   const Tellico::Data::Image& img = Tellico::ImageFactory::imageById(m_imageId);
0338   QVERIFY(!img.isNull());
0339   // id is the MD5 hash, since it's not link only
0340   QCOMPARE(img.id(), QStringLiteral("ecaf5185c4016881aaabb4933211d5d6.png"));
0341   QCOMPARE(img.format(), QByteArray("png"));
0342   QCOMPARE(img.linkOnly(), false);
0343 }
0344 
0345 void ImageJobTest::testFactoryRequestNetworkLinkOnly() {
0346   if(!hasNetwork()) QSKIP("This test requires network access", SkipSingle);
0347 
0348   QVERIFY(m_imageId.isEmpty());
0349   connect(Tellico::ImageFactory::self(), &Tellico::ImageFactory::imageAvailable,
0350           this, &ImageJobTest::slotAvailable);
0351 
0352   QUrl u(QStringLiteral("https://tellico-project.org/wp-content/uploads/96-tellico.png"));
0353   // first, tell the image factory that the image is link only
0354   Tellico::Data::ImageInfo info(u.url(), "PNG", 64, 64, true /* link only */);
0355   Tellico::ImageFactory::cacheImageInfo(info);
0356 
0357   Tellico::ImageFactory::requestImageById(u.url());
0358 
0359   enterLoop();
0360   QVERIFY(!m_imageId.isEmpty());
0361   // success!
0362   QCOMPARE(m_result, 0);
0363   // the image should be in local memory now
0364   QVERIFY(Tellico::ImageFactory::self()->hasImageInMemory(m_imageId));
0365   QVERIFY(Tellico::ImageFactory::self()->hasImageInfo(m_imageId));
0366 
0367   const Tellico::Data::Image& img = Tellico::ImageFactory::imageById(m_imageId);
0368   QVERIFY(!img.isNull());
0369   // id is not the MD5 hash
0370   QCOMPARE(img.id(), u.url());
0371   QCOMPARE(img.format(), QByteArray("png"));
0372   QCOMPARE(img.linkOnly(), true);
0373 }