| 147 | |
| 148 | template<class CompoundJob> |
| 149 | static void testFinishingSubjob() |
| 150 | { |
| 151 | auto *const job = new KillableTestJob; |
| 152 | auto *const compoundJob = new CompoundJob; |
| 153 | QVERIFY(compoundJob->addSubjob(job)); |
| 154 | |
| 155 | JobSpies jobSpies(job); |
| 156 | JobSpies compoundJobSpies(compoundJob); |
| 157 | |
| 158 | compoundJob->start(); |
| 159 | |
| 160 | using Action = KCompoundJobTest::Action; |
| 161 | QFETCH(const Action, action); |
| 162 | switch (action) { |
| 163 | case Action::Finish: |
| 164 | job->emitResult(); |
| 165 | break; |
| 166 | case Action::KillVerbosely: |
| 167 | QVERIFY(job->kill(KJob::EmitResult)); |
| 168 | break; |
| 169 | case Action::KillQuietly: |
| 170 | QVERIFY(job->kill(KJob::Quietly)); |
| 171 | break; |
| 172 | case Action::Destroy: |
| 173 | job->deleteLater(); |
| 174 | break; |
| 175 | } |
| 176 | |
| 177 | QEventLoop loop; |
| 178 | QTimer::singleShot(100, &loop, &QEventLoop::quit); |
| 179 | QObject::connect(compoundJob, &QObject::destroyed, &loop, &QEventLoop::quit); |
| 180 | QCOMPARE(loop.exec(), 0); |
| 181 | |
| 182 | // The following 3 comparisons verify that KJob works as expected. |
| 183 | QCOMPARE(jobSpies.finished.size(), 1); // KJob::finished() is always emitted. |
| 184 | // KJob::result() is not emitted when a job is killed quietly or destroyed. |
| 185 | QCOMPARE(jobSpies.result.size(), action == Action::Finish || action == Action::KillVerbosely); |
| 186 | // An auto-delete job is destroyed via deleteLater() when finished. |
| 187 | QCOMPARE(jobSpies.destroyed.size(), 1); |
| 188 | |
| 189 | // KCompoundJob must listen to &KJob::finished signal to invoke subjobFinished() |
| 190 | // no matter how a subjob is finished - normally, killed or destroyed. |
| 191 | // CompoundJob calls emitResult() and is destroyed when its last subjob finishes. |
| 192 | QFETCH(const bool, crashOnFailure); |
| 193 | if (crashOnFailure) { |
| 194 | if (compoundJobSpies.destroyed.empty()) { |
| 195 | // compoundJob is still alive. This must be a bug. |
| 196 | // The clearSubjobs() call will segfault if the already destroyed job |
| 197 | // has not been removed from the subjob list. |
| 198 | compoundJob->clearSubjobs(); |
| 199 | delete compoundJob; |
| 200 | } |
| 201 | } else { |
| 202 | QCOMPARE(compoundJobSpies.finished.size(), 1); |
| 203 | QCOMPARE(compoundJobSpies.result.size(), 1); |
| 204 | QCOMPARE(compoundJobSpies.destroyed.size(), 1); |
| 205 | } |
| 206 | } |