qt5base-lts/tests/auto/qfuture/tst_qfuture.cpp
Qt by Nokia 38be0d1383 Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you
want to look at revision history older than this, please refer to the
Qt Git wiki for how to use Git history grafting. At the time of
writing, this wiki is located here:

http://qt.gitorious.org/qt/pages/GitIntroductionWithQt

If you have already performed the grafting and you don't see any
history beyond this commit, try running "git log" with the "--follow"
argument.

Branched from the monolithic repo, Qt master branch, at commit
896db169ea224deb96c59ce8af800d019de63f12
2011-04-27 12:05:43 +02:00

1469 lines
34 KiB
C++

/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the test suite of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <QCoreApplication>
#include <QDebug>
#define QFUTURE_TEST
#include <QtTest/QtTest>
#include <qfuture.h>
#include "versioncheck.h"
#include <qfuturewatcher.h>
#include <qtconcurrentresultstore.h>
#include <qtconcurrentexception.h>
#ifndef QT_NO_CONCURRENT_TEST
#include <private/qfutureinterface_p.h>
using namespace QtConcurrent;
//TESTED_CLASS=
//TESTED_FILES=
class tst_QFuture: public QObject
{
Q_OBJECT
private slots:
void resultStore();
void future();
void futureInterface();
void refcounting();
void cancel();
void statePropagation();
void multipleResults();
void indexedResults();
void progress();
void progressText();
void resultsAfterFinished();
void resultsAsList();
void implicitConversions();
void iterators();
void pause();
void throttling();
void voidConversions();
#ifndef QT_NO_EXCEPTIONS
void exceptions();
void exceptions_QTBUG18149();
#endif
};
QTEST_MAIN(tst_QFuture)
void tst_QFuture::resultStore()
{
int int0 = 0;
int int1 = 1;
int int2 = 2;
{
ResultStore<int> store;
ResultIteratorBase it = store.begin();
QVERIFY(store.begin() == store.end());
QVERIFY(store.resultAt(0) == store.end());
QVERIFY(store.resultAt(1) == store.end());
}
{
ResultStoreBase store;
store.addResult(-1, &int0); // note to self: adding a pointer to the stack here is ok since
store.addResult(1, &int1); // ResultStoreBase does not take ownership, only ResultStore<> does.
ResultIteratorBase it = store.begin();
QCOMPARE(it.resultIndex(), 0);
QVERIFY(it == store.begin());
QVERIFY(it != store.end());
++it;
QCOMPARE(it.resultIndex(), 1);
QVERIFY(it != store.begin());
QVERIFY(it != store.end());
++it;
QVERIFY(it != store.begin());
QVERIFY(it == store.end());
}
QVector<int> vec0 = QVector<int>() << 2 << 3;
QVector<int> vec1 = QVector<int>() << 4 << 5;
{
ResultStoreBase store;
store.addResults(-1, &vec0, 2, 2);
store.addResults(-1, &vec1, 2, 2);
ResultIteratorBase it = store.begin();
QCOMPARE(it.resultIndex(), 0);
QVERIFY(it == store.begin());
QVERIFY(it != store.end());
++it;
QCOMPARE(it.resultIndex(), 1);
QVERIFY(it != store.begin());
QVERIFY(it != store.end());
++it;
QCOMPARE(it.resultIndex(), 2);
++it;
QCOMPARE(it.resultIndex(), 3);
++it;
QVERIFY(it == store.end());
}
{
ResultStoreBase store;
store.addResult(-1, &int0);
store.addResults(-1, &vec1, 2, 2);
store.addResult(-1, &int1);
ResultIteratorBase it = store.begin();
QCOMPARE(it.resultIndex(), 0);
QVERIFY(it == store.begin());
QVERIFY(it != store.end());
++it;
QCOMPARE(it.resultIndex(), 1);
QVERIFY(it != store.begin());
QVERIFY(it != store.end());
++it;
QCOMPARE(it.resultIndex(), 2);
QVERIFY(it != store.end());
++it;
QCOMPARE(it.resultIndex(), 3);
QVERIFY(it != store.end());
++it;
QVERIFY(it == store.end());
QCOMPARE(store.resultAt(0).resultIndex(), 0);
QCOMPARE(store.resultAt(1).resultIndex(), 1);
QCOMPARE(store.resultAt(2).resultIndex(), 2);
QCOMPARE(store.resultAt(3).resultIndex(), 3);
QCOMPARE(store.resultAt(4), store.end());
}
{
ResultStore<int> store;
store.addResult(-1, &int0);
store.addResults(-1, &vec0);
store.addResult(-1, &int1);
ResultIteratorBase it = store.begin();
QCOMPARE(it.resultIndex(), 0);
QVERIFY(it == store.begin());
QVERIFY(it != store.end());
++it;
QCOMPARE(it.resultIndex(), 1);
QVERIFY(it != store.begin());
QVERIFY(it != store.end());
++it;
QCOMPARE(it.resultIndex(), 2);
QVERIFY(it != store.end());
++it;
QCOMPARE(it.resultIndex(), 3);
QVERIFY(it != store.end());
++it;
QVERIFY(it == store.end());
QCOMPARE(store.resultAt(0).value(), int0);
QCOMPARE(store.resultAt(1).value(), vec0[0]);
QCOMPARE(store.resultAt(2).value(), vec0[1]);
QCOMPARE(store.resultAt(3).value(), int1);
}
{
ResultStore<int> store;
store.addResult(-1, &int0);
store.addResults(-1, &vec0);
store.addResult(200, &int1);
QCOMPARE(store.resultAt(0).value(), int0);
QCOMPARE(store.resultAt(1).value(), vec0[0]);
QCOMPARE(store.resultAt(2).value(), vec0[1]);
QCOMPARE(store.resultAt(200).value(), int1);
}
{
ResultStore<int> store;
store.addResult(1, &int1);
store.addResult(0, &int0);
store.addResult(-1, &int2);
QCOMPARE(store.resultAt(0).value(), int0);
QCOMPARE(store.resultAt(1).value(), int1);
QCOMPARE(store.resultAt(2).value(), int2);
}
{
ResultStore<int> store;
QCOMPARE(store.contains(0), false);
QCOMPARE(store.contains(1), false);
QCOMPARE(store.contains(INT_MAX), false);
}
{
// Test filter mode, where "gaps" in the result array aren't allowed.
ResultStore<int> store;
store.setFilterMode(true);
store.addResult(0, &int0);
QCOMPARE(store.contains(0), true);
store.addResult(2, &int2); // add result at index 2
QCOMPARE(store.contains(2), false); // but 1 is missing, so this 2 won't be reported yet.
store.addResult(1, &int1);
QCOMPARE(store.contains(1), true);
QCOMPARE(store.contains(2), true); // 2 should be visible now.
store.addResult(4, &int0);
store.addResult(5, &int0);
store.addResult(7, &int0);
QCOMPARE(store.contains(4), false);
QCOMPARE(store.contains(5), false);
QCOMPARE(store.contains(7), false);
store.addResult(3, &int0); // adding 3 makes 4 and 5 visible
QCOMPARE(store.contains(4), true);
QCOMPARE(store.contains(5), true);
QCOMPARE(store.contains(7), false);
store.addResult(6, &int0); // adding 6 makes 7 visible
QCOMPARE(store.contains(6), true);
QCOMPARE(store.contains(7), true);
QCOMPARE(store.contains(8), false);
}
{
// test canceled results
ResultStore<int> store;
store.setFilterMode(true);
store.addResult(0, &int0);
QCOMPARE(store.contains(0), true);
store.addResult(2, &int0);
QCOMPARE(store.contains(2), false);
store.addCanceledResult(1); // report no result at 1
QCOMPARE(store.contains(0), true);
QCOMPARE(store.contains(1), true); // 2 gets renamed to 1
QCOMPARE(store.contains(2), false);
store.addResult(3, &int0);
QCOMPARE(store.contains(2), true); //3 gets renamed to 2
store.addResult(6, &int0);
store.addResult(7, &int0);
QCOMPARE(store.contains(3), false);
store.addCanceledResult(4);
store.addCanceledResult(5);
QCOMPARE(store.contains(3), true); //6 gets renamed to 3
QCOMPARE(store.contains(4), true); //7 gets renamed to 4
store.addResult(8, &int0);
QCOMPARE(store.contains(5), true); //8 gets renamed to 4
QCOMPARE(store.contains(6), false);
QCOMPARE(store.contains(7), false);
}
{
// test addResult return value
ResultStore<int> store;
store.setFilterMode(true);
store.addResult(0, &int0);
QCOMPARE(store.count(), 1); // result 0 becomes available
QCOMPARE(store.contains(0), true);
store.addResult(2, &int0);
QCOMPARE(store.count(), 1);
QCOMPARE(store.contains(2), false);
store.addCanceledResult(1);
QCOMPARE(store.count(), 2); // result 2 is renamed to 1 and becomes available
QCOMPARE(store.contains(0), true);
QCOMPARE(store.contains(1), true);
QCOMPARE(store.contains(2), false);
store.addResult(3, &int0);
QCOMPARE(store.count(), 3);
QCOMPARE(store.contains(2), true);
store.addResult(6, &int0);
QCOMPARE(store.count(), 3);
store.addResult(7, &int0);
QCOMPARE(store.count(), 3);
QCOMPARE(store.contains(3), false);
store.addCanceledResult(4);
store.addCanceledResult(5);
QCOMPARE(store.count(), 5); // 6 and 7 is renamed to 3 and 4 and becomes available
QCOMPARE(store.contains(3), true);
QCOMPARE(store.contains(4), true);
store.addResult(8, &int0);
QCOMPARE(store.contains(5), true);
QCOMPARE(store.count(), 6);
QCOMPARE(store.contains(6), false);
QCOMPARE(store.contains(7), false);
}
{
// test resultCount in non-filtered mode. It should always be possible
// to iterate through the results 0 to resultCount.
ResultStore<int> store;
store.addResult(0, &int0);
QCOMPARE(store.count(), 1);
store.addResult(2, &int0);
QCOMPARE(store.count(), 1);
store.addResult(1, &int0);
QCOMPARE(store.count(), 3);
}
{
ResultStore<int> store;
store.addResult(2, &int0);
QCOMPARE(store.count(), 0);
store.addResult(1, &int0);
QCOMPARE(store.count(), 0);
store.addResult(0, &int0);
QCOMPARE(store.count(), 3);
}
{
ResultStore<int> store;
store.addResults(2, &vec1);
QCOMPARE(store.count(), 0);
store.addResult(1, &int0);
QCOMPARE(store.count(), 0);
store.addResult(0, &int0);
QCOMPARE(store.count(), 4);
}
{
ResultStore<int> store;
store.addResults(2, &vec1);
QCOMPARE(store.count(), 0);
store.addResults(0, &vec0);
QCOMPARE(store.count(), 4);
}
{
ResultStore<int> store;
store.addResults(3, &vec1);
QCOMPARE(store.count(), 0);
store.addResults(0, &vec0);
QCOMPARE(store.count(), 2);
store.addResult(2, &int0);
QCOMPARE(store.count(), 5);
}
{
ResultStore<int> store;
store.setFilterMode(true);
store.addResults(3, &vec1);
QCOMPARE(store.count(), 0);
store.addResults(0, &vec0);
QCOMPARE(store.count(), 2);
store.addCanceledResult(2);
QCOMPARE(store.count(), 4);
}
{
ResultStore<int> store;
store.setFilterMode(true);
store.addResults(3, &vec1);
QCOMPARE(store.count(), 0);
store.addCanceledResults(0, 3);
QCOMPARE(store.count(), 2);
}
{
ResultStore<int> store;
store.setFilterMode(true);
store.addResults(3, &vec1);
QCOMPARE(store.count(), 0);
store.addCanceledResults(0, 3);
QCOMPARE(store.count(), 2); // results at 3 and 4 become available at index 0, 1
store.addResult(5, &int0);
QCOMPARE(store.count(), 3);// result 5 becomes available at index 2
}
{
ResultStore<int> store;
store.addResult(1, &int0);
store.addResult(3, &int0);
store.addResults(6, &vec0);
QCOMPARE(store.contains(0), false);
QCOMPARE(store.contains(1), true);
QCOMPARE(store.contains(2), false);
QCOMPARE(store.contains(3), true);
QCOMPARE(store.contains(4), false);
QCOMPARE(store.contains(5), false);
QCOMPARE(store.contains(6), true);
QCOMPARE(store.contains(7), true);
}
{
ResultStore<int> store;
store.setFilterMode(true);
store.addResult(1, &int0);
store.addResult(3, &int0);
store.addResults(6, &vec0);
QCOMPARE(store.contains(0), false);
QCOMPARE(store.contains(1), false);
QCOMPARE(store.contains(2), false);
QCOMPARE(store.contains(3), false);
QCOMPARE(store.contains(4), false);
QCOMPARE(store.contains(5), false);
QCOMPARE(store.contains(6), false);
QCOMPARE(store.contains(7), false);
store.addCanceledResult(0);
store.addCanceledResult(2);
store.addCanceledResults(4, 2);
QCOMPARE(store.contains(0), true);
QCOMPARE(store.contains(1), true);
QCOMPARE(store.contains(2), true);
QCOMPARE(store.contains(3), true);
QCOMPARE(store.contains(4), false);
QCOMPARE(store.contains(5), false);
QCOMPARE(store.contains(6), false);
QCOMPARE(store.contains(7), false);
}
{
ResultStore<int> store;
store.setFilterMode(true);
store.addCanceledResult(0);
QCOMPARE(store.contains(0), false);
store.addResult(1, &int0);
QCOMPARE(store.contains(0), true);
QCOMPARE(store.contains(1), false);
}
}
void tst_QFuture::future()
{
// default constructors
QFuture<int> intFuture;
intFuture.waitForFinished();
QFuture<QString> stringFuture;
stringFuture.waitForFinished();
QFuture<void> voidFuture;
voidFuture.waitForFinished();
QFuture<void> defaultVoidFuture;
defaultVoidFuture.waitForFinished();
// copy constructor
QFuture<int> intFuture2(intFuture);
QFuture<void> voidFuture2(defaultVoidFuture);
// assigmnent operator
intFuture2 = QFuture<int>();
voidFuture2 = QFuture<void>();
// state
QCOMPARE(intFuture2.isStarted(), true);
QCOMPARE(intFuture2.isFinished(), true);
}
class IntResult : public QFutureInterface<int>
{
public:
QFuture<int> run()
{
this->reportStarted();
QFuture<int> future = QFuture<int>(this);
int res = 10;
reportFinished(&res);
return future;
}
};
int value = 10;
class VoidResult : public QFutureInterfaceBase
{
public:
QFuture<void> run()
{
this->reportStarted();
QFuture<void> future = QFuture<void>(this);
reportFinished();
return future;
}
};
void tst_QFuture::futureInterface()
{
{
QFuture<void> future;
{
QFutureInterface<void> i;
i.reportStarted();
future = i.future();
i.reportFinished();
}
}
{
QFuture<int> future;
{
QFutureInterface<int> i;
i.reportStarted();
i.reportResult(10);
future = i.future();
i.reportFinished();
}
QCOMPARE(future.resultAt(0), 10);
}
{
QFuture<int> intFuture;
QCOMPARE(intFuture.isStarted(), true);
QCOMPARE(intFuture.isFinished(), true);
IntResult result;
result.reportStarted();
intFuture = result.future();
QCOMPARE(intFuture.isStarted(), true);
QCOMPARE(intFuture.isFinished(), false);
result.reportFinished(&value);
QCOMPARE(intFuture.isStarted(), true);
QCOMPARE(intFuture.isFinished(), true);
int e = intFuture.result();
QCOMPARE(intFuture.isStarted(), true);
QCOMPARE(intFuture.isFinished(), true);
QCOMPARE(intFuture.isCanceled(), false);
QCOMPARE(e, value);
intFuture.waitForFinished();
IntResult intAlgo;
intFuture = intAlgo.run();
QFuture<int> intFuture2(intFuture);
QCOMPARE(intFuture.result(), value);
QCOMPARE(intFuture2.result(), value);
intFuture.waitForFinished();
VoidResult a;
a.run().waitForFinished();
}
}
template <typename T>
void testRefCounting()
{
QFutureInterface<T> interface;
QCOMPARE(int(interface.d->refCount), 1);
{
interface.reportStarted();
QFuture<T> f = interface.future();
QCOMPARE(int(interface.d->refCount), 2);
QFuture<T> f2(f);
QCOMPARE(int(interface.d->refCount), 3);
QFuture<T> f3;
f3 = f2;
QCOMPARE(int(interface.d->refCount), 4);
interface.reportFinished(0);
QCOMPARE(int(interface.d->refCount), 4);
}
QCOMPARE(int(interface.d->refCount), 1);
}
void tst_QFuture::refcounting()
{
testRefCounting<int>();
}
void tst_QFuture::cancel()
{
{
QFuture<void> f;
QFutureInterface<void> result;
result.reportStarted();
f = result.future();
QVERIFY(f.isCanceled() == false);
result.reportCanceled();
QVERIFY(f.isCanceled());
result.reportFinished();
QVERIFY(f.isCanceled());
f.waitForFinished();
QVERIFY(f.isCanceled());
}
// Cancel from the QFuture side and test if the result
// interface detects it.
{
QFutureInterface<void> result;
QFuture<void> f;
QVERIFY(f.isStarted() == true);
result.reportStarted();
f = result.future();
QVERIFY(f.isStarted() == true);
QVERIFY(result.isCanceled() == false);
f.cancel();
QVERIFY(result.isCanceled());
result.reportFinished();
}
// Test that finished futures can be canceled.
{
QFutureInterface<void> result;
QFuture<void> f;
QVERIFY(f.isStarted() == true);
result.reportStarted();
f = result.future();
QVERIFY(f.isStarted() == true);
result.reportFinished();
f.cancel();
QVERIFY(result.isCanceled());
QVERIFY(f.isCanceled());
}
// Results reported after canceled is called should not be propagated.
{
QFutureInterface<int> futureInterface;
futureInterface.reportStarted();
QFuture<int> f = futureInterface.future();
int result = 0;
futureInterface.reportResult(&result);
result = 1;
futureInterface.reportResult(&result);
f.cancel();
result = 2;
futureInterface.reportResult(&result);
result = 3;
futureInterface.reportResult(&result);
futureInterface.reportFinished();
QCOMPARE(f.results(), QList<int>());
}
}
void tst_QFuture::statePropagation()
{
QFuture<void> f1;
QFuture<void> f2;
QCOMPARE(f1.isStarted(), true);
QFutureInterface<void> result;
result.reportStarted();
f1 = result.future();
f2 = f1;
QCOMPARE(f2.isStarted(), true);
result.reportCanceled();
QCOMPARE(f2.isStarted(), true);
QCOMPARE(f2.isCanceled(), true);
QFuture<void> f3 = f2;
QCOMPARE(f3.isStarted(), true);
QCOMPARE(f3.isCanceled(), true);
result.reportFinished();
QCOMPARE(f2.isStarted(), true);
QCOMPARE(f2.isCanceled(), true);
QCOMPARE(f3.isStarted(), true);
QCOMPARE(f3.isCanceled(), true);
}
/*
Tests that a QFuture can return multiple results.
*/
void tst_QFuture::multipleResults()
{
IntResult a;
a.reportStarted();
QFuture<int> f = a.future();
QFuture<int> copy = f;
int result;
result = 1;
a.reportResult(&result);
QCOMPARE(f.resultAt(0), 1);
result = 2;
a.reportResult(&result);
QCOMPARE(f.resultAt(1), 2);
result = 3;
a.reportResult(&result);
result = 4;
a.reportFinished(&result);
QCOMPARE(f.results(), QList<int>() << 1 << 2 << 3 << 4);
// test foreach
QList<int> fasit = QList<int>() << 1 << 2 << 3 << 4;
{
QList<int> results;
foreach(int result, f)
results.append(result);
QCOMPARE(results, fasit);
}
{
QList<int> results;
foreach(int result, copy)
results.append(result);
QCOMPARE(results, fasit);
}
}
/*
Test out-of-order result reporting using indexes
*/
void tst_QFuture::indexedResults()
{
{
QFutureInterface<QChar> Interface;
QFuture<QChar> f;
QVERIFY(f.isStarted() == true);
Interface.reportStarted();
f = Interface.future();
QVERIFY(f.isStarted() == true);
QChar result;
result = 'B';
Interface.reportResult(&result, 1);
QCOMPARE(f.resultAt(1), result);
result = 'A';
Interface.reportResult(&result, 0);
QCOMPARE(f.resultAt(0), result);
result = 'C';
Interface.reportResult(&result); // no index
QCOMPARE(f.resultAt(2), result);
Interface.reportFinished();
QCOMPARE(f.results(), QList<QChar>() << 'A' << 'B' << 'C');
}
{
// Test result reporting with a missing result in the middle
QFutureInterface<int> Interface;
Interface.reportStarted();
QFuture<int> f = Interface.future();
int result;
result = 0;
Interface.reportResult(&result, 0);
QVERIFY(f.isResultReadyAt(0));
QCOMPARE(f.resultAt(0), 0);
result = 3;
Interface.reportResult(&result, 3);
QVERIFY(f.isResultReadyAt(3));
QCOMPARE(f.resultAt(3), 3);
result = 2;
Interface.reportResult(&result, 2);
QVERIFY(f.isResultReadyAt(2));
QCOMPARE(f.resultAt(2), 2);
result = 4;
Interface.reportResult(&result); // no index
QVERIFY(f.isResultReadyAt(4));
QCOMPARE(f.resultAt(4), 4);
Interface.reportFinished();
QCOMPARE(f.results(), QList<int>() << 0 << 2 << 3 << 4);
}
}
void tst_QFuture::progress()
{
QFutureInterface<QChar> result;
QFuture<QChar> f;
QCOMPARE (f.progressValue(), 0);
result.reportStarted();
f = result.future();
QCOMPARE (f.progressValue(), 0);
result.setProgressValue(50);
QCOMPARE (f.progressValue(), 50);
result.reportFinished();
QCOMPARE (f.progressValue(), 50);
}
void tst_QFuture::progressText()
{
QFutureInterface<void> i;
i.reportStarted();
QFuture<void> f = i.future();
QCOMPARE(f.progressText(), QLatin1String(""));
i.setProgressValueAndText(1, QLatin1String("foo"));
QCOMPARE(f.progressText(), QLatin1String("foo"));
i.reportFinished();
}
/*
Test that results reported after finished are ignored.
*/
void tst_QFuture::resultsAfterFinished()
{
{
IntResult a;
a.reportStarted();
QFuture<int> f = a.future();
int result;
QCOMPARE(f.resultCount(), 0);
result = 1;
a.reportResult(&result);
QCOMPARE(f.resultAt(0), 1);
a.reportFinished();
QCOMPARE(f.resultAt(0), 1);
QCOMPARE(f.resultCount(), 1);
result = 2;
a.reportResult(&result);
QCOMPARE(f.resultCount(), 1);
}
// cancel it
{
IntResult a;
a.reportStarted();
QFuture<int> f = a.future();
int result;
QCOMPARE(f.resultCount(), 0);
result = 1;
a.reportResult(&result);
QCOMPARE(f.resultAt(0), 1);
QCOMPARE(f.resultCount(), 1);
a.reportCanceled();
QCOMPARE(f.resultAt(0), 1);
QCOMPARE(f.resultCount(), 1);
result = 2;
a.reportResult(&result);
a.reportFinished();
}
}
void tst_QFuture::resultsAsList()
{
IntResult a;
a.reportStarted();
QFuture<int> f = a.future();
int result;
result = 1;
a.reportResult(&result);
result = 2;
a.reportResult(&result);
a.reportFinished();
QList<int> results = f.results();
QCOMPARE(results, QList<int>() << 1 << 2);
}
/*
Test that QFuture<T> can be implicitly converted to T
*/
void tst_QFuture::implicitConversions()
{
QFutureInterface<QString> iface;
iface.reportStarted();
QFuture<QString> f(&iface);
const QString input("FooBar 2000");
iface.reportFinished(&input);
const QString result = f;
QCOMPARE(result, input);
QCOMPARE(QString(f), input);
QCOMPARE(static_cast<QString>(f), input);
}
void tst_QFuture::iterators()
{
{
QFutureInterface<int> e;
e.reportStarted();
QFuture<int> f = e.future();
int result;
result = 1;
e.reportResult(&result);
result = 2;
e.reportResult(&result);
result = 3;
e.reportResult(&result);
e.reportFinished();
QList<int> results;
QFutureIterator<int> i(f);
while (i.hasNext()) {
results.append(i.next());
}
QCOMPARE(results, f.results());
QFuture<int>::const_iterator i1 = f.begin(), i2 = i1 + 1;
QFuture<int>::const_iterator c1 = i1, c2 = c1 + 1;
QVERIFY(i1 == i1);
QVERIFY(i1 == c1);
QVERIFY(c1 == i1);
QVERIFY(c1 == c1);
QVERIFY(i2 == i2);
QVERIFY(i2 == c2);
QVERIFY(c2 == i2);
QVERIFY(c2 == c2);
QVERIFY(i1 != i2);
QVERIFY(i1 != c2);
QVERIFY(c1 != i2);
QVERIFY(c1 != c2);
QVERIFY(i2 != i1);
QVERIFY(i2 != c1);
QVERIFY(c2 != i1);
QVERIFY(c2 != c1);
int x1 = *i1;
Q_UNUSED(x1);
int x2 = *i2;
Q_UNUSED(x2);
int y1 = *c1;
Q_UNUSED(y1);
int y2 = *c2;
Q_UNUSED(y2);
}
{
QFutureInterface<QString> e;
e.reportStarted();
QFuture<QString> f = e.future();
e.reportResult(QString("one"));
e.reportResult(QString("two"));
e.reportResult(QString("three"));
e.reportFinished();
QList<QString> results;
QFutureIterator<QString> i(f);
while (i.hasNext()) {
results.append(i.next());
}
QCOMPARE(results, f.results());
QFuture<QString>::const_iterator i1 = f.begin(), i2 = i1 + 1;
QFuture<QString>::const_iterator c1 = i1, c2 = c1 + 1;
QVERIFY(i1 == i1);
QVERIFY(i1 == c1);
QVERIFY(c1 == i1);
QVERIFY(c1 == c1);
QVERIFY(i2 == i2);
QVERIFY(i2 == c2);
QVERIFY(c2 == i2);
QVERIFY(c2 == c2);
QVERIFY(i1 != i2);
QVERIFY(i1 != c2);
QVERIFY(c1 != i2);
QVERIFY(c1 != c2);
QVERIFY(i2 != i1);
QVERIFY(i2 != c1);
QVERIFY(c2 != i1);
QVERIFY(c2 != c1);
QString x1 = *i1;
QString x2 = *i2;
QString y1 = *c1;
QString y2 = *c2;
QCOMPARE(x1, y1);
QCOMPARE(x2, y2);
int i1Size = i1->size();
int i2Size = i2->size();
int c1Size = c1->size();
int c2Size = c2->size();
QCOMPARE(i1Size, c1Size);
QCOMPARE(i2Size, c2Size);
}
{
const int resultCount = 20;
QFutureInterface<int> e;
e.reportStarted();
QFuture<int> f = e.future();
for (int i = 0; i < resultCount; ++i) {
e.reportResult(i);
}
e.reportFinished();
{
QFutureIterator<int> it(f);
QFutureIterator<int> it2(it);
}
{
QFutureIterator<int> it(f);
for (int i = 0; i < resultCount - 1; ++i) {
QVERIFY(it.hasNext());
QCOMPARE(it.peekNext(), i);
QCOMPARE(it.next(), i);
}
QVERIFY(it.hasNext());
QCOMPARE(it.peekNext(), resultCount - 1);
QCOMPARE(it.next(), resultCount - 1);
QVERIFY(it.hasNext() == false);
}
{
QFutureIterator<int> it(f);
QVERIFY(it.hasNext());
it.toBack();
QVERIFY(it.hasNext() == false);
it.toFront();
QVERIFY(it.hasNext());
}
}
}
class SignalSlotObject : public QObject
{
Q_OBJECT
public:
SignalSlotObject()
: finishedCalled(false),
canceledCalled(false),
rangeBegin(0),
rangeEnd(0) { }
public slots:
void finished()
{
// qDebug() << "finished called";
finishedCalled = true;
}
void canceled()
{
// qDebug() << "canceled called";
canceledCalled = true;
}
void resultReady(int index)
{
// qDebug() << "result" << index << "ready";
results.insert(index);
}
void progressRange(int begin, int end)
{
// qDebug() << "progress range" << begin << end;
rangeBegin = begin;
rangeEnd = end;
}
void progress(int progress)
{
// qDebug() << "progress" << progress;
reportedProgress.insert(progress);
}
public:
bool finishedCalled;
bool canceledCalled;
QSet<int> results;
int rangeBegin;
int rangeEnd;
QSet<int> reportedProgress;
};
void tst_QFuture::pause()
{
QFutureInterface<void> Interface;
Interface.reportStarted();
QFuture<void> f = Interface.future();
QVERIFY(Interface.isPaused() == false);
f.pause();
QVERIFY(Interface.isPaused() == true);
f.resume();
QVERIFY(Interface.isPaused() == false);
f.togglePaused();
QVERIFY(Interface.isPaused() == true);
f.togglePaused();
QVERIFY(Interface.isPaused() == false);
Interface.reportFinished();
}
const int resultCount = 1000;
class ResultObject : public QObject
{
Q_OBJECT
public slots:
void resultReady(int)
{
}
public:
};
// Test that that the isPaused() on future result interface returns true
// if we report a lot of results that are not handled.
void tst_QFuture::throttling()
{
{
QFutureInterface<void> i;
i.reportStarted();
QFuture<void> f = i.future();
QVERIFY(i.isThrottled() == false);
i.setThrottled(true);
QVERIFY(i.isThrottled());
i.setThrottled(false);
QVERIFY(i.isThrottled() == false);
i.setThrottled(true);
QVERIFY(i.isThrottled());
i.reportFinished();
}
/*
QFutureInterface<int> *Interface = new QFutureInterface<int>();
Interface.reportStarted();
QFuture<int> f = QFuture<int>(Interface);
ResultObject object;
f.connectTo(ThrottledResultReadyAtSignal, &object, SLOT(resultReady(int)), Qt::DirectConnection);
for (int i = 0; i < 100; ++i)
Interface.reportResult(&i);
QVERIFY(Interface.isPaused() == true);
// read the results, this should resume the task.
for (int i = 0; i < 100; ++i)
f.throttledResult(i);
QVERIFY(Interface.isPaused() == false);
Interface.reportFinished();
*/
}
void tst_QFuture::voidConversions()
{
QFutureInterface<int> iface;
iface.reportStarted();
QFuture<int> intFuture(&iface);
int value = 10;
iface.reportFinished(&value);
QFuture<void> voidFuture(intFuture);
voidFuture = intFuture;
QVERIFY(voidFuture == intFuture);
}
#ifndef QT_NO_EXCEPTIONS
QFuture<void> createExceptionFuture()
{
QFutureInterface<void> i;
i.reportStarted();
QFuture<void> f = i.future();
Exception e;
i.reportException(e);
i.reportFinished();
return f;
}
QFuture<int> createExceptionResultFuture()
{
QFutureInterface<int> i;
i.reportStarted();
QFuture<int> f = i.future();
int r = 0;
i.reportResult(r);
Exception e;
i.reportException(e);
i.reportFinished();
return f;
}
class DerivedException : public Exception
{
public:
void raise() const { throw *this; }
Exception *clone() const { return new DerivedException(*this); }
};
QFuture<void> createDerivedExceptionFuture()
{
QFutureInterface<void> i;
i.reportStarted();
QFuture<void> f = i.future();
DerivedException e;
i.reportException(e);
i.reportFinished();
return f;
}
void tst_QFuture::exceptions()
{
// test throwing from waitForFinished
{
QFuture<void> f = createExceptionFuture();
bool caught = false;
try {
f.waitForFinished();
} catch (Exception &) {
caught = true;
}
QVERIFY(caught);
}
// test result()
{
QFuture<int> f = createExceptionResultFuture();
bool caught = false;
try {
f.result();
} catch (Exception &) {
caught = true;
}
QVERIFY(caught);
}
// test result() and destroy
{
bool caught = false;
try {
createExceptionResultFuture().result();
} catch (Exception &) {
caught = true;
}
QVERIFY(caught);
}
// test results()
{
QFuture<int> f = createExceptionResultFuture();
bool caught = false;
try {
f.results();
} catch (Exception &) {
caught = true;
}
QVERIFY(caught);
}
// test foreach
{
QFuture<int> f = createExceptionResultFuture();
bool caught = false;
try {
foreach (int e, f.results()) {
Q_UNUSED(e);
QFAIL("did not get exception");
}
} catch (Exception &) {
caught = true;
}
QVERIFY(caught);
}
// catch derived exceptions
{
bool caught = false;
try {
createDerivedExceptionFuture().waitForFinished();
} catch (Exception &) {
caught = true;
}
QVERIFY(caught);
}
{
bool caught = false;
try {
createDerivedExceptionFuture().waitForFinished();
} catch (DerivedException &) {
caught = true;
}
QVERIFY(caught);
}
}
void tst_QFuture::exceptions_QTBUG18149()
{
class MyClass
{
public:
~MyClass()
{
QFuture<void> f = createExceptionFuture();
bool caught = false;
try {
f.waitForFinished();
} catch (Exception &) {
caught = true;
}
QVERIFY(caught);
}
};
try {
MyClass m;
throw 0;
} catch (int) {}
}
#endif // QT_NO_EXCEPTIONS
#include "tst_qfuture.moc"
#else
QTEST_NOOP_MAIN
#endif