summaryrefslogtreecommitdiffstats
path: root/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp')
-rw-r--r--tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp510
1 files changed, 407 insertions, 103 deletions
diff --git a/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp b/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp
index a322a1c11d..40aa89ded4 100644
--- a/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp
+++ b/tests/auto/corelib/thread/qfuturewatcher/tst_qfuturewatcher.cpp
@@ -1,41 +1,17 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#include <QCoreApplication>
#include <QDebug>
#include <QElapsedTimer>
-#include <QtTest/QtTest>
+#include <QSignalSpy>
#include <QtConcurrent>
#include <private/qfutureinterface_p.h>
using namespace QtConcurrent;
+using namespace std::chrono_literals;
-#include <QtTest/QtTest>
+#include <QTest>
//#define PRINT
@@ -46,8 +22,11 @@ private slots:
void startFinish();
void progressValueChanged();
void canceled();
+ void cancelAndFinish_data();
+ void cancelAndFinish();
void resultAt();
void resultReadyAt();
+ void orderedResultReadyAt();
void futureSignals();
void watchFinishedFuture();
void watchCanceledFuture();
@@ -57,14 +36,20 @@ private slots:
void sharedFutureInterface();
void changeFuture();
void cancelEvents();
+#if QT_DEPRECATED_SINCE(6, 0)
void pauseEvents();
- void finishedState();
+ void pausedSuspendedOrder();
+#endif
+ void suspendEvents();
+ void suspended();
+ void suspendedEventsOrder();
void throttling();
void incrementalMapResults();
void incrementalFilterResults();
void qfutureSynchronizer();
void warnRace();
void matchFlags();
+ void checkStateConsistency();
};
void sleeper()
@@ -76,20 +61,31 @@ void tst_QFutureWatcher::startFinish()
{
QFutureWatcher<void> futureWatcher;
- QSignalSpy startedSpy(&futureWatcher, &QFutureWatcher<void>::started);
- QSignalSpy finishedSpy(&futureWatcher, &QFutureWatcher<void>::finished);
-
- QVERIFY(startedSpy.isValid());
- QVERIFY(finishedSpy.isValid());
+ int startedCount = 0;
+ int finishedCount = 0;
+ QObject::connect(&futureWatcher, &QFutureWatcher<void>::started,
+ [&startedCount, &finishedCount](){
+ ++startedCount;
+ QCOMPARE(startedCount, 1);
+ QCOMPARE(finishedCount, 0);
+ });
+ QObject::connect(&futureWatcher, &QFutureWatcher<void>::finished,
+ [&startedCount, &finishedCount](){
+ ++finishedCount;
+ QCOMPARE(startedCount, 1);
+ QCOMPARE(finishedCount, 1);
+ });
futureWatcher.setFuture(QtConcurrent::run(sleeper));
- QVERIFY(startedSpy.wait());
- QCOMPARE(startedSpy.count(), 1);
- QCOMPARE(finishedSpy.count(), 0);
futureWatcher.future().waitForFinished();
- QVERIFY(finishedSpy.wait());
- QCOMPARE(startedSpy.count(), 1);
- QCOMPARE(finishedSpy.count(), 1);
+
+ // waitForFinished() may unblock before asynchronous
+ // started() and finished() signals are delivered to the main thread.
+ // prosessEvents() should empty the pending queue.
+ qApp->processEvents();
+
+ QCOMPARE(startedCount, 1);
+ QCOMPARE(finishedCount, 1);
}
void mapSleeper(int &)
@@ -97,9 +93,9 @@ void mapSleeper(int &)
QTest::qSleep(100);
}
-QSet<int> progressValues;
-QSet<QString> progressTexts;
-QMutex mutex;
+static QSet<int> progressValues;
+static QSet<QString> progressTexts;
+static QMutex mutex;
class ProgressObject : public QObject
{
Q_OBJECT
@@ -174,7 +170,7 @@ class CancelObject : public QObject
Q_OBJECT
public:
bool wasCanceled;
- CancelObject() : wasCanceled(false) {};
+ CancelObject() : wasCanceled(false) {}
public slots:
void cancel();
};
@@ -212,12 +208,48 @@ void tst_QFutureWatcher::canceled()
future.waitForFinished();
}
-class IntTask : public RunFunctionTask<int>
+void tst_QFutureWatcher::cancelAndFinish_data()
+{
+ QTest::addColumn<bool>("isCanceled");
+ QTest::addColumn<bool>("isFinished");
+
+ QTest::addRow("running") << false << false;
+ QTest::addRow("canceled") << true << false;
+ QTest::addRow("finished") << false << true;
+ QTest::addRow("canceledAndFinished") << true << true;
+}
+
+void tst_QFutureWatcher::cancelAndFinish()
+{
+ QFETCH(bool, isCanceled);
+ QFETCH(bool, isFinished);
+
+ QFutureInterface<void> fi;
+ QFutureWatcher<void> futureWatcher;
+ QSignalSpy finishedSpy(&futureWatcher, &QFutureWatcher<void>::finished);
+ QSignalSpy canceledSpy(&futureWatcher, &QFutureWatcher<void>::canceled);
+ futureWatcher.setFuture(fi.future());
+
+ fi.reportStarted();
+
+ if (isCanceled)
+ fi.cancel();
+ if (isFinished)
+ fi.reportFinished();
+
+ fi.cancelAndFinish();
+
+ // The signals should be emitted only once
+ QTRY_COMPARE(canceledSpy.size(), 1);
+ QTRY_COMPARE(finishedSpy.size(), 1);
+}
+
+class IntTask : public RunFunctionTaskBase<int>
{
public:
- void runFunctor()
+ void runFunctor() override
{
- result = 10;
+ promise.reportResult(10);
}
};
@@ -249,6 +281,28 @@ void tst_QFutureWatcher::resultReadyAt()
QVERIFY(resultSpy.wait());
}
+void tst_QFutureWatcher::orderedResultReadyAt()
+{
+ for (int i = 0; i < 1000; ++i) {
+ QObject context;
+ QFuture<QString> f = run([](QPromise<QString> &fi) {
+ fi.addResult("First");
+ fi.addResult("Second");
+ });
+ QList<int> actualIndices;
+
+ QFutureWatcher<QString> watcher;
+ connect(&watcher, &QFutureWatcherBase::resultReadyAt, &context,
+ [&actualIndices](int index) { actualIndices.append(index); });
+ watcher.setFuture(f);
+ f.waitForFinished();
+ QCoreApplication::processEvents();
+ const QList<int> expectedIndices{0, 1};
+ QCOMPARE(actualIndices.size(), expectedIndices.size());
+ QCOMPARE(actualIndices, expectedIndices);
+ }
+}
+
class SignalSlotObject : public QObject
{
Q_OBJECT
@@ -319,21 +373,21 @@ void tst_QFutureWatcher::futureSignals()
const int progress = 1;
a.setProgressValue(progress);
- QTRY_COMPARE(progressSpy.count(), 2);
+ QTRY_COMPARE(progressSpy.size(), 2);
QCOMPARE(progressSpy.takeFirst().at(0).toInt(), 0);
QCOMPARE(progressSpy.takeFirst().at(0).toInt(), 1);
const int result = 10;
a.reportResult(&result);
QVERIFY(resultReadySpy.wait());
- QCOMPARE(resultReadySpy.count(), 1);
+ QCOMPARE(resultReadySpy.size(), 1);
a.reportFinished(&result);
- QTRY_COMPARE(resultReadySpy.count(), 2);
+ QTRY_COMPARE(resultReadySpy.size(), 2);
QCOMPARE(resultReadySpy.takeFirst().at(0).toInt(), 0); // check the index
QCOMPARE(resultReadySpy.takeFirst().at(0).toInt(), 1);
- QCOMPARE(finishedSpy.count(), 1);
+ QCOMPARE(finishedSpy.size(), 1);
}
}
@@ -372,10 +426,10 @@ void tst_QFutureWatcher::watchFinishedFuture()
watcher.setFuture(f);
QVERIFY(finishedSpy.wait());
- QCOMPARE(startedSpy.count(), 1);
- QCOMPARE(finishedSpy.count(), 1);
- QCOMPARE(resultReadySpy.count(), 1);
- QCOMPARE(canceledSpy.count(), 0);
+ QCOMPARE(startedSpy.size(), 1);
+ QCOMPARE(finishedSpy.size(), 1);
+ QCOMPARE(resultReadySpy.size(), 1);
+ QCOMPARE(canceledSpy.size(), 0);
}
void tst_QFutureWatcher::watchCanceledFuture()
@@ -406,10 +460,10 @@ void tst_QFutureWatcher::watchCanceledFuture()
watcher.setFuture(f);
QVERIFY(finishedSpy.wait());
- QCOMPARE(startedSpy.count(), 1);
- QCOMPARE(finishedSpy.count(), 1);
- QCOMPARE(resultReadySpy.count(), 0);
- QCOMPARE(canceledSpy.count(), 1);
+ QCOMPARE(startedSpy.size(), 1);
+ QCOMPARE(finishedSpy.size(), 1);
+ QCOMPARE(resultReadySpy.size(), 0);
+ QCOMPARE(canceledSpy.size(), 1);
}
void tst_QFutureWatcher::disconnectRunningFuture()
@@ -432,28 +486,28 @@ void tst_QFutureWatcher::disconnectRunningFuture()
const int result = 10;
a.reportResult(&result);
QVERIFY(resultReadySpy.wait());
- QCOMPARE(resultReadySpy.count(), 1);
+ QCOMPARE(resultReadySpy.size(), 1);
delete watcher;
a.reportResult(&result);
QTest::qWait(10);
- QCOMPARE(resultReadySpy.count(), 1);
+ QCOMPARE(resultReadySpy.size(), 1);
a.reportFinished(&result);
QTest::qWait(10);
- QCOMPARE(finishedSpy.count(), 0);
+ QCOMPARE(finishedSpy.size(), 0);
}
const int maxProgress = 100000;
-class ProgressEmitterTask : public RunFunctionTask<void>
+class ProgressEmitterTask : public RunFunctionTaskBase<void>
{
public:
- void runFunctor()
+ void runFunctor() override
{
- setProgressRange(0, maxProgress);
+ promise.setProgressRange(0, maxProgress);
for (int p = 0; p <= maxProgress; ++p)
- setProgressValue(p);
+ promise.setProgressValue(p);
}
};
@@ -470,30 +524,31 @@ void tst_QFutureWatcher::tooMuchProgress()
QObject::connect(&f, SIGNAL(progressValueChanged(int)), &o, SLOT(registerProgress(int)));
f.setFuture((new ProgressEmitterTask())->start());
- QTestEventLoop::instance().enterLoop(5);
+ // Android reports ca. 10k progressValueChanged per second
+ QTestEventLoop::instance().enterLoop(15);
QVERIFY(!QTestEventLoop::instance().timeout());
QVERIFY(progressValues.contains(maxProgress));
}
template <typename T>
-class ProgressTextTask : public RunFunctionTask<T>
+class ProgressTextTask : public RunFunctionTaskBase<T>
{
public:
- void runFunctor()
+ void runFunctor() override
{
- this->setProgressValueAndText(1, QLatin1String("Foo 1"));
+ this->promise.setProgressValueAndText(1, QLatin1String("Foo 1"));
- while (this->isProgressUpdateNeeded() == false)
+ while (this->promise.isProgressUpdateNeeded() == false)
QTest::qSleep(1);
- this->setProgressValueAndText(2, QLatin1String("Foo 2"));
+ this->promise.setProgressValueAndText(2, QLatin1String("Foo 2"));
- while (this->isProgressUpdateNeeded() == false)
+ while (this->promise.isProgressUpdateNeeded() == false)
QTest::qSleep(1);
- this->setProgressValueAndText(3, QLatin1String("Foo 3"));
+ this->promise.setProgressValueAndText(3, QLatin1String("Foo 3"));
- while (this->isProgressUpdateNeeded() == false)
+ while (this->promise.isProgressUpdateNeeded() == false)
QTest::qSleep(1);
- this->setProgressValueAndText(4, QLatin1String("Foo 4"));
+ this->promise.setProgressValueAndText(4, QLatin1String("Foo 4"));
}
};
@@ -546,12 +601,21 @@ void callInterface(T &obj)
obj.isFinished();
obj.isRunning();
obj.isCanceled();
- obj.isPaused();
+ obj.isSuspended();
+ obj.isSuspending();
obj.cancel();
- obj.pause();
+ obj.suspend();
obj.resume();
+ obj.toggleSuspended();
+#if QT_DEPRECATED_SINCE(6, 0)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+ obj.isPaused();
+ obj.pause();
obj.togglePaused();
+QT_WARNING_POP
+#endif
obj.waitForFinished();
const T& objConst = obj;
@@ -564,7 +628,14 @@ void callInterface(T &obj)
objConst.isFinished();
objConst.isRunning();
objConst.isCanceled();
+ objConst.isSuspending();
+ objConst.isSuspended();
+#if QT_DEPRECATED_SINCE(6, 0)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
objConst.isPaused();
+QT_WARNING_POP
+#endif
}
template <typename T>
@@ -625,14 +696,14 @@ void tst_QFutureWatcher::changeFuture()
watcher.setFuture(b); // But oh no! we're switching to another future
QTest::qWait(10); // before the event gets delivered.
- QCOMPARE(resultReadySpy.count(), 0);
+ QCOMPARE(resultReadySpy.size(), 0);
watcher.setFuture(a);
watcher.setFuture(b);
watcher.setFuture(a); // setting it back gets us one event, not two.
QVERIFY(resultReadySpy.wait());
- QCOMPARE(resultReadySpy.count(), 1);
+ QCOMPARE(resultReadySpy.size(), 1);
}
// Test that events aren't delivered from canceled futures
@@ -660,9 +731,12 @@ void tst_QFutureWatcher::cancelEvents()
QVERIFY(finishedSpy.wait());
- QCOMPARE(resultReadySpy.count(), 0);
+ QCOMPARE(resultReadySpy.size(), 0);
}
+#if QT_DEPRECATED_SINCE(6, 0)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
// Tests that events from paused futures are saved and
// delivered on resume.
void tst_QFutureWatcher::pauseEvents()
@@ -678,18 +752,22 @@ void tst_QFutureWatcher::pauseEvents()
QSignalSpy resultReadySpy(&watcher, &QFutureWatcher<int>::resultReadyAt);
QVERIFY(resultReadySpy.isValid());
+ QSignalSpy pauseSpy(&watcher, &QFutureWatcher<int>::paused);
+ QVERIFY(pauseSpy.isValid());
+
watcher.setFuture(iface.future());
watcher.pause();
+ QTRY_COMPARE(pauseSpy.size(), 1);
+
int value = 0;
iface.reportFinished(&value);
- QTest::qWait(10);
- QCOMPARE(resultReadySpy.count(), 0);
+ // A result is reported, although the watcher is paused.
+ // The corresponding event should be also reported.
+ QTRY_COMPARE(resultReadySpy.size(), 1);
watcher.resume();
- QTRY_VERIFY2(!resultReadySpy.isEmpty(), "Result didn't arrive");
- QCOMPARE(resultReadySpy.count(), 1);
}
{
QFutureInterface<int> iface;
@@ -715,32 +793,209 @@ void tst_QFutureWatcher::pauseEvents()
a.resume(); // should give us no results.
QTest::qWait(10);
- QCOMPARE(resultReadySpy.count(), 0);
+ QCOMPARE(resultReadySpy.size(), 0);
}
}
-// Test that the finished state for the watcher gets
-// set when the finished event is delivered.
-// This means it will lag the finished state for the future,
-// but makes it more useful.
-void tst_QFutureWatcher::finishedState()
+void tst_QFutureWatcher::pausedSuspendedOrder()
{
- QFutureInterface<int> iface;
+ QFutureInterface<void> iface;
iface.reportStarted();
- QFuture<int> future = iface.future();
+
+ QFutureWatcher<void> watcher;
+
+ QSignalSpy pausedSpy(&watcher, &QFutureWatcher<void>::paused);
+ QVERIFY(pausedSpy.isValid());
+
+ QSignalSpy suspendedSpy(&watcher, &QFutureWatcher<void>::suspended);
+ QVERIFY(suspendedSpy.isValid());
+
+ bool pausedBeforeSuspended = false;
+ bool notSuspendedBeforePaused = false;
+ connect(&watcher, &QFutureWatcher<void>::paused,
+ [&] { notSuspendedBeforePaused = (suspendedSpy.size() == 0); });
+ connect(&watcher, &QFutureWatcher<void>::suspended,
+ [&] { pausedBeforeSuspended = (pausedSpy.size() == 1); });
+
+ watcher.setFuture(iface.future());
+ iface.reportSuspended();
+
+ // Make sure reportPaused() is ignored if the state is not paused
+ pausedSpy.wait(100);
+ QCOMPARE(pausedSpy.size(), 0);
+ QCOMPARE(suspendedSpy.size(), 0);
+
+ iface.setPaused(true);
+ iface.reportSuspended();
+
+ QTRY_COMPARE(suspendedSpy.size(), 1);
+ QCOMPARE(pausedSpy.size(), 1);
+ QVERIFY(notSuspendedBeforePaused);
+ QVERIFY(pausedBeforeSuspended);
+
+ iface.reportFinished();
+}
+QT_WARNING_POP
+#endif // QT_DEPRECATED_SINCE(6, 0)
+
+// Tests that events from suspended futures are saved and
+// delivered on resume.
+void tst_QFutureWatcher::suspendEvents()
+{
+ {
+ QFutureInterface<int> iface;
+ iface.reportStarted();
+
+ QFutureWatcher<int> watcher;
+
+ SignalSlotObject object;
+ connect(&watcher, &QFutureWatcher<int>::resultReadyAt, &object,
+ &SignalSlotObject::resultReadyAt);
+ QSignalSpy resultReadySpy(&watcher, &QFutureWatcher<int>::resultReadyAt);
+ QVERIFY(resultReadySpy.isValid());
+
+ QSignalSpy suspendingSpy(&watcher, &QFutureWatcher<int>::suspending);
+ QVERIFY(suspendingSpy.isValid());
+
+ watcher.setFuture(iface.future());
+ watcher.suspend();
+
+ QTRY_COMPARE(suspendingSpy.size(), 1);
+
+ int value = 0;
+ iface.reportFinished(&value);
+
+ // A result is reported, although the watcher is paused.
+ // The corresponding event should be also reported.
+ QTRY_COMPARE(resultReadySpy.size(), 1);
+
+ watcher.resume();
+ }
+ {
+ QFutureInterface<int> iface;
+ iface.reportStarted();
+
+ QFuture<int> a = iface.future();
+
+ QFutureWatcher<int> watcher;
+
+ SignalSlotObject object;
+ connect(&watcher, &QFutureWatcher<int>::resultReadyAt, &object,
+ &SignalSlotObject::resultReadyAt);
+ QSignalSpy resultReadySpy(&watcher, &QFutureWatcher<int>::resultReadyAt);
+ QVERIFY(resultReadySpy.isValid());
+
+ watcher.setFuture(a);
+ a.suspend();
+
+ int value = 0;
+ iface.reportFinished(&value);
+
+ QFuture<int> b;
+ watcher.setFuture(b); // If we watch b instead, resuming a
+ a.resume(); // should give us no results.
+
+ QTest::qWait(10);
+ QCOMPARE(resultReadySpy.size(), 0);
+ }
+}
+
+void tst_QFutureWatcher::suspended()
+{
QFutureWatcher<int> watcher;
- QSignalSpy startedSpy(&watcher, &QFutureWatcher<int>::started);
+ QSignalSpy resultReadySpy(&watcher, &QFutureWatcher<int>::resultReadyAt);
+#if QT_DEPRECATED_SINCE(6, 0)
+QT_WARNING_PUSH
+QT_WARNING_DISABLE_DEPRECATED
+ QSignalSpy pausedSpy(&watcher, &QFutureWatcher<int>::paused);
+QT_WARNING_POP
+#endif
+ QSignalSpy suspendingSpy(&watcher, &QFutureWatcher<int>::suspending);
+ QSignalSpy suspendedSpy(&watcher, &QFutureWatcher<int>::suspended);
QSignalSpy finishedSpy(&watcher, &QFutureWatcher<int>::finished);
+ const int numValues = 25;
+ std::vector<int> values(numValues, 0);
+ std::atomic_int count = 0;
+
+ QThreadPool pool;
+ pool.setMaxThreadCount(3);
+
+ QFuture<int> future = QtConcurrent::mapped(&pool, values, [&](int value) {
+ ++count;
+ // Sleep, to make sure not all threads will start at once.
+ QThread::sleep(50ms);
+ return value;
+ });
watcher.setFuture(future);
- QVERIFY(startedSpy.wait());
- iface.reportFinished();
- QVERIFY(future.isFinished());
- QVERIFY(!watcher.isFinished());
+ // Allow some threads to start before suspending.
+ QThread::sleep(200ms);
- QVERIFY(finishedSpy.wait());
- QVERIFY(watcher.isFinished());
+ watcher.suspend();
+ watcher.suspend();
+ QTRY_COMPARE(suspendedSpy.size(), 1); // suspended() should be emitted only once
+ QCOMPARE(suspendingSpy.size(), 2); // suspending() is emitted as many times as requested
+#if QT_DEPRECATED_SINCE(6, 0)
+ QCOMPARE(pausedSpy.size(), 2); // paused() is emitted as many times as requested
+#endif
+
+ // Make sure QFutureWatcher::resultReadyAt() is emitted only for already started threads.
+ const auto resultReadyAfterPaused = resultReadySpy.size();
+ QCOMPARE(resultReadyAfterPaused, count);
+
+ // Make sure no more results are reported before resuming.
+ QThread::sleep(200ms);
+ QCOMPARE(resultReadyAfterPaused, resultReadySpy.size());
+ resultReadySpy.clear();
+
+ watcher.resume();
+ QTRY_COMPARE(finishedSpy.size(), 1);
+
+ // Make sure that no more suspended() signals have been emitted.
+ QCOMPARE(suspendedSpy.size(), 1);
+
+ // Make sure the rest of results were reported after resume.
+ QCOMPARE(resultReadySpy.size(), numValues - resultReadyAfterPaused);
+}
+
+void tst_QFutureWatcher::suspendedEventsOrder()
+{
+ QFutureInterface<void> iface;
+ iface.reportStarted();
+
+ QFutureWatcher<void> watcher;
+
+ QSignalSpy suspendingSpy(&watcher, &QFutureWatcher<void>::suspending);
+ QVERIFY(suspendingSpy.isValid());
+
+ QSignalSpy suspendedSpy(&watcher, &QFutureWatcher<void>::suspended);
+ QVERIFY(suspendedSpy.isValid());
+
+ bool suspendingBeforeSuspended = false;
+ bool notSuspendedBeforeSuspending = false;
+ connect(&watcher, &QFutureWatcher<void>::suspending,
+ [&] { notSuspendedBeforeSuspending = (suspendedSpy.size() == 0); });
+ connect(&watcher, &QFutureWatcher<void>::suspended,
+ [&] { suspendingBeforeSuspended = (suspendingSpy.size() == 1); });
+
+ watcher.setFuture(iface.future());
+ iface.reportSuspended();
+
+ // Make sure reportPaused() is ignored if the state is not paused
+ suspendingSpy.wait(100);
+ QCOMPARE(suspendingSpy.size(), 0);
+ QCOMPARE(suspendedSpy.size(), 0);
+
+ iface.setSuspended(true);
+ iface.reportSuspended();
+
+ QTRY_COMPARE(suspendedSpy.size(), 1);
+ QCOMPARE(suspendingSpy.size(), 1);
+ QVERIFY(notSuspendedBeforeSuspending);
+ QVERIFY(suspendingBeforeSuspended);
+
+ iface.reportFinished();
}
/*
@@ -766,7 +1021,7 @@ void tst_QFutureWatcher::throttling()
QVERIFY(iface.isThrottled());
- QTRY_COMPARE(resultSpy.count(), resultCount); // Process the results
+ QTRY_COMPARE(resultSpy.size(), resultCount); // Process the results
QVERIFY(!iface.isThrottled());
@@ -908,7 +1163,7 @@ public:
void tst_QFutureWatcher::warnRace()
{
-#ifndef Q_OS_MAC //I don't know why it is not working on mac
+#ifndef Q_OS_DARWIN // I don't know why it is not working on mac
#ifndef QT_NO_DEBUG
QTest::ignoreMessage(QtWarningMsg, "QFutureWatcher::connect: connecting after calling setFuture() is likely to produce race");
#endif
@@ -937,6 +1192,55 @@ void tst_QFutureWatcher::matchFlags()
QCOMPARE(watcher.isFinished(), future.isFinished());
}
+void tst_QFutureWatcher::checkStateConsistency()
+{
+#define CHECK_FAIL(state) \
+ do { \
+ if (QTest::currentTestFailed()) \
+ QFAIL("checkState() failed, QFutureWatcher has inconistent state after " state "!"); \
+ } while (false)
+
+ QFutureWatcher<void> futureWatcher;
+
+ auto checkState = [&futureWatcher] {
+ QCOMPARE(futureWatcher.isStarted(), futureWatcher.future().isStarted());
+ QCOMPARE(futureWatcher.isRunning(), futureWatcher.future().isRunning());
+ QCOMPARE(futureWatcher.isCanceled(), futureWatcher.future().isCanceled());
+ QCOMPARE(futureWatcher.isSuspended(), futureWatcher.future().isSuspended());
+ QCOMPARE(futureWatcher.isSuspending(), futureWatcher.future().isSuspending());
+ QCOMPARE(futureWatcher.isFinished(), futureWatcher.future().isFinished());
+ };
+
+ checkState();
+ CHECK_FAIL("default-constructing");
+
+ QFutureInterface<void> fi;
+ futureWatcher.setFuture(fi.future());
+ checkState();
+ CHECK_FAIL("setting future");
+
+ fi.reportStarted();
+ checkState();
+ CHECK_FAIL("starting");
+
+ fi.future().suspend();
+ checkState();
+ CHECK_FAIL("suspending");
+
+ fi.reportSuspended();
+ checkState();
+ CHECK_FAIL("suspended");
+
+ fi.reportCanceled();
+ checkState();
+ CHECK_FAIL("canceling");
+
+ fi.reportFinished();
+ checkState();
+ CHECK_FAIL("finishing");
+
+#undef CHECK_FAIL
+}
QTEST_MAIN(tst_QFutureWatcher)
#include "tst_qfuturewatcher.moc"