File indexing completed on 2024-04-28 15:20:09

0001 /*
0002     This file is part of the KDE project
0003     SPDX-FileCopyrightText: 2006 Kevin Ottens <ervin@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #include "kjobtest.h"
0009 
0010 #include <QMetaEnum>
0011 #include <QSignalSpy>
0012 #include <QTest>
0013 #include <QTimer>
0014 #include <QVector>
0015 
0016 #include <string>
0017 
0018 QTEST_MAIN(KJobTest)
0019 
0020 KJobTest::KJobTest()
0021     : loop(this)
0022 {
0023 }
0024 
0025 void KJobTest::testEmitResult_data()
0026 {
0027     QTest::addColumn<int>("errorCode");
0028     QTest::addColumn<QString>("errorText");
0029 
0030     QTest::newRow("no error") << int(KJob::NoError) << QString();
0031     QTest::newRow("error no text") << 2 << QString();
0032     QTest::newRow("error with text") << 6 << "oops! an error? naaah, really?";
0033 }
0034 
0035 void KJobTest::testEmitResult()
0036 {
0037     TestJob *job = new TestJob;
0038 
0039     connect(job, &KJob::result, this, [this](KJob *job) {
0040         slotResult(job);
0041         loop.quit();
0042     });
0043 
0044     QFETCH(int, errorCode);
0045     QFETCH(QString, errorText);
0046 
0047     job->setError(errorCode);
0048     job->setErrorText(errorText);
0049 
0050     QSignalSpy destroyed_spy(job, &QObject::destroyed);
0051     job->start();
0052     QVERIFY(!job->isFinished());
0053     loop.exec();
0054     QVERIFY(job->isFinished());
0055 
0056     QCOMPARE(m_lastError, errorCode);
0057     QCOMPARE(m_lastErrorText, errorText);
0058 
0059     // Verify that the job is not deleted immediately...
0060     QCOMPARE(destroyed_spy.size(), 0);
0061     QTimer::singleShot(0, &loop, &QEventLoop::quit);
0062     // ... but when we enter the event loop again.
0063     loop.exec();
0064     QCOMPARE(destroyed_spy.size(), 1);
0065 }
0066 
0067 void KJobTest::testProgressTracking()
0068 {
0069     TestJob *testJob = new TestJob;
0070     KJob *job = testJob;
0071 
0072     qRegisterMetaType<KJob *>("KJob*");
0073     qRegisterMetaType<qulonglong>("qulonglong");
0074 
0075 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 80)
0076     QSignalSpy processed_spy(job, qOverload<KJob *, KJob::Unit, qulonglong>(&KJob::processedAmount));
0077     QSignalSpy total_spy(job, qOverload<KJob *, KJob::Unit, qulonglong>(&KJob::totalAmount));
0078     QSignalSpy percent_spy(job, qOverload<KJob *, ulong>(&KJob::percent));
0079 #endif
0080     QSignalSpy processedChanged_spy(job, &KJob::processedAmountChanged);
0081     QSignalSpy totalChanged_spy(job, &KJob::totalAmountChanged);
0082     QSignalSpy percentChanged_spy(job, &KJob::percentChanged);
0083 
0084     /* Process a first item. Corresponding signal should be emitted.
0085      * Total size didn't change.
0086      * Since the total size is unknown, no percent signal is emitted.
0087      */
0088     testJob->setProcessedSize(1);
0089 
0090 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 80)
0091     QCOMPARE(processed_spy.size(), 1);
0092     QCOMPARE(processed_spy.at(0).at(0).value<KJob *>(), static_cast<KJob *>(job));
0093     QCOMPARE(processed_spy.at(0).at(2).value<qulonglong>(), qulonglong(1));
0094     QCOMPARE(total_spy.size(), 0);
0095     QCOMPARE(percent_spy.size(), 0);
0096 #endif
0097     QCOMPARE(processedChanged_spy.size(), 1);
0098     QCOMPARE(processedChanged_spy.at(0).at(0).value<KJob *>(), static_cast<KJob *>(job));
0099     QCOMPARE(processedChanged_spy.at(0).at(2).value<qulonglong>(), qulonglong(1));
0100     QCOMPARE(totalChanged_spy.size(), 0);
0101     QCOMPARE(percentChanged_spy.size(), 0);
0102 
0103     /* Now, we know the total size. It's signaled.
0104      * The new percentage is signaled too.
0105      */
0106     testJob->setTotalSize(10);
0107 
0108 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 80)
0109     QCOMPARE(processed_spy.size(), 1);
0110     QCOMPARE(total_spy.size(), 1);
0111     QCOMPARE(total_spy.at(0).at(0).value<KJob *>(), job);
0112     QCOMPARE(total_spy.at(0).at(2).value<qulonglong>(), qulonglong(10));
0113     QCOMPARE(percent_spy.size(), 1);
0114     QCOMPARE(percent_spy.at(0).at(0).value<KJob *>(), job);
0115     QCOMPARE(percent_spy.at(0).at(1).value<unsigned long>(), static_cast<unsigned long>(10));
0116 #endif
0117     QCOMPARE(processedChanged_spy.size(), 1);
0118     QCOMPARE(totalChanged_spy.size(), 1);
0119     QCOMPARE(totalChanged_spy.at(0).at(0).value<KJob *>(), job);
0120     QCOMPARE(totalChanged_spy.at(0).at(2).value<qulonglong>(), qulonglong(10));
0121     QCOMPARE(percentChanged_spy.size(), 1);
0122     QCOMPARE(percentChanged_spy.at(0).at(0).value<KJob *>(), job);
0123     QCOMPARE(percentChanged_spy.at(0).at(1).value<unsigned long>(), static_cast<unsigned long>(10));
0124 
0125     /* We announce a new percentage by hand.
0126      * Total, and processed didn't change, so no signal is emitted for them.
0127      */
0128     testJob->setPercent(15);
0129 
0130 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 80)
0131     QCOMPARE(processed_spy.size(), 1);
0132     QCOMPARE(total_spy.size(), 1);
0133     QCOMPARE(percent_spy.size(), 2);
0134     QCOMPARE(percent_spy.at(1).at(0).value<KJob *>(), job);
0135     QCOMPARE(percent_spy.at(1).at(1).value<unsigned long>(), static_cast<unsigned long>(15));
0136 #endif
0137     QCOMPARE(processedChanged_spy.size(), 1);
0138     QCOMPARE(totalChanged_spy.size(), 1);
0139     QCOMPARE(percentChanged_spy.size(), 2);
0140     QCOMPARE(percentChanged_spy.at(1).at(0).value<KJob *>(), job);
0141     QCOMPARE(percentChanged_spy.at(1).at(1).value<unsigned long>(), static_cast<unsigned long>(15));
0142 
0143     /* We make some progress.
0144      * Processed size and percent are signaled.
0145      */
0146     testJob->setProcessedSize(3);
0147 
0148 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 80)
0149     QCOMPARE(processed_spy.size(), 2);
0150     QCOMPARE(processed_spy.at(1).at(0).value<KJob *>(), job);
0151     QCOMPARE(processed_spy.at(1).at(2).value<qulonglong>(), qulonglong(3));
0152     QCOMPARE(total_spy.size(), 1);
0153     QCOMPARE(percent_spy.size(), 3);
0154     QCOMPARE(percent_spy.at(2).at(0).value<KJob *>(), job);
0155     QCOMPARE(percent_spy.at(2).at(1).value<unsigned long>(), static_cast<unsigned long>(30));
0156 #endif
0157     QCOMPARE(processedChanged_spy.size(), 2);
0158     QCOMPARE(processedChanged_spy.at(1).at(0).value<KJob *>(), job);
0159     QCOMPARE(processedChanged_spy.at(1).at(2).value<qulonglong>(), qulonglong(3));
0160     QCOMPARE(totalChanged_spy.size(), 1);
0161     QCOMPARE(percentChanged_spy.size(), 3);
0162     QCOMPARE(percentChanged_spy.at(2).at(0).value<KJob *>(), job);
0163     QCOMPARE(percentChanged_spy.at(2).at(1).value<unsigned long>(), static_cast<unsigned long>(30));
0164 
0165     /* We set a new total size, but equals to the previous one.
0166      * No signal is emitted.
0167      */
0168     testJob->setTotalSize(10);
0169 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 80)
0170     QCOMPARE(processed_spy.size(), 2);
0171     QCOMPARE(total_spy.size(), 1);
0172     QCOMPARE(percent_spy.size(), 3);
0173 #endif
0174     QCOMPARE(processedChanged_spy.size(), 2);
0175     QCOMPARE(totalChanged_spy.size(), 1);
0176     QCOMPARE(percentChanged_spy.size(), 3);
0177 
0178     /* We 'lost' the previous work done.
0179      * Signals both percentage and new processed size.
0180      */
0181     testJob->setProcessedSize(0);
0182 
0183 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 80)
0184     QCOMPARE(processed_spy.size(), 3);
0185     QCOMPARE(processed_spy.at(2).at(0).value<KJob *>(), job);
0186     QCOMPARE(processed_spy.at(2).at(2).value<qulonglong>(), qulonglong(0));
0187     QCOMPARE(total_spy.size(), 1);
0188     QCOMPARE(percent_spy.size(), 4);
0189     QCOMPARE(percent_spy.at(3).at(0).value<KJob *>(), job);
0190     QCOMPARE(percent_spy.at(3).at(1).value<unsigned long>(), static_cast<unsigned long>(0));
0191 #endif
0192     QCOMPARE(processedChanged_spy.size(), 3);
0193     QCOMPARE(processedChanged_spy.at(2).at(0).value<KJob *>(), job);
0194     QCOMPARE(processedChanged_spy.at(2).at(2).value<qulonglong>(), qulonglong(0));
0195     QCOMPARE(totalChanged_spy.size(), 1);
0196     QCOMPARE(percentChanged_spy.size(), 4);
0197     QCOMPARE(percentChanged_spy.at(3).at(0).value<KJob *>(), job);
0198     QCOMPARE(percentChanged_spy.at(3).at(1).value<unsigned long>(), static_cast<unsigned long>(0));
0199 
0200     /* We process more than the total size!?
0201      * Signals both percentage and new processed size.
0202      * Percentage is 150%
0203      *
0204      * Might sounds weird, but verify that this case is handled gracefully.
0205      */
0206     testJob->setProcessedSize(15);
0207 
0208 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 80)
0209     QCOMPARE(processed_spy.size(), 4);
0210     QCOMPARE(processed_spy.at(3).at(0).value<KJob *>(), job);
0211     QCOMPARE(processed_spy.at(3).at(2).value<qulonglong>(), qulonglong(15));
0212     QCOMPARE(total_spy.size(), 1);
0213     QCOMPARE(percent_spy.size(), 5);
0214     QCOMPARE(percent_spy.at(4).at(0).value<KJob *>(), job);
0215     QCOMPARE(percent_spy.at(4).at(1).value<unsigned long>(), static_cast<unsigned long>(150));
0216 #endif
0217     QCOMPARE(processedChanged_spy.size(), 4);
0218     QCOMPARE(processedChanged_spy.at(3).at(0).value<KJob *>(), job);
0219     QCOMPARE(processedChanged_spy.at(3).at(2).value<qulonglong>(), qulonglong(15));
0220     QCOMPARE(totalChanged_spy.size(), 1);
0221     QCOMPARE(percentChanged_spy.size(), 5);
0222     QCOMPARE(percentChanged_spy.at(4).at(0).value<KJob *>(), job);
0223     QCOMPARE(percentChanged_spy.at(4).at(1).value<unsigned long>(), static_cast<unsigned long>(150));
0224 
0225 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 80)
0226     processed_spy.clear();
0227     total_spy.clear();
0228     percent_spy.clear();
0229 #endif
0230     processedChanged_spy.clear();
0231     totalChanged_spy.clear();
0232     percentChanged_spy.clear();
0233 
0234     /**
0235      * Try again with Files as the progress unit
0236      */
0237     testJob->setProgressUnit(KJob::Files);
0238     testJob->setProcessedSize(16);
0239 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 80)
0240     QCOMPARE(percent_spy.size(), 0); // no impact on percent
0241 #endif
0242     QCOMPARE(percentChanged_spy.size(), 0);
0243 
0244     testJob->setTotalFiles(5);
0245 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 80)
0246     QCOMPARE(percent_spy.size(), 1);
0247     QCOMPARE(percent_spy.at(0).at(1).value<unsigned long>(), static_cast<unsigned long>(0));
0248 #endif
0249     QCOMPARE(percentChanged_spy.size(), 1);
0250     QCOMPARE(percentChanged_spy.at(0).at(1).value<unsigned long>(), static_cast<unsigned long>(0));
0251 
0252     testJob->setProcessedFiles(2);
0253 #if KCOREADDONS_ENABLE_DEPRECATED_SINCE(5, 80)
0254     QCOMPARE(percent_spy.size(), 2);
0255     QCOMPARE(percent_spy.at(1).at(1).value<unsigned long>(), static_cast<unsigned long>(40));
0256 #endif
0257     QCOMPARE(percentChanged_spy.size(), 2);
0258     QCOMPARE(percentChanged_spy.at(1).at(1).value<unsigned long>(), static_cast<unsigned long>(40));
0259 
0260     delete job;
0261 }
0262 
0263 void KJobTest::testExec_data()
0264 {
0265     QTest::addColumn<int>("errorCode");
0266     QTest::addColumn<QString>("errorText");
0267 
0268     QTest::newRow("no error") << int(KJob::NoError) << QString();
0269     QTest::newRow("error no text") << 2 << QString();
0270     QTest::newRow("error with text") << 6 << "oops! an error? naaah, really?";
0271 }
0272 
0273 void KJobTest::testExec()
0274 {
0275     TestJob *job = new TestJob;
0276 
0277     QFETCH(int, errorCode);
0278     QFETCH(QString, errorText);
0279 
0280     job->setError(errorCode);
0281     job->setErrorText(errorText);
0282 
0283     int resultEmitted = 0;
0284     // Prove to Kai Uwe that one can connect a job to a lambdas, despite the "private" signal
0285     connect(job, &KJob::result, this, [&resultEmitted](KJob *) {
0286         ++resultEmitted;
0287     });
0288 
0289     QSignalSpy destroyed_spy(job, &QObject::destroyed);
0290 
0291     QVERIFY(!job->isFinished());
0292     bool status = job->exec();
0293     QVERIFY(job->isFinished());
0294 
0295     QCOMPARE(resultEmitted, 1);
0296     QCOMPARE(status, (errorCode == KJob::NoError));
0297     QCOMPARE(job->error(), errorCode);
0298     QCOMPARE(job->errorText(), errorText);
0299 
0300     // Verify that the job is not deleted immediately...
0301     QCOMPARE(destroyed_spy.size(), 0);
0302     QTimer::singleShot(0, &loop, &QEventLoop::quit);
0303     // ... but when we enter the event loop again.
0304     loop.exec();
0305     QCOMPARE(destroyed_spy.size(), 1);
0306 }
0307 
0308 void KJobTest::testKill_data()
0309 {
0310     QTest::addColumn<int>("killVerbosity");
0311     QTest::addColumn<int>("errorCode");
0312     QTest::addColumn<QString>("errorText");
0313     QTest::addColumn<int>("resultEmitCount");
0314     QTest::addColumn<int>("finishedEmitCount");
0315 
0316     QTest::newRow("killed with result") << int(KJob::EmitResult) << int(KJob::KilledJobError) << QString() << 1 << 1;
0317     QTest::newRow("killed quietly") << int(KJob::Quietly) << int(KJob::KilledJobError) << QString() << 0 << 1;
0318 }
0319 
0320 void KJobTest::testKill()
0321 {
0322     auto *const job = setupErrorResultFinished();
0323     QSignalSpy destroyed_spy(job, &QObject::destroyed);
0324 
0325     QFETCH(int, killVerbosity);
0326     QFETCH(int, errorCode);
0327     QFETCH(QString, errorText);
0328     QFETCH(int, resultEmitCount);
0329     QFETCH(int, finishedEmitCount);
0330 
0331     QVERIFY(!job->isFinished());
0332     job->kill(static_cast<KJob::KillVerbosity>(killVerbosity));
0333     QVERIFY(job->isFinished());
0334     loop.processEvents(QEventLoop::AllEvents, 2000);
0335 
0336     QCOMPARE(m_lastError, errorCode);
0337     QCOMPARE(m_lastErrorText, errorText);
0338 
0339     QCOMPARE(job->error(), errorCode);
0340     QCOMPARE(job->errorText(), errorText);
0341 
0342     QCOMPARE(m_resultCount, resultEmitCount);
0343     QCOMPARE(m_finishedCount, finishedEmitCount);
0344 
0345     // Verify that the job is not deleted immediately...
0346     QCOMPARE(destroyed_spy.size(), 0);
0347     QTimer::singleShot(0, &loop, &QEventLoop::quit);
0348     // ... but when we enter the event loop again.
0349     loop.exec();
0350     QCOMPARE(destroyed_spy.size(), 1);
0351 
0352     QVERIFY(m_jobFinishCount.size() == (finishedEmitCount - resultEmitCount));
0353     m_jobFinishCount.clear();
0354 }
0355 
0356 void KJobTest::testDestroy()
0357 {
0358     auto *const job = setupErrorResultFinished();
0359     QVERIFY(!job->isFinished());
0360     delete job;
0361     QCOMPARE(m_lastError, static_cast<int>(KJob::NoError));
0362     QCOMPARE(m_lastErrorText, QString{});
0363     QCOMPARE(m_resultCount, 0);
0364     QCOMPARE(m_finishedCount, 1);
0365 
0366     QVERIFY(m_jobFinishCount.size() == 1);
0367     m_jobFinishCount.clear();
0368 }
0369 
0370 void KJobTest::testEmitAtMostOnce_data()
0371 {
0372     QTest::addColumn<bool>("autoDelete");
0373     QTest::addColumn<QVector<Action>>("actions");
0374 
0375     const auto actionName = [](Action action) {
0376         return QMetaEnum::fromType<Action>().valueToKey(static_cast<int>(action));
0377     };
0378 
0379     for (bool autoDelete : {true, false}) {
0380         for (Action a : {Action::Start, Action::KillQuietly, Action::KillVerbosely}) {
0381             for (Action b : {Action::Start, Action::KillQuietly, Action::KillVerbosely}) {
0382                 const auto dataTag = std::string{actionName(a)} + '-' + actionName(b) + (autoDelete ? "-autoDelete" : "");
0383                 QTest::newRow(dataTag.c_str()) << autoDelete << QVector<Action>{a, b};
0384             }
0385         }
0386     }
0387 }
0388 
0389 void KJobTest::testEmitAtMostOnce()
0390 {
0391     auto *const job = setupErrorResultFinished();
0392     QSignalSpy destroyed_spy(job, &QObject::destroyed);
0393 
0394     QFETCH(bool, autoDelete);
0395     job->setAutoDelete(autoDelete);
0396 
0397     QFETCH(QVector<Action>, actions);
0398     for (auto action : actions) {
0399         switch (action) {
0400         case Action::Start:
0401             job->start(); // in effect calls QTimer::singleShot(0, ... emitResult)
0402             break;
0403         case Action::KillQuietly:
0404             QTimer::singleShot(0, job, [=] {
0405                 job->kill(KJob::Quietly);
0406             });
0407             break;
0408         case Action::KillVerbosely:
0409             QTimer::singleShot(0, job, [=] {
0410                 job->kill(KJob::EmitResult);
0411             });
0412             break;
0413         }
0414     }
0415 
0416     QVERIFY(!job->isFinished());
0417     loop.processEvents(QEventLoop::AllEvents, 2000);
0418     QCOMPARE(destroyed_spy.size(), autoDelete);
0419     if (!autoDelete) {
0420         QVERIFY(job->isFinished());
0421     }
0422 
0423     QVERIFY(!actions.empty());
0424     // The first action alone should determine the job's error and result.
0425     const auto firstAction = actions.front();
0426 
0427     const int errorCode = firstAction == Action::Start ? KJob::NoError : KJob::KilledJobError;
0428     QCOMPARE(m_lastError, errorCode);
0429     QCOMPARE(m_lastErrorText, QString{});
0430     if (!autoDelete) {
0431         QCOMPARE(job->error(), m_lastError);
0432         QCOMPARE(job->errorText(), m_lastErrorText);
0433     }
0434 
0435     QCOMPARE(m_resultCount, firstAction == Action::KillQuietly ? 0 : 1);
0436     QCOMPARE(m_finishedCount, 1);
0437 
0438     if (!autoDelete) {
0439         delete job;
0440     }
0441 }
0442 
0443 void KJobTest::testDelegateUsage()
0444 {
0445     TestJob *job1 = new TestJob;
0446     TestJob *job2 = new TestJob;
0447     TestJobUiDelegate *delegate = new TestJobUiDelegate;
0448     QPointer<TestJobUiDelegate> guard(delegate);
0449 
0450     QVERIFY(job1->uiDelegate() == nullptr);
0451     job1->setUiDelegate(delegate);
0452     QVERIFY(job1->uiDelegate() == delegate);
0453 
0454     QVERIFY(job2->uiDelegate() == nullptr);
0455     job2->setUiDelegate(delegate);
0456     QVERIFY(job2->uiDelegate() == nullptr);
0457 
0458     delete job1;
0459     delete job2;
0460     QVERIFY(guard.isNull()); // deleted by job1
0461 }
0462 
0463 void KJobTest::testNestedExec()
0464 {
0465     m_innerJob = nullptr;
0466     QTimer::singleShot(100, this, &KJobTest::slotStartInnerJob);
0467     m_outerJob = new WaitJob();
0468     m_outerJob->exec();
0469 }
0470 
0471 void KJobTest::slotStartInnerJob()
0472 {
0473     QTimer::singleShot(100, this, &KJobTest::slotFinishOuterJob);
0474     m_innerJob = new WaitJob();
0475     m_innerJob->exec();
0476 }
0477 
0478 void KJobTest::slotFinishOuterJob()
0479 {
0480     QTimer::singleShot(100, this, &KJobTest::slotFinishInnerJob);
0481     m_outerJob->makeItFinish();
0482 }
0483 
0484 void KJobTest::slotFinishInnerJob()
0485 {
0486     m_innerJob->makeItFinish();
0487 }
0488 
0489 void KJobTest::slotResult(KJob *job)
0490 {
0491     const auto testJob = qobject_cast<const TestJob *>(job);
0492     QVERIFY(testJob);
0493     QVERIFY(testJob->isFinished());
0494 
0495     // Ensure the job has already emitted finished() if we are tracking from
0496     // setupErrorResultFinished
0497     if (m_jobFinishCount.contains(job)) {
0498         QVERIFY(m_jobFinishCount.value(job) == 1);
0499         QVERIFY(m_jobFinishCount.remove(job) == 1 /* num items removed */);
0500     }
0501 
0502     if (job->error()) {
0503         m_lastError = job->error();
0504         m_lastErrorText = job->errorText();
0505     } else {
0506         m_lastError = KJob::NoError;
0507         m_lastErrorText.clear();
0508     }
0509 
0510     m_resultCount++;
0511 }
0512 
0513 void KJobTest::slotFinished(KJob *job)
0514 {
0515     QVERIFY2(m_jobFinishCount.value(job) == 0, "Ensure we have not double-emitted KJob::finished()");
0516     m_jobFinishCount[job]++;
0517 
0518     if (job->error()) {
0519         m_lastError = job->error();
0520         m_lastErrorText = job->errorText();
0521     } else {
0522         m_lastError = KJob::NoError;
0523         m_lastErrorText.clear();
0524     }
0525 
0526     m_finishedCount++;
0527 }
0528 
0529 TestJob *KJobTest::setupErrorResultFinished()
0530 {
0531     m_lastError = KJob::UserDefinedError;
0532     m_lastErrorText.clear();
0533     m_resultCount = 0;
0534     m_finishedCount = 0;
0535 
0536     auto *job = new TestJob;
0537     m_jobFinishCount[job] = 0;
0538     connect(job, &KJob::result, this, &KJobTest::slotResult);
0539     connect(job, &KJob::finished, this, &KJobTest::slotFinished);
0540     return job;
0541 }
0542 
0543 TestJob::TestJob()
0544     : KJob()
0545 {
0546 }
0547 
0548 TestJob::~TestJob()
0549 {
0550 }
0551 
0552 void TestJob::start()
0553 {
0554     QTimer::singleShot(0, this, [this] {
0555         emitResult();
0556     });
0557 }
0558 
0559 bool TestJob::doKill()
0560 {
0561     return true;
0562 }
0563 
0564 void TestJob::setError(int errorCode)
0565 {
0566     KJob::setError(errorCode);
0567 }
0568 
0569 void TestJob::setErrorText(const QString &errorText)
0570 {
0571     KJob::setErrorText(errorText);
0572 }
0573 
0574 void TestJob::setProcessedSize(qulonglong size)
0575 {
0576     KJob::setProcessedAmount(KJob::Bytes, size);
0577 }
0578 
0579 void TestJob::setTotalSize(qulonglong size)
0580 {
0581     KJob::setTotalAmount(KJob::Bytes, size);
0582 }
0583 
0584 void TestJob::setProcessedFiles(qulonglong files)
0585 {
0586     KJob::setProcessedAmount(KJob::Files, files);
0587 }
0588 
0589 void TestJob::setTotalFiles(qulonglong files)
0590 {
0591     KJob::setTotalAmount(KJob::Files, files);
0592 }
0593 
0594 void TestJob::setPercent(unsigned long percentage)
0595 {
0596     KJob::setPercent(percentage);
0597 }
0598 
0599 void WaitJob::start()
0600 {
0601 }
0602 
0603 void WaitJob::makeItFinish()
0604 {
0605     emitResult();
0606 }
0607 
0608 void TestJobUiDelegate::connectJob(KJob *job)
0609 {
0610     QVERIFY(job->uiDelegate() != nullptr);
0611 }
0612 
0613 #include "moc_kjobtest.cpp"