From 0547598a28c3c1dd5c5f4c3ec9888b0de499199b Mon Sep 17 00:00:00 2001 From: Holger Ihrig Date: Wed, 24 Aug 2011 10:51:34 +0200 Subject: Moving relevant tests to corelib/concurrent Adding tests for QFutureSynchronizer and QtConcurrentResultStore Added minor things in QFutureSynchronizer and QtConcurrentResultStore and removed tests for destruction Task-number: QTBUG-21066 Change-Id: I9f088b89463340f339c914bcb37fb2f9d3b62057 Reviewed-on: http://codereview.qt.nokia.com/3477 Reviewed-by: Qt Sanity Bot Reviewed-by: Rohan McGovern Reviewed-by: Jason McDonald --- tests/auto/corelib/concurrent/concurrent.pro | 19 + tests/auto/corelib/concurrent/qfuture/.gitignore | 1 + tests/auto/corelib/concurrent/qfuture/qfuture.pro | 5 + .../corelib/concurrent/qfuture/tst_qfuture.cpp | 1469 ++++++++++++ .../auto/corelib/concurrent/qfuture/versioncheck.h | 49 + .../qfuturesynchronizer/qfuturesynchronizer.pro | 5 + .../tst_qfuturesynchronizer.cpp | 158 ++ .../corelib/concurrent/qfuturewatcher/.gitignore | 1 + .../concurrent/qfuturewatcher/qfuturewatcher.pro | 4 + .../qfuturewatcher/tst_qfuturewatcher.cpp | 930 ++++++++ .../concurrent/qtconcurrentfilter/.gitignore | 1 + .../qtconcurrentfilter/qtconcurrentfilter.pro | 6 + .../qtconcurrentfilter/tst_qtconcurrentfilter.cpp | 1546 ++++++++++++ .../qtconcurrentiteratekernel/.gitignore | 1 + .../qtconcurrentiteratekernel.pro | 5 + .../tst_qtconcurrentiteratekernel.cpp | 360 +++ .../corelib/concurrent/qtconcurrentmap/.gitignore | 1 + .../corelib/concurrent/qtconcurrentmap/functions.h | 130 ++ .../concurrent/qtconcurrentmap/qtconcurrentmap.pro | 6 + .../qtconcurrentmap/tst_qtconcurrentmap.cpp | 2448 ++++++++++++++++++++ .../qtconcurrentresultstore.pro | 5 + .../tst_qtconcurrentresultstore.cpp | 491 ++++ .../corelib/concurrent/qtconcurrentrun/.gitignore | 1 + .../concurrent/qtconcurrentrun/qtconcurrentrun.pro | 5 + .../qtconcurrentrun/tst_qtconcurrentrun.cpp | 518 +++++ .../concurrent/qtconcurrentthreadengine/.gitignore | 1 + .../qtconcurrentthreadengine.pro | 5 + .../tst_qtconcurrentthreadengine.cpp | 536 +++++ .../auto/corelib/concurrent/qthreadpool/.gitignore | 1 + .../corelib/concurrent/qthreadpool/qthreadpool.pro | 4 + .../concurrent/qthreadpool/tst_qthreadpool.cpp | 870 +++++++ 31 files changed, 9582 insertions(+) create mode 100644 tests/auto/corelib/concurrent/concurrent.pro create mode 100644 tests/auto/corelib/concurrent/qfuture/.gitignore create mode 100644 tests/auto/corelib/concurrent/qfuture/qfuture.pro create mode 100644 tests/auto/corelib/concurrent/qfuture/tst_qfuture.cpp create mode 100644 tests/auto/corelib/concurrent/qfuture/versioncheck.h create mode 100644 tests/auto/corelib/concurrent/qfuturesynchronizer/qfuturesynchronizer.pro create mode 100644 tests/auto/corelib/concurrent/qfuturesynchronizer/tst_qfuturesynchronizer.cpp create mode 100644 tests/auto/corelib/concurrent/qfuturewatcher/.gitignore create mode 100644 tests/auto/corelib/concurrent/qfuturewatcher/qfuturewatcher.pro create mode 100644 tests/auto/corelib/concurrent/qfuturewatcher/tst_qfuturewatcher.cpp create mode 100644 tests/auto/corelib/concurrent/qtconcurrentfilter/.gitignore create mode 100644 tests/auto/corelib/concurrent/qtconcurrentfilter/qtconcurrentfilter.pro create mode 100644 tests/auto/corelib/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp create mode 100644 tests/auto/corelib/concurrent/qtconcurrentiteratekernel/.gitignore create mode 100644 tests/auto/corelib/concurrent/qtconcurrentiteratekernel/qtconcurrentiteratekernel.pro create mode 100644 tests/auto/corelib/concurrent/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp create mode 100644 tests/auto/corelib/concurrent/qtconcurrentmap/.gitignore create mode 100644 tests/auto/corelib/concurrent/qtconcurrentmap/functions.h create mode 100644 tests/auto/corelib/concurrent/qtconcurrentmap/qtconcurrentmap.pro create mode 100644 tests/auto/corelib/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp create mode 100644 tests/auto/corelib/concurrent/qtconcurrentresultstore/qtconcurrentresultstore.pro create mode 100644 tests/auto/corelib/concurrent/qtconcurrentresultstore/tst_qtconcurrentresultstore.cpp create mode 100644 tests/auto/corelib/concurrent/qtconcurrentrun/.gitignore create mode 100644 tests/auto/corelib/concurrent/qtconcurrentrun/qtconcurrentrun.pro create mode 100644 tests/auto/corelib/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp create mode 100644 tests/auto/corelib/concurrent/qtconcurrentthreadengine/.gitignore create mode 100644 tests/auto/corelib/concurrent/qtconcurrentthreadengine/qtconcurrentthreadengine.pro create mode 100644 tests/auto/corelib/concurrent/qtconcurrentthreadengine/tst_qtconcurrentthreadengine.cpp create mode 100644 tests/auto/corelib/concurrent/qthreadpool/.gitignore create mode 100644 tests/auto/corelib/concurrent/qthreadpool/qthreadpool.pro create mode 100644 tests/auto/corelib/concurrent/qthreadpool/tst_qthreadpool.cpp (limited to 'tests/auto/corelib/concurrent') diff --git a/tests/auto/corelib/concurrent/concurrent.pro b/tests/auto/corelib/concurrent/concurrent.pro new file mode 100644 index 0000000000..6d7850b18f --- /dev/null +++ b/tests/auto/corelib/concurrent/concurrent.pro @@ -0,0 +1,19 @@ +TEMPLATE=subdirs +SUBDIRS=\ + qfuture \ + qfuturesynchronizer \ + qfuturewatcher \ + qtconcurrentfilter \ + qtconcurrentiteratekernel \ + qtconcurrentmap \ + qtconcurrentresultstore \ + qtconcurrentrun \ + qtconcurrentthreadengine \ + qthreadpool + +symbian:SUBDIRS -= \ + qtconcurrentfilter \ + qtconcurrentiteratekernel \ + qtconcurrentmap \ + qtconcurrentrun \ + qtconcurrentthreadengine \ diff --git a/tests/auto/corelib/concurrent/qfuture/.gitignore b/tests/auto/corelib/concurrent/qfuture/.gitignore new file mode 100644 index 0000000000..77c055c874 --- /dev/null +++ b/tests/auto/corelib/concurrent/qfuture/.gitignore @@ -0,0 +1 @@ +tst_qfuture diff --git a/tests/auto/corelib/concurrent/qfuture/qfuture.pro b/tests/auto/corelib/concurrent/qfuture/qfuture.pro new file mode 100644 index 0000000000..0e74f47678 --- /dev/null +++ b/tests/auto/corelib/concurrent/qfuture/qfuture.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +DEFINES += QT_STRICT_ITERATORS +SOURCES += tst_qfuture.cpp +QT = core core-private +CONFIG += parallel_test diff --git a/tests/auto/corelib/concurrent/qfuture/tst_qfuture.cpp b/tests/auto/corelib/concurrent/qfuture/tst_qfuture.cpp new file mode 100644 index 0000000000..2178489bd9 --- /dev/null +++ b/tests/auto/corelib/concurrent/qfuture/tst_qfuture.cpp @@ -0,0 +1,1469 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include + +#define QFUTURE_TEST + +#include +#include +#include "versioncheck.h" +#include +#include +#include + +#ifndef QT_NO_CONCURRENT_TEST +#include + +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 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 vec0 = QVector() << 2 << 3; + QVector vec1 = QVector() << 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 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 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 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 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 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 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 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 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 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 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 store; + store.addResults(2, &vec1); + QCOMPARE(store.count(), 0); + + store.addResults(0, &vec0); + QCOMPARE(store.count(), 4); + } + { + ResultStore 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 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 store; + store.setFilterMode(true); + store.addResults(3, &vec1); + QCOMPARE(store.count(), 0); + + store.addCanceledResults(0, 3); + QCOMPARE(store.count(), 2); + } + + { + ResultStore 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 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 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 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 intFuture; + intFuture.waitForFinished(); + QFuture stringFuture; + stringFuture.waitForFinished(); + QFuture voidFuture; + voidFuture.waitForFinished(); + QFuture defaultVoidFuture; + defaultVoidFuture.waitForFinished(); + + // copy constructor + QFuture intFuture2(intFuture); + QFuture voidFuture2(defaultVoidFuture); + + // assigmnent operator + intFuture2 = QFuture(); + voidFuture2 = QFuture(); + + // state + QCOMPARE(intFuture2.isStarted(), true); + QCOMPARE(intFuture2.isFinished(), true); +} + +class IntResult : public QFutureInterface +{ +public: + QFuture run() + { + this->reportStarted(); + QFuture future = QFuture(this); + + int res = 10; + reportFinished(&res); + return future; + } +}; + +int value = 10; + +class VoidResult : public QFutureInterfaceBase +{ +public: + QFuture run() + { + this->reportStarted(); + QFuture future = QFuture(this); + reportFinished(); + return future; + } +}; + +void tst_QFuture::futureInterface() +{ + { + QFuture future; + { + QFutureInterface i; + i.reportStarted(); + future = i.future(); + i.reportFinished(); + } + } + { + QFuture future; + { + QFutureInterface i; + i.reportStarted(); + i.reportResult(10); + future = i.future(); + i.reportFinished(); + } + QCOMPARE(future.resultAt(0), 10); + } + + { + QFuture 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 intFuture2(intFuture); + QCOMPARE(intFuture.result(), value); + QCOMPARE(intFuture2.result(), value); + intFuture.waitForFinished(); + + VoidResult a; + a.run().waitForFinished(); + } +} + +template +void testRefCounting() +{ + QFutureInterface interface; + QCOMPARE(int(interface.d->refCount), 1); + + { + interface.reportStarted(); + + QFuture f = interface.future(); + QCOMPARE(int(interface.d->refCount), 2); + + QFuture f2(f); + QCOMPARE(int(interface.d->refCount), 3); + + QFuture 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(); +} + +void tst_QFuture::cancel() +{ + { + QFuture f; + QFutureInterface 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 result; + + QFuture 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 result; + + QFuture 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 futureInterface; + futureInterface.reportStarted(); + QFuture 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()); + } +} + +void tst_QFuture::statePropagation() +{ + QFuture f1; + QFuture f2; + + QCOMPARE(f1.isStarted(), true); + + QFutureInterface result; + result.reportStarted(); + f1 = result.future(); + + f2 = f1; + + QCOMPARE(f2.isStarted(), true); + + result.reportCanceled(); + + QCOMPARE(f2.isStarted(), true); + QCOMPARE(f2.isCanceled(), true); + + QFuture 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 f = a.future(); + + QFuture 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() << 1 << 2 << 3 << 4); + + // test foreach + QList fasit = QList() << 1 << 2 << 3 << 4; + { + QList results; + foreach(int result, f) + results.append(result); + QCOMPARE(results, fasit); + } + { + QList results; + foreach(int result, copy) + results.append(result); + QCOMPARE(results, fasit); + } +} + +/* + Test out-of-order result reporting using indexes +*/ +void tst_QFuture::indexedResults() +{ + { + QFutureInterface Interface; + QFuture 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() << 'A' << 'B' << 'C'); + } + + { + // Test result reporting with a missing result in the middle + QFutureInterface Interface; + Interface.reportStarted(); + QFuture 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() << 0 << 2 << 3 << 4); + } +} + +void tst_QFuture::progress() +{ + QFutureInterface result; + QFuture 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 i; + i.reportStarted(); + QFuture 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 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 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 f = a.future(); + + int result; + result = 1; + a.reportResult(&result); + result = 2; + a.reportResult(&result); + + a.reportFinished(); + + QList results = f.results(); + QCOMPARE(results, QList() << 1 << 2); +} + +/* + Test that QFuture can be implicitly converted to T +*/ +void tst_QFuture::implicitConversions() +{ + QFutureInterface iface; + iface.reportStarted(); + + QFuture f(&iface); + + const QString input("FooBar 2000"); + iface.reportFinished(&input); + + const QString result = f; + QCOMPARE(result, input); + QCOMPARE(QString(f), input); + QCOMPARE(static_cast(f), input); +} + +void tst_QFuture::iterators() +{ + { + QFutureInterface e; + e.reportStarted(); + QFuture f = e.future(); + + int result; + result = 1; + e.reportResult(&result); + result = 2; + e.reportResult(&result); + result = 3; + e.reportResult(&result); + e.reportFinished(); + + QList results; + QFutureIterator i(f); + while (i.hasNext()) { + results.append(i.next()); + } + + QCOMPARE(results, f.results()); + + QFuture::const_iterator i1 = f.begin(), i2 = i1 + 1; + QFuture::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 e; + e.reportStarted(); + QFuture f = e.future(); + + e.reportResult(QString("one")); + e.reportResult(QString("two")); + e.reportResult(QString("three")); + e.reportFinished(); + + QList results; + QFutureIterator i(f); + while (i.hasNext()) { + results.append(i.next()); + } + + QCOMPARE(results, f.results()); + + QFuture::const_iterator i1 = f.begin(), i2 = i1 + 1; + QFuture::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 e; + e.reportStarted(); + QFuture f = e.future(); + + for (int i = 0; i < resultCount; ++i) { + e.reportResult(i); + } + + e.reportFinished(); + + { + QFutureIterator it(f); + QFutureIterator it2(it); + } + + { + QFutureIterator 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 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 results; + int rangeBegin; + int rangeEnd; + QSet reportedProgress; +}; + +void tst_QFuture::pause() +{ + QFutureInterface Interface; + + Interface.reportStarted(); + QFuture 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 i; + + i.reportStarted(); + QFuture 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 *Interface = new QFutureInterface(); + Interface.reportStarted(); + QFuture f = QFuture(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 iface; + iface.reportStarted(); + + QFuture intFuture(&iface); + + int value = 10; + iface.reportFinished(&value); + + QFuture voidFuture(intFuture); + voidFuture = intFuture; + + QVERIFY(voidFuture == intFuture); +} + + +#ifndef QT_NO_EXCEPTIONS + +QFuture createExceptionFuture() +{ + QFutureInterface i; + i.reportStarted(); + QFuture f = i.future(); + + Exception e; + i.reportException(e); + i.reportFinished(); + return f; +} + +QFuture createExceptionResultFuture() +{ + QFutureInterface i; + i.reportStarted(); + QFuture 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 createDerivedExceptionFuture() +{ + QFutureInterface i; + i.reportStarted(); + QFuture f = i.future(); + + DerivedException e; + i.reportException(e); + i.reportFinished(); + return f; +} + +void tst_QFuture::exceptions() +{ + +// test throwing from waitForFinished +{ + QFuture f = createExceptionFuture(); + bool caught = false; + try { + f.waitForFinished(); + } catch (Exception &) { + caught = true; + } + QVERIFY(caught); +} + +// test result() +{ + QFuture 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 f = createExceptionResultFuture(); + bool caught = false; + try { + f.results(); + } catch (Exception &) { + caught = true; + } + QVERIFY(caught); +} + +// test foreach +{ + QFuture 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 f = createExceptionFuture(); + bool caught = false; + try { + f.waitForFinished(); + } catch (Exception &) { + caught = true; + } + QVERIFY(caught); + } + }; + + try { + MyClass m; + Q_UNUSED(m); + throw 0; + } catch (int) {} + +} + + +#endif // QT_NO_EXCEPTIONS + +#include "tst_qfuture.moc" + +#else +QTEST_NOOP_MAIN +#endif diff --git a/tests/auto/corelib/concurrent/qfuture/versioncheck.h b/tests/auto/corelib/concurrent/qfuture/versioncheck.h new file mode 100644 index 0000000000..9e4d0c6eeb --- /dev/null +++ b/tests/auto/corelib/concurrent/qfuture/versioncheck.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include + +#ifdef QT_NO_CONCURRENT +#define QT_NO_CONCURRENT_TEST +#endif + +#if defined(Q_CC_MSVC) && _MSC_VER < 1400 +#define QT_NO_CONCURRENT_TEST +#endif diff --git a/tests/auto/corelib/concurrent/qfuturesynchronizer/qfuturesynchronizer.pro b/tests/auto/corelib/concurrent/qfuturesynchronizer/qfuturesynchronizer.pro new file mode 100644 index 0000000000..11012cce24 --- /dev/null +++ b/tests/auto/corelib/concurrent/qfuturesynchronizer/qfuturesynchronizer.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +QT = core +SOURCES += tst_qfuturesynchronizer.cpp \ + +CONFIG += parallel_test diff --git a/tests/auto/corelib/concurrent/qfuturesynchronizer/tst_qfuturesynchronizer.cpp b/tests/auto/corelib/concurrent/qfuturesynchronizer/tst_qfuturesynchronizer.cpp new file mode 100644 index 0000000000..5aced3f8c1 --- /dev/null +++ b/tests/auto/corelib/concurrent/qfuturesynchronizer/tst_qfuturesynchronizer.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include +#include + +class tst_QFutureSynchronizer : public QObject +{ + Q_OBJECT + + +private Q_SLOTS: + void construction(); + void addFuture(); + void cancelOnWait(); + void clearFutures(); + void futures(); + void setFuture(); + void waitForFinished(); +}; + + +void tst_QFutureSynchronizer::construction() +{ + + QFuture future; + QFutureSynchronizer synchronizer; + QFutureSynchronizer synchronizerWithFuture(future); + + QCOMPARE(synchronizer.futures().size(), 0); + QCOMPARE(synchronizerWithFuture.futures().size(), 1); +} + +void tst_QFutureSynchronizer::addFuture() +{ + QFutureSynchronizer synchronizer; + + synchronizer.addFuture(QFuture()); + QFuture future; + synchronizer.addFuture(future); + synchronizer.addFuture(future); + + QCOMPARE(synchronizer.futures().size(), 3); +} + +void tst_QFutureSynchronizer::cancelOnWait() +{ + QFutureSynchronizer synchronizer; + QVERIFY(!synchronizer.cancelOnWait()); + synchronizer.setCancelOnWait(true); + QVERIFY(synchronizer.cancelOnWait()); + synchronizer.setCancelOnWait(false); + QVERIFY(!synchronizer.cancelOnWait()); + synchronizer.setCancelOnWait(true); + QVERIFY(synchronizer.cancelOnWait()); +} + +void tst_QFutureSynchronizer::clearFutures() +{ + QFutureSynchronizer synchronizer; + synchronizer.clearFutures(); + QVERIFY(synchronizer.futures().isEmpty()); + + synchronizer.addFuture(QFuture()); + QFuture future; + synchronizer.addFuture(future); + synchronizer.addFuture(future); + synchronizer.clearFutures(); + QVERIFY(synchronizer.futures().isEmpty()); +} + +void tst_QFutureSynchronizer::futures() +{ + QFutureSynchronizer synchronizer; + + QList > futures; + for (int i=0; i<100; i++) { + QFuture future; + futures.append(future); + synchronizer.addFuture(future); + } + + QCOMPARE(futures, synchronizer.futures()); +} + +void tst_QFutureSynchronizer::setFuture() +{ + QFutureSynchronizer synchronizer; + + for (int i=0; i<100; i++) { + synchronizer.addFuture(QFuture()); + } + QCOMPARE(synchronizer.futures().size(), 100); + + QFuture future; + synchronizer.setFuture(future); + QCOMPARE(synchronizer.futures().size(), 1); + QCOMPARE(synchronizer.futures().first(), future); +} + +void tst_QFutureSynchronizer::waitForFinished() +{ + QFutureSynchronizer synchronizer; + + for (int i=0; i<100; i++) { + synchronizer.addFuture(QFuture()); + } + synchronizer.waitForFinished(); + const QList > futures = synchronizer.futures(); + + for (int i=0; i<100; i++) { + QVERIFY(futures.at(i).isFinished()); + } +} + +QTEST_MAIN(tst_QFutureSynchronizer) + +#include "tst_qfuturesynchronizer.moc" diff --git a/tests/auto/corelib/concurrent/qfuturewatcher/.gitignore b/tests/auto/corelib/concurrent/qfuturewatcher/.gitignore new file mode 100644 index 0000000000..1d778431c5 --- /dev/null +++ b/tests/auto/corelib/concurrent/qfuturewatcher/.gitignore @@ -0,0 +1 @@ +tst_qfuturewatcher diff --git a/tests/auto/corelib/concurrent/qfuturewatcher/qfuturewatcher.pro b/tests/auto/corelib/concurrent/qfuturewatcher/qfuturewatcher.pro new file mode 100644 index 0000000000..9de37d014f --- /dev/null +++ b/tests/auto/corelib/concurrent/qfuturewatcher/qfuturewatcher.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qfuturewatcher.cpp +QT = core core-private +CONFIG += parallel_test diff --git a/tests/auto/corelib/concurrent/qfuturewatcher/tst_qfuturewatcher.cpp b/tests/auto/corelib/concurrent/qfuturewatcher/tst_qfuturewatcher.cpp new file mode 100644 index 0000000000..d8fa2230f3 --- /dev/null +++ b/tests/auto/corelib/concurrent/qfuturewatcher/tst_qfuturewatcher.cpp @@ -0,0 +1,930 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include + +#include +#include "../qfuture/versioncheck.h" +#include +#include +#include +#include "../../../../shared/util.h" + +#ifndef QT_NO_CONCURRENT_TEST +#include + +using namespace QtConcurrent; + +#include + +//#define PRINT + +class tst_QFutureWatcher: public QObject +{ + Q_OBJECT +private slots: + void startFinish(); + void progressValueChanged(); + void canceled(); + void resultAt(); + void resultReadyAt(); + void futureSignals(); + void watchFinishedFuture(); + void watchCanceledFuture(); + void disconnectRunningFuture(); + void toMuchProgress(); + void progressText(); + void sharedFutureInterface(); + void changeFuture(); + void cancelEvents(); + void pauseEvents(); + void finishedState(); + void throttling(); + void incrementalMapResults(); + void incrementalFilterResults(); + void qfutureSynchornizer(); + void warnRace(); +}; + +QTEST_MAIN(tst_QFutureWatcher) + +void sleeper() +{ + QTest::qSleep(100); +} + +void tst_QFutureWatcher::startFinish() +{ + QFutureWatcher futureWatcher; + + QSignalSpy started(&futureWatcher, SIGNAL(started())); + QSignalSpy finished(&futureWatcher, SIGNAL(finished())); + + futureWatcher.setFuture(QtConcurrent::run(sleeper)); + QTest::qWait(10); // spin the event loop to deliver queued signals. + QCOMPARE(started.count(), 1); + QCOMPARE(finished.count(), 0); + futureWatcher.future().waitForFinished(); + QTest::qWait(10); + QCOMPARE(started.count(), 1); + QCOMPARE(finished.count(), 1); +} + +void mapSleeper(int &) +{ + QTest::qSleep(100); +} + +QSet progressValues; +QSet progressTexts; +QMutex mutex; +class ProgressObject : public QObject +{ +Q_OBJECT +public slots: + void printProgress(int); + void printText(const QString &text); + void registerProgress(int); + void registerText(const QString &text); +}; + +void ProgressObject::printProgress(int progress) +{ + qDebug() << "thread" << QThread::currentThread() << "reports progress" << progress; +} + +void ProgressObject::printText(const QString &text) +{ + qDebug() << "thread" << QThread::currentThread() << "reports progress text" << text; +} + +void ProgressObject::registerProgress(int progress) +{ + QTest::qSleep(1); + progressValues.insert(progress); +} + +void ProgressObject::registerText(const QString &text) +{ + QTest::qSleep(1); + progressTexts.insert(text); +} + + +QList createList(int listSize) +{ + QList list; + for (int i = 0; i < listSize; ++i) { + list.append(i); + } + return list; +} + +void tst_QFutureWatcher::progressValueChanged() +{ +#ifdef PRINT + qDebug() << "main thread" << QThread::currentThread(); +#endif + + progressValues.clear(); + const int listSize = 20; + QList list = createList(listSize); + + QFutureWatcher futureWatcher; + ProgressObject progressObject; + QObject::connect(&futureWatcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); +#ifdef PRINT + QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &progressObject, SLOT(printProgress(int)), Qt::DirectConnection ); +#endif + QObject::connect(&futureWatcher, SIGNAL(progressValueChanged(int)), &progressObject, SLOT(registerProgress(int))); + + futureWatcher.setFuture(QtConcurrent::map(list, mapSleeper)); + + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + futureWatcher.disconnect(); + QVERIFY(progressValues.contains(0)); + QVERIFY(progressValues.contains(listSize)); +} + +class CancelObject : public QObject +{ +Q_OBJECT +public: + bool wasCanceled; + CancelObject() : wasCanceled(false) {}; +public slots: + void cancel(); +}; + +void CancelObject::cancel() +{ +#ifdef PRINT + qDebug() << "thread" << QThread::currentThread() << "reports canceled"; +#endif + wasCanceled = true; +} + +void tst_QFutureWatcher::canceled() +{ + const int listSize = 20; + QList list = createList(listSize); + + QFutureWatcher futureWatcher; + QFuture future; + CancelObject cancelObject; + + QObject::connect(&futureWatcher, SIGNAL(canceled()), &cancelObject, SLOT(cancel())); + QObject::connect(&futureWatcher, SIGNAL(canceled()), + &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); + + future = QtConcurrent::map(list, mapSleeper); + futureWatcher.setFuture(future); + futureWatcher.cancel(); + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QVERIFY(future.isCanceled()); + QVERIFY(cancelObject.wasCanceled); + futureWatcher.disconnect(); + future.waitForFinished(); +} + +class IntTask : public RunFunctionTask +{ +public: + void runFunctor() + { + result = 10; + } +}; + +void tst_QFutureWatcher::resultAt() +{ + QFutureWatcher futureWatcher; + futureWatcher.setFuture((new IntTask())->start()); + futureWatcher.waitForFinished(); + QCOMPARE(futureWatcher.result(), 10); + QCOMPARE(futureWatcher.resultAt(0), 10); +} + +void tst_QFutureWatcher::resultReadyAt() +{ + QFutureWatcher futureWatcher; + QObject::connect(&futureWatcher, SIGNAL(resultReadyAt(int)), &QTestEventLoop::instance(), SLOT(exitLoop()), Qt::QueuedConnection); + + QFuture future = (new IntTask())->start(); + futureWatcher.setFuture(future); + + QTestEventLoop::instance().enterLoop(1); + QVERIFY(!QTestEventLoop::instance().timeout()); + + // Setting the future again should give us another signal. + // (this is to prevent the race where the task associated + // with the future finishes before setFuture is called.) + futureWatcher.setFuture(QFuture()); + futureWatcher.setFuture(future); + + QTestEventLoop::instance().enterLoop(1); + QVERIFY(!QTestEventLoop::instance().timeout()); +} + +class SignalSlotObject : public QObject +{ +Q_OBJECT + +signals: + void cancel(); + +public slots: + void started() + { + qDebug() << "started called"; + } + + void finished() + { + qDebug() << "finished called"; + } + + void canceled() + { + qDebug() << "canceled called"; + } + +#ifdef PRINT + void resultReadyAt(int index) + { + qDebug() << "result" << index << "ready"; + } +#else + void resultReadyAt(int) { } +#endif + void progressValueChanged(int progress) + { + qDebug() << "progress" << progress; + } + + void progressRangeChanged(int min, int max) + { + qDebug() << "progress range" << min << max; + } + +}; + +void tst_QFutureWatcher::futureSignals() +{ + { + QFutureInterface a; + QFutureWatcher f; + + SignalSlotObject object; +#ifdef PRINT + connect(&f, SIGNAL(finished()), &object, SLOT(finished())); + connect(&f, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int))); +#endif + // must connect to resultReadyAt so that the watcher can detect the connection + // (QSignalSpy does not trigger it.) + connect(&f, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int))); + a.reportStarted(); + f.setFuture(a.future()); + + QSignalSpy progressSpy(&f, SIGNAL(progressValueChanged(int))); + const int progress = 1; + a.setProgressValue(progress); + QTest::qWait(10); + QCOMPARE(progressSpy.count(), 2); + QCOMPARE(progressSpy.takeFirst().at(0).toInt(), 0); + QCOMPARE(progressSpy.takeFirst().at(0).toInt(), 1); + + QSignalSpy finishedSpy(&f, SIGNAL(finished())); + QSignalSpy resultReadySpy(&f, SIGNAL(resultReadyAt(int))); + + const int result = 10; + a.reportResult(&result); + QTest::qWait(10); + QCOMPARE(resultReadySpy.count(), 1); + a.reportFinished(&result); + QTest::qWait(10); + + QCOMPARE(resultReadySpy.count(), 2); + QCOMPARE(resultReadySpy.takeFirst().at(0).toInt(), 0); // check the index + QCOMPARE(resultReadySpy.takeFirst().at(0).toInt(), 1); + + QCOMPARE(finishedSpy.count(), 1); + } +} + +void tst_QFutureWatcher::watchFinishedFuture() +{ + QFutureInterface iface; + iface.reportStarted(); + + QFuture f = iface.future(); + + int value = 100; + iface.reportFinished(&value); + + QFutureWatcher watcher; + + SignalSlotObject object; +#ifdef PRINT + connect(&watcher, SIGNAL(started()), &object, SLOT(started())); + connect(&watcher, SIGNAL(canceled()), &object, SLOT(canceled())); + connect(&watcher, SIGNAL(finished()), &object, SLOT(finished())); + connect(&watcher, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int))); + connect(&watcher, SIGNAL(progressRangeChanged(int, int)), &object, SLOT(progressRangeChanged(int, int))); +#endif + connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int))); + + QSignalSpy startedSpy(&watcher, SIGNAL(started())); + QSignalSpy finishedSpy(&watcher, SIGNAL(finished())); + QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int))); + QSignalSpy canceledSpy(&watcher, SIGNAL(canceled())); + + watcher.setFuture(f); + QTest::qWait(10); + + QCOMPARE(startedSpy.count(), 1); + QCOMPARE(finishedSpy.count(), 1); + QCOMPARE(resultReadySpy.count(), 1); + QCOMPARE(canceledSpy.count(), 0); +} + +void tst_QFutureWatcher::watchCanceledFuture() +{ + QFuture f; + QFutureWatcher watcher; + + SignalSlotObject object; +#ifdef PRINT + connect(&watcher, SIGNAL(started()), &object, SLOT(started())); + connect(&watcher, SIGNAL(canceled()), &object, SLOT(canceled())); + connect(&watcher, SIGNAL(finished()), &object, SLOT(finished())); + connect(&watcher, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int))); + connect(&watcher, SIGNAL(progressRangeChanged(int, int)), &object, SLOT(progressRangeChanged(int, int))); +#endif + connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int))); + + QSignalSpy startedSpy(&watcher, SIGNAL(started())); + QSignalSpy finishedSpy(&watcher, SIGNAL(finished())); + QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int))); + QSignalSpy canceledSpy(&watcher, SIGNAL(canceled())); + + watcher.setFuture(f); + QTest::qWait(10); + + QCOMPARE(startedSpy.count(), 1); + QCOMPARE(finishedSpy.count(), 1); + QCOMPARE(resultReadySpy.count(), 0); + QCOMPARE(canceledSpy.count(), 1); +} + +void tst_QFutureWatcher::disconnectRunningFuture() +{ + QFutureInterface a; + a.reportStarted(); + + QFuture f = a.future(); + QFutureWatcher *watcher = new QFutureWatcher(); + watcher->setFuture(f); + + SignalSlotObject object; + connect(watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int))); + + QSignalSpy finishedSpy(watcher, SIGNAL(finished())); + QSignalSpy resultReadySpy(watcher, SIGNAL(resultReadyAt(int))); + + const int result = 10; + a.reportResult(&result); + QTest::qWait(10); + QCOMPARE(resultReadySpy.count(), 1); + + delete watcher; + + a.reportResult(&result); + QTest::qWait(10); + QCOMPARE(resultReadySpy.count(), 1); + + a.reportFinished(&result); + QTest::qWait(10); + QCOMPARE(finishedSpy.count(), 0); +} + +const int maxProgress = 100000; +class ProgressEmitterTask : public RunFunctionTask +{ +public: + void runFunctor() + { + setProgressRange(0, maxProgress); + for (int p = 0; p <= maxProgress; ++p) + setProgressValue(p); + } +}; + +void tst_QFutureWatcher::toMuchProgress() +{ + progressValues.clear(); + ProgressObject o; + + QFutureWatcher f; + QObject::connect(&f, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); +#ifdef PRINT + QObject::connect(&f, SIGNAL(progressValueChanged(int)), &o, SLOT(printProgress(int))); +#endif + QObject::connect(&f, SIGNAL(progressValueChanged(int)), &o, SLOT(registerProgress(int))); + f.setFuture((new ProgressEmitterTask())->start()); + + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + QVERIFY(progressValues.contains(maxProgress)); +} + +template +class ProgressTextTask : public RunFunctionTask +{ +public: + void runFunctor() + { + this->setProgressValueAndText(1, QLatin1String("Foo 1")); + + while (this->isProgressUpdateNeeded() == false) + QTest::qSleep(1); + this->setProgressValueAndText(2, QLatin1String("Foo 2")); + + while (this->isProgressUpdateNeeded() == false) + QTest::qSleep(1); + this->setProgressValueAndText(3, QLatin1String("Foo 3")); + + while (this->isProgressUpdateNeeded() == false) + QTest::qSleep(1); + this->setProgressValueAndText(4, QLatin1String("Foo 4")); + } +}; + +void tst_QFutureWatcher::progressText() +{ + { // instantiate API for T=int and T=void. + ProgressTextTask a; + ProgressTextTask b; + } + { + progressValues.clear(); + progressTexts.clear(); + QFuture f = ((new ProgressTextTask())->start()); + QFutureWatcher watcher; + ProgressObject o; + QObject::connect(&watcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); +#ifdef PRINT + QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &o, SLOT(printProgress(int))); + QObject::connect(&watcher, SIGNAL(progressTextChanged(const QString &)), &o, SLOT(printText(const QString &))); +#endif + QObject::connect(&watcher, SIGNAL(progressValueChanged(int)), &o, SLOT(registerProgress(int))); + QObject::connect(&watcher, SIGNAL(progressTextChanged(const QString &)), &o, SLOT(registerText(const QString &))); + + watcher.setFuture(f); + QTestEventLoop::instance().enterLoop(5); + QVERIFY(!QTestEventLoop::instance().timeout()); + + QCOMPARE(f.progressText(), QLatin1String("Foo 4")); + QCOMPARE(f.progressValue(), 4); + QVERIFY(progressValues.contains(1)); + QVERIFY(progressValues.contains(2)); + QVERIFY(progressValues.contains(3)); + QVERIFY(progressValues.contains(4)); + QVERIFY(progressTexts.contains(QLatin1String("Foo 1"))); + QVERIFY(progressTexts.contains(QLatin1String("Foo 2"))); + QVERIFY(progressTexts.contains(QLatin1String("Foo 3"))); + QVERIFY(progressTexts.contains(QLatin1String("Foo 4"))); + } +} + +template +void callInterface(T &obj) +{ + obj.progressValue(); + obj.progressMinimum(); + obj.progressMaximum(); + obj.progressText(); + + obj.isStarted(); + obj.isFinished(); + obj.isRunning(); + obj.isCanceled(); + obj.isPaused(); + + obj.cancel(); + obj.pause(); + obj.resume(); + obj.togglePaused(); + obj.waitForFinished(); + + const T& objConst = obj; + objConst.progressValue(); + objConst.progressMinimum(); + objConst.progressMaximum(); + objConst.progressText(); + + objConst.isStarted(); + objConst.isFinished(); + objConst.isRunning(); + objConst.isCanceled(); + objConst.isPaused(); +} + +template +void callInterface(const T &obj) +{ + obj.result(); + obj.resultAt(0); +} + + +// QFutureWatcher and QFuture has a similar interface. Test +// that the functions we want ot have in both are actually +// there. +void tst_QFutureWatcher::sharedFutureInterface() +{ + QFutureInterface iface; + iface.reportStarted(); + + QFuture intFuture = iface.future(); + + int value = 0; + iface.reportFinished(&value); + + QFuture voidFuture; + QFutureWatcher intWatcher; + intWatcher.setFuture(intFuture); + QFutureWatcher voidWatcher; + + callInterface(intFuture); + callInterface(voidFuture); + callInterface(intWatcher); + callInterface(voidWatcher); + + callInterface(intFuture); + callInterface(intWatcher); +} + +void tst_QFutureWatcher::changeFuture() +{ + QFutureInterface iface; + iface.reportStarted(); + + QFuture a = iface.future(); + + int value = 0; + iface.reportFinished(&value); + + QFuture b; + + QFutureWatcher watcher; + + SignalSlotObject object; + connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int))); + QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int))); + + watcher.setFuture(a); // Watch 'a' which will genere a resultReady event. + watcher.setFuture(b); // But oh no! we're switching to another future + QTest::qWait(10); // before the event gets delivered. + + QCOMPARE(resultReadySpy.count(), 0); + + watcher.setFuture(a); + watcher.setFuture(b); + watcher.setFuture(a); // setting it back gets us one event, not two. + QTest::qWait(10); + + QCOMPARE(resultReadySpy.count(), 1); +} + +// Test that events aren't delivered from canceled futures +void tst_QFutureWatcher::cancelEvents() +{ + QFutureInterface iface; + iface.reportStarted(); + + QFuture a = iface.future(); + + int value = 0; + iface.reportFinished(&value); + + QFutureWatcher watcher; + + SignalSlotObject object; + connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int))); + QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int))); + + watcher.setFuture(a); + watcher.cancel(); + + QTest::qWait(10); + + QCOMPARE(resultReadySpy.count(), 0); +} + +// Tests that events from paused futures are saved and +// delivered on resume. +void tst_QFutureWatcher::pauseEvents() +{ + { + QFutureInterface iface; + iface.reportStarted(); + + QFuture a = iface.future(); + + int value = 0; + iface.reportFinished(&value); + + QFutureWatcher watcher; + + SignalSlotObject object; + connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int))); + QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int))); + + watcher.setFuture(a); + watcher.pause(); + + QTest::qWait(10); + QCOMPARE(resultReadySpy.count(), 0); + + watcher.resume(); + QTest::qWait(10); + QCOMPARE(resultReadySpy.count(), 1); + } + { + QFutureInterface iface; + iface.reportStarted(); + + QFuture a = iface.future(); + + int value = 0; + iface.reportFinished(&value); + + QFutureWatcher watcher; + + SignalSlotObject object; + connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int))); + QSignalSpy resultReadySpy(&watcher, SIGNAL(resultReadyAt(int))); + + watcher.setFuture(a); + a.pause(); + + QFuture b; + watcher.setFuture(b); // If we watch b instead, resuming a + a.resume(); // should give us no results. + + QTest::qWait(10); + QCOMPARE(resultReadySpy.count(), 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() +{ + QFutureInterface iface; + iface.reportStarted(); + QFuture future = iface.future(); + QFutureWatcher watcher; + + watcher.setFuture(future); + QTest::qWait(10); + + iface.reportFinished(); + QVERIFY(future.isFinished()); + QVERIFY(watcher.isFinished() == false); + + QTest::qWait(10); + QVERIFY(watcher.isFinished()); +} + +/* + Verify that throttling kicks in if you report a lot of results, + and that it clears when the result events are processed. +*/ +void tst_QFutureWatcher::throttling() +{ + QFutureInterface iface; + iface.reportStarted(); + QFuture future = iface.future(); + QFutureWatcher watcher; + watcher.setFuture(future); + + QVERIFY(iface.isThrottled() == false); + + for (int i = 0; i < 1000; ++i) { + int result = 0; + iface.reportResult(result); + } + + QVERIFY(iface.isThrottled() == true); + + QTest::qWait(100); // process events. + + QVERIFY(iface.isThrottled() == false); + + iface.reportFinished(); +} + +int mapper(const int &i) +{ + return i; +} + +class ResultReadyTester : public QObject +{ +Q_OBJECT +public: + ResultReadyTester(QFutureWatcher *watcher) + :m_watcher(watcher), filter(false), ok(true), count(0) + { + + } +public slots: + void resultReadyAt(int index) + { + ++count; + if (m_watcher->future().isResultReadyAt(index) == false) + ok = false; + if (!filter && m_watcher->future().resultAt(index) != index) + ok = false; + if (filter && m_watcher->future().resultAt(index) != index * 2 + 1) + ok = false; + } +public: + QFutureWatcher *m_watcher; + bool filter; + bool ok; + int count; +}; + +void tst_QFutureWatcher::incrementalMapResults() +{ + QFutureWatcher watcher; + + SignalSlotObject object; +#ifdef PRINT + connect(&watcher, SIGNAL(finished()), &object, SLOT(finished())); + connect(&watcher, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int))); + connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int))); +#endif + + QObject::connect(&watcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + ResultReadyTester resultReadyTester(&watcher); + connect(&watcher, SIGNAL(resultReadyAt(int)), &resultReadyTester, SLOT(resultReadyAt(int))); + + const int count = 10000; + QList ints; + for (int i = 0; i < count; ++i) + ints << i; + + QFuture future = QtConcurrent::mapped(ints, mapper); + watcher.setFuture(future); + + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(resultReadyTester.count, count); + QVERIFY(resultReadyTester.ok); + QVERIFY(watcher.isFinished()); + future.waitForFinished(); +} + +bool filterer(int i) +{ + return (i % 2); +} + +void tst_QFutureWatcher::incrementalFilterResults() +{ + QFutureWatcher watcher; + + SignalSlotObject object; +#ifdef PRINT + connect(&watcher, SIGNAL(finished()), &object, SLOT(finished())); + connect(&watcher, SIGNAL(progressValueChanged(int)), &object, SLOT(progressValueChanged(int))); + connect(&watcher, SIGNAL(resultReadyAt(int)), &object, SLOT(resultReadyAt(int))); +#endif + + QObject::connect(&watcher, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop())); + + + ResultReadyTester resultReadyTester(&watcher); + resultReadyTester.filter = true; + connect(&watcher, SIGNAL(resultReadyAt(int)), &resultReadyTester, SLOT(resultReadyAt(int))); + + const int count = 10000; + QList ints; + for (int i = 0; i < count; ++i) + ints << i; + + QFuture future = QtConcurrent::filtered(ints, filterer); + watcher.setFuture(future); + + QTestEventLoop::instance().enterLoop(10); + QVERIFY(!QTestEventLoop::instance().timeout()); + QCOMPARE(resultReadyTester.count, count / 2); + QVERIFY(resultReadyTester.ok); + QVERIFY(watcher.isFinished()); + future.waitForFinished(); +} + +void tst_QFutureWatcher::qfutureSynchornizer() +{ + int taskCount = 1000; + QTime t; + t.start(); + + { + QFutureSynchronizer sync; + + sync.setCancelOnWait(true); + for (int i = 0; i < taskCount; ++i) { + sync.addFuture(run(sleeper)); + } + } + + // Test that we're not running each task. + QVERIFY(t.elapsed() < taskCount * 10); +} + +class DummyObject : public QObject { + Q_OBJECT +public slots: + void dummySlot() {} +public: + static void function(QMutex *m) + { + QMutexLocker lock(m); + } +}; + +void tst_QFutureWatcher::warnRace() +{ +#ifndef Q_OS_MAC //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 +#endif + QFutureWatcher watcher; + DummyObject object; + QMutex mutex; + mutex.lock(); + + QFuture future = QtConcurrent::run(DummyObject::function, &mutex); + watcher.setFuture(future); + QTRY_VERIFY(future.isStarted()); + connect(&watcher, SIGNAL(finished()), &object, SLOT(dummySlot())); + mutex.unlock(); + future.waitForFinished(); +} + +#include "tst_qfuturewatcher.moc" + +#else +QTEST_NOOP_MAIN +#endif diff --git a/tests/auto/corelib/concurrent/qtconcurrentfilter/.gitignore b/tests/auto/corelib/concurrent/qtconcurrentfilter/.gitignore new file mode 100644 index 0000000000..f93d27e009 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentfilter/.gitignore @@ -0,0 +1 @@ +tst_qtconcurrentfilter diff --git a/tests/auto/corelib/concurrent/qtconcurrentfilter/qtconcurrentfilter.pro b/tests/auto/corelib/concurrent/qtconcurrentfilter/qtconcurrentfilter.pro new file mode 100644 index 0000000000..62d4908e69 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentfilter/qtconcurrentfilter.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +DEFINES += QT_STRICT_ITERATORS +SOURCES += tst_qtconcurrentfilter.cpp +QT = core +CONFIG += parallel_test +linux*:CONFIG += insignificant_test diff --git a/tests/auto/corelib/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp b/tests/auto/corelib/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp new file mode 100644 index 0000000000..33611d7331 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentfilter/tst_qtconcurrentfilter.cpp @@ -0,0 +1,1546 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include + +#include "../qtconcurrentmap/functions.h" +#include "../qfuture/versioncheck.h" + +class tst_QtConcurrentFilter : public QObject +{ + Q_OBJECT + +private slots: + void filter(); + void filtered(); + void filteredReduced(); + void resultAt(); + void incrementalResults(); + void noDetatch(); + void stlContainers(); +}; + +#if !defined (QT_NO_CONCURRENT_TEST) && !defined(QT_NO_CONCURRENT_FILTER) + +void tst_QtConcurrentFilter::filter() +{ + // functor + { + QList list; + list << 1 << 2 << 3 << 4; + QtConcurrent::filter(list, KeepEvenIntegers()).waitForFinished(); + QCOMPARE(list, QList() << 2 << 4); + } + { + QList list; + list << 1 << 2 << 3 << 4; + QtConcurrent::blockingFilter(list, KeepEvenIntegers()); + QCOMPARE(list, QList() << 2 << 4); + } + { + QLinkedList linkedList; + linkedList << 1 << 2 << 3 << 4; + QtConcurrent::filter(linkedList, KeepEvenIntegers()).waitForFinished(); + QCOMPARE(linkedList, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList; + linkedList << 1 << 2 << 3 << 4; + QtConcurrent::blockingFilter(linkedList, KeepEvenIntegers()); + QCOMPARE(linkedList, QLinkedList() << 2 << 4); + } + { + QVector vector; + vector << 1 << 2 << 3 << 4; + QtConcurrent::filter(vector, KeepEvenIntegers()).waitForFinished(); + QCOMPARE(vector, QVector() << 2 << 4); + } + { + QVector vector; + vector << 1 << 2 << 3 << 4; + QtConcurrent::blockingFilter(vector, KeepEvenIntegers()); + QCOMPARE(vector, QVector() << 2 << 4); + } + + + // function + { + QList list; + list << 1 << 2 << 3 << 4; + QtConcurrent::filter(list, keepEvenIntegers).waitForFinished(); + QCOMPARE(list, QList() << 2 << 4); + } + { + QList list; + list << 1 << 2 << 3 << 4; + QtConcurrent::blockingFilter(list, keepEvenIntegers); + QCOMPARE(list, QList() << 2 << 4); + } + { + QLinkedList linkedList; + linkedList << 1 << 2 << 3 << 4; + QtConcurrent::filter(linkedList, keepEvenIntegers).waitForFinished(); + QCOMPARE(linkedList, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList; + linkedList << 1 << 2 << 3 << 4; + QtConcurrent::blockingFilter(linkedList, keepEvenIntegers); + QCOMPARE(linkedList, QLinkedList() << 2 << 4); + } + + // bound function + { + QList list; + list << 1 << 2 << 3 << 4; + QtConcurrent::filter(list, keepEvenIntegers).waitForFinished(); + QCOMPARE(list, QList() << 2 << 4); + } + { + QList list; + list << 1 << 2 << 3 << 4; + QtConcurrent::blockingFilter(list, keepEvenIntegers); + QCOMPARE(list, QList() << 2 << 4); + } + { + QLinkedList linkedList; + linkedList << 1 << 2 << 3 << 4; + QtConcurrent::filter(linkedList, keepEvenIntegers).waitForFinished(); + QCOMPARE(linkedList, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList; + linkedList << 1 << 2 << 3 << 4; + QtConcurrent::blockingFilter(linkedList, keepEvenIntegers); + QCOMPARE(linkedList, QLinkedList() << 2 << 4); + } + + // member + { + QList list; + list << 1 << 2 << 3 << 4; + QtConcurrent::filter(list, &Number::isEven).waitForFinished(); + QCOMPARE(list, QList() << 2 << 4); + } + { + QList list; + list << 1 << 2 << 3 << 4; + QtConcurrent::blockingFilter(list, &Number::isEven); + QCOMPARE(list, QList() << 2 << 4); + } + { + QLinkedList linkedList; + linkedList << 1 << 2 << 3 << 4; + QtConcurrent::filter(linkedList, &Number::isEven).waitForFinished(); + QCOMPARE(linkedList, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList; + linkedList << 1 << 2 << 3 << 4; + QtConcurrent::blockingFilter(linkedList, &Number::isEven); + QCOMPARE(linkedList, QLinkedList() << 2 << 4); + } +} + +void tst_QtConcurrentFilter::filtered() +{ + QList list; + list << 1 << 2 << 3 << 4; + + // functor + { + QFuture f = QtConcurrent::filtered(list, KeepEvenIntegers()); + QList list2 = f.results(); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QFuture f = QtConcurrent::filtered(list.begin(), list.end(), KeepEvenIntegers()); + QList list2 = f.results(); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QFuture f = QtConcurrent::filtered(list.constBegin(), + list.constEnd(), + KeepEvenIntegers()); + QList list2 = f.results(); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFiltered(list, KeepEvenIntegers()); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFiltered >(list.begin(), + list.end(), + KeepEvenIntegers()); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFiltered >(list.constBegin(), + list.constEnd(), + KeepEvenIntegers()); + QCOMPARE(list2, QList() << 2 << 4); + } + + { + QVector vector; + vector << 1 << 2 << 3 << 4; + QVector vector2 = QtConcurrent::blockingFiltered(vector, KeepEvenIntegers()); + QCOMPARE(vector2, QVector() << 2 << 4); + } + { + QVector vector; + vector << 1 << 2 << 3 << 4; + QFuture f = QtConcurrent::filtered(vector, KeepEvenIntegers()); + QCOMPARE(f.results(), QList() << 2 << 4); + } + + { + QLinkedList linkedList; + linkedList << 1 << 2 << 3 << 4; + QLinkedList linkedList2 = QtConcurrent::blockingFiltered(linkedList, KeepEvenIntegers()); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList; + linkedList << 1 << 2 << 3 << 4; + QFuture f = QtConcurrent::filtered(linkedList, KeepEvenIntegers()); + QCOMPARE(f.results(), QList() << 2 << 4); + } + + // function + { + QFuture f = QtConcurrent::filtered(list, keepEvenIntegers); + QList list2 = f.results(); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QFuture f = QtConcurrent::filtered(list.begin(), list.end(), keepEvenIntegers); + QList list2 = f.results(); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QFuture f = QtConcurrent::filtered(list.constBegin(), + list.constEnd(), + keepEvenIntegers); + QList list2 = f.results(); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFiltered(list, keepEvenIntegers); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFiltered >(list.begin(), + list.end(), + keepEvenIntegers); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFiltered >(list.constBegin(), + list.constEnd(), + keepEvenIntegers); + QCOMPARE(list2, QList() << 2 << 4); + } + + // bound function + { + QFuture f = QtConcurrent::filtered(list, keepEvenIntegers); + QList list2 = f.results(); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QFuture f = QtConcurrent::filtered(list.begin(), list.end(), keepEvenIntegers); + QList list2 = f.results(); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QFuture f = QtConcurrent::filtered(list.constBegin(), + list.constEnd(), + keepEvenIntegers); + QList list2 = f.results(); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFiltered(list, keepEvenIntegers); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFiltered >(list.begin(), + list.end(), + keepEvenIntegers); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFiltered >(list.constBegin(), + list.constEnd(), + keepEvenIntegers); + QCOMPARE(list2, QList() << 2 << 4); + } + + // const member function + { + QList integers; + integers << 1 << 2 << 3 << 4; + QFuture f = QtConcurrent::filtered(integers, &Number::isEven); + QList list2 = f.results(); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList integers; + integers << 1 << 2 << 3 << 4; + QFuture f = QtConcurrent::filtered(integers.begin(), + integers.end(), + &Number::isEven); + QList list2 = f.results(); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList integers; + integers << 1 << 2 << 3 << 4; + QFuture f = QtConcurrent::filtered(integers.constBegin(), + integers.constEnd(), + &Number::isEven); + QList list2 = f.results(); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList integers; + integers << 1 << 2 << 3 << 4; + QList list2 = QtConcurrent::blockingFiltered(integers, &Number::isEven); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList integers; + integers << 1 << 2 << 3 << 4; + QList list2 = QtConcurrent::blockingFiltered >(integers.begin(), + integers.end(), + &Number::isEven); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList integers; + integers << 1 << 2 << 3 << 4; + QList list2 = + QtConcurrent::blockingFiltered >(integers.constBegin(), + integers.constEnd(), + &Number::isEven); + QCOMPARE(list2, QList() << 2 << 4); + } + + // same thing on linked lists + + QLinkedList linkedList; + linkedList << 1 << 2 << 3 << 4; + + // functor + { + QFuture f = QtConcurrent::filtered(linkedList, KeepEvenIntegers()); + QList linkedList2 = f.results(); + QCOMPARE(linkedList2, QList() << 2 << 4); + } + { + QFuture f = QtConcurrent::filtered(linkedList.begin(), + linkedList.end(), + KeepEvenIntegers()); + QList linkedList2 = f.results(); + QCOMPARE(linkedList2, QList() << 2 << 4); + } + { + QFuture f = QtConcurrent::filtered(linkedList.constBegin(), + linkedList.constEnd(), + KeepEvenIntegers()); + QList linkedList2 = f.results(); + QCOMPARE(linkedList2, QList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFiltered(linkedList, KeepEvenIntegers()); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFiltered >(linkedList.begin(), + linkedList.end(), + KeepEvenIntegers()); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFiltered >(linkedList.constBegin(), + linkedList.constEnd(), + KeepEvenIntegers()); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + + // function + { + QFuture f = QtConcurrent::filtered(linkedList, keepEvenIntegers); + QList linkedList2 = f.results(); + QCOMPARE(linkedList2, QList() << 2 << 4); + } + { + QFuture f = QtConcurrent::filtered(linkedList.begin(), + linkedList.end(), + keepEvenIntegers); + QList linkedList2 = f.results(); + QCOMPARE(linkedList2, QList() << 2 << 4); + } + { + QFuture f = QtConcurrent::filtered(linkedList.constBegin(), + linkedList.constEnd(), + keepEvenIntegers); + QList linkedList2 = f.results(); + QCOMPARE(linkedList2, QList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFiltered(linkedList, keepEvenIntegers); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFiltered >(linkedList.begin(), + linkedList.end(), + keepEvenIntegers); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFiltered >(linkedList.constBegin(), + linkedList.constEnd(), + keepEvenIntegers); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + + // bound function + { + QFuture f = QtConcurrent::filtered(linkedList, keepEvenIntegers); + QList linkedList2 = f.results(); + QCOMPARE(linkedList2, QList() << 2 << 4); + } + { + QFuture f = QtConcurrent::filtered(linkedList.begin(), + linkedList.end(), + keepEvenIntegers); + QList linkedList2 = f.results(); + QCOMPARE(linkedList2, QList() << 2 << 4); + } + { + QFuture f = QtConcurrent::filtered(linkedList.constBegin(), + linkedList.constEnd(), + keepEvenIntegers); + QList linkedList2 = f.results(); + QCOMPARE(linkedList2, QList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFiltered(linkedList, keepEvenIntegers); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFiltered >(linkedList.begin(), + linkedList.end(), + keepEvenIntegers); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFiltered >(linkedList.constBegin(), + linkedList.constEnd(), + keepEvenIntegers); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + + // const member function + { + QLinkedList integers; + integers << 1 << 2 << 3 << 4; + QFuture f = QtConcurrent::filtered(integers, &Number::isEven); + QList linkedList2 = f.results(); + QCOMPARE(linkedList2, QList() << 2 << 4); + } + { + QLinkedList integers; + integers << 1 << 2 << 3 << 4; + QFuture f = QtConcurrent::filtered(integers.begin(), + integers.end(), + &Number::isEven); + QList linkedList2 = f.results(); + QCOMPARE(linkedList2, QList() << 2 << 4); + } + { + QLinkedList integers; + integers << 1 << 2 << 3 << 4; + QFuture f = QtConcurrent::filtered(integers.constBegin(), + integers.constEnd(), + &Number::isEven); + QList linkedList2 = f.results(); + QCOMPARE(linkedList2, QList() << 2 << 4); + } + { + QLinkedList integers; + integers << 1 << 2 << 3 << 4; + QLinkedList linkedList2 = QtConcurrent::blockingFiltered(integers, &Number::isEven); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList integers; + integers << 1 << 2 << 3 << 4; + QLinkedList linkedList2 = QtConcurrent::blockingFiltered >(integers.begin(), + integers.end(), + &Number::isEven); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList integers; + integers << 1 << 2 << 3 << 4; + QLinkedList linkedList2 = + QtConcurrent::blockingFiltered >(integers.constBegin(), + integers.constEnd(), + &Number::isEven); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } +} + +void tst_QtConcurrentFilter::filteredReduced() +{ + QList list; + list << 1 << 2 << 3 << 4; + QList numberList; + numberList << 1 << 2 << 3 << 4; + + // functor-functor + { + int sum = QtConcurrent::filteredReduced(list, KeepEvenIntegers(), IntSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::filteredReduced(list, keepEvenIntegers, intSumReduce); + QCOMPARE(sum2, 6); + } + { + QVector vector; + vector << 1 << 2 << 3 << 4; + int sum = QtConcurrent::filteredReduced(vector, KeepEvenIntegers(), IntSumReduce()); + QCOMPARE(sum, 6); + } + + { + int sum = QtConcurrent::filteredReduced(list.begin(), + list.end(), + KeepEvenIntegers(), + IntSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::filteredReduced(list.begin(), + list.end(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::filteredReduced(list.constBegin(), + list.constEnd(), + KeepEvenIntegers(), + IntSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::filteredReduced(list.constBegin(), + list.constEnd(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(list, KeepEvenIntegers(), IntSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::blockingFilteredReduced(list, keepEvenIntegers, intSumReduce); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(list.begin(), + list.end(), + KeepEvenIntegers(), + IntSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::blockingFilteredReduced(list.begin(), + list.end(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(list.constBegin(), + list.constEnd(), + KeepEvenIntegers(), + IntSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::blockingFilteredReduced(list.constBegin(), + list.constEnd(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum2, 6); + } + + // function-functor + { + int sum = QtConcurrent::filteredReduced(list, keepEvenIntegers, IntSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(list.begin(), + list.end(), + keepEvenIntegers, + IntSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(list.constBegin(), + list.constEnd(), + keepEvenIntegers, + IntSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(list, keepEvenIntegers, IntSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(list.begin(), + list.end(), + keepEvenIntegers, + IntSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(list.constBegin(), + list.constEnd(), + keepEvenIntegers, + IntSumReduce()); + QCOMPARE(sum, 6); + } + + // functor-function + { + int sum = QtConcurrent::filteredReduced(list, KeepEvenIntegers(), intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(list.begin(), + list.end(), + KeepEvenIntegers(), + intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(list.constBegin(), + list.constEnd(), + KeepEvenIntegers(), + intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(list, KeepEvenIntegers(), intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(list.begin(), + list.end(), + KeepEvenIntegers(), + intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(list.constBegin(), + list.constEnd(), + KeepEvenIntegers(), + intSumReduce); + QCOMPARE(sum, 6); + } + + // function-function + { + int sum = QtConcurrent::filteredReduced(list, keepEvenIntegers, intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(list.begin(), + list.end(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(list.constBegin(), + list.constEnd(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(list, keepEvenIntegers, intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(list.begin(), + list.end(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(list.constBegin(), + list.constEnd(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum, 6); + } + + // functor-member + { + QList list2 = QtConcurrent::filteredReduced(list, KeepEvenIntegers(), &QList::push_back, QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::filteredReduced(list.begin(), + list.end(), + KeepEvenIntegers(), + &QList::push_back, + QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::filteredReduced(list.constBegin(), + list.constEnd(), + KeepEvenIntegers(), + &QList::push_back, + QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFilteredReduced(list, KeepEvenIntegers(), &QList::push_back, QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFilteredReduced(list.begin(), + list.end(), + KeepEvenIntegers(), + &QList::push_back, + QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFilteredReduced(list.constBegin(), + list.constEnd(), + KeepEvenIntegers(), + &QList::push_back, + QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + + // member-functor + { + int sum = QtConcurrent::filteredReduced(numberList, &Number::isEven, NumberSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::filteredReduced(QList(numberList), + &Number::isEven, + NumberSumReduce()); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::filteredReduced(numberList.begin(), + numberList.end(), + &Number::isEven, + NumberSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(numberList.constBegin(), + numberList.constEnd(), + &Number::isEven, + NumberSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(numberList, &Number::isEven, NumberSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::blockingFilteredReduced(QList(numberList), + &Number::isEven, + NumberSumReduce()); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(numberList.begin(), + numberList.end(), + &Number::isEven, + NumberSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(numberList.constBegin(), + numberList.constEnd(), + &Number::isEven, + NumberSumReduce()); + QCOMPARE(sum, 6); + } + + // member-member + { + QList numbers; + numbers << 1 << 2 << 3 << 4; + QList list2 = QtConcurrent::filteredReduced(numbers, + &Number::isEven, + &QList::push_back, QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList numbers; + numbers << 1 << 2 << 3 << 4; + QList list2 = QtConcurrent::filteredReduced(numbers.begin(), + numbers.end(), + &Number::isEven, + &QList::push_back, + QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList numbers; + numbers << 1 << 2 << 3 << 4; + QList list2 = QtConcurrent::filteredReduced(numbers.constBegin(), + numbers.constEnd(), + &Number::isEven, + &QList::push_back, + QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList numbers; + numbers << 1 << 2 << 3 << 4; + QList list2 = QtConcurrent::blockingFilteredReduced(numbers, + &Number::isEven, + &QList::push_back, QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList numbers; + numbers << 1 << 2 << 3 << 4; + QList list2 = QtConcurrent::blockingFilteredReduced(numbers.begin(), + numbers.end(), + &Number::isEven, + &QList::push_back, + QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList numbers; + numbers << 1 << 2 << 3 << 4; + QList list2 = QtConcurrent::blockingFilteredReduced(numbers.constBegin(), + numbers.constEnd(), + &Number::isEven, + &QList::push_back, + QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + + // function-member + { + QList list2 = QtConcurrent::filteredReduced(list, keepEvenIntegers, &QList::push_back, QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::filteredReduced(list.begin(), + list.end(), + keepEvenIntegers, + &QList::push_back, + QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::filteredReduced(list.constBegin(), + list.constEnd(), + keepEvenIntegers, + &QList::push_back, + QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFilteredReduced(list, keepEvenIntegers, &QList::push_back, QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFilteredReduced(list.begin(), + list.end(), + keepEvenIntegers, + &QList::push_back, + QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + { + QList list2 = QtConcurrent::blockingFilteredReduced(list.constBegin(), + list.constEnd(), + keepEvenIntegers, + &QList::push_back, + QtConcurrent::OrderedReduce); + QCOMPARE(list2, QList() << 2 << 4); + } + + // member-function + { + int sum = QtConcurrent::filteredReduced(numberList, &Number::isEven, numberSumReduce); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::filteredReduced(QList(numberList), + &Number::isEven, + numberSumReduce); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::filteredReduced(numberList.begin(), + numberList.end(), + &Number::isEven, + numberSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(numberList.constBegin(), + numberList.constEnd(), + &Number::isEven, + numberSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(numberList, &Number::isEven, numberSumReduce); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::blockingFilteredReduced(QList(numberList), + &Number::isEven, + numberSumReduce); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(numberList.begin(), + numberList.end(), + &Number::isEven, + numberSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(numberList.constBegin(), + numberList.constEnd(), + &Number::isEven, + numberSumReduce); + QCOMPARE(sum, 6); + } + + // same as above on linked lists + QLinkedList linkedList; + linkedList << 1 << 2 << 3 << 4; + QLinkedList numberLinkedList; + numberLinkedList << 1 << 2 << 3 << 4; + + // functor-functor + { + int sum = QtConcurrent::filteredReduced(linkedList, KeepEvenIntegers(), IntSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::filteredReduced(linkedList, keepEvenIntegers, intSumReduce); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::filteredReduced(linkedList.begin(), + linkedList.end(), + KeepEvenIntegers(), + IntSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::filteredReduced(linkedList.begin(), + linkedList.end(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::filteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + KeepEvenIntegers(), + IntSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::filteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(linkedList, KeepEvenIntegers(), IntSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::blockingFilteredReduced(linkedList, keepEvenIntegers, intSumReduce); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(linkedList.begin(), + linkedList.end(), + KeepEvenIntegers(), + IntSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::blockingFilteredReduced(linkedList.begin(), + linkedList.end(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + KeepEvenIntegers(), + IntSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::blockingFilteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum2, 6); + } + + // function-functor + { + int sum = QtConcurrent::filteredReduced(linkedList, keepEvenIntegers, IntSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(linkedList.begin(), + linkedList.end(), + keepEvenIntegers, + IntSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + keepEvenIntegers, + IntSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(linkedList, keepEvenIntegers, IntSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(linkedList.begin(), + linkedList.end(), + keepEvenIntegers, + IntSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + keepEvenIntegers, + IntSumReduce()); + QCOMPARE(sum, 6); + } + + // functor-function + { + int sum = QtConcurrent::filteredReduced(linkedList, KeepEvenIntegers(), intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(linkedList.begin(), + linkedList.end(), + KeepEvenIntegers(), + intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + KeepEvenIntegers(), + intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(linkedList, KeepEvenIntegers(), intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(linkedList.begin(), + linkedList.end(), + KeepEvenIntegers(), + intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + KeepEvenIntegers(), + intSumReduce); + QCOMPARE(sum, 6); + } + + // function-function + { + int sum = QtConcurrent::filteredReduced(linkedList, keepEvenIntegers, intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(linkedList.begin(), + linkedList.end(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(linkedList, keepEvenIntegers, intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(linkedList.begin(), + linkedList.end(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + keepEvenIntegers, + intSumReduce); + QCOMPARE(sum, 6); + } + + // functor-member + { + QLinkedList linkedList2 = QtConcurrent::filteredReduced(linkedList, KeepEvenIntegers(), &QLinkedList::append, QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::filteredReduced(linkedList.begin(), + linkedList.end(), + KeepEvenIntegers(), + &QLinkedList::append, + QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::filteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + KeepEvenIntegers(), + &QLinkedList::append, + QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFilteredReduced(linkedList, KeepEvenIntegers(), &QLinkedList::append, QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFilteredReduced(linkedList.begin(), + linkedList.end(), + KeepEvenIntegers(), + &QLinkedList::append, + QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFilteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + KeepEvenIntegers(), + &QLinkedList::append, + QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + + // member-functor + { + int sum = QtConcurrent::filteredReduced(numberLinkedList, &Number::isEven, NumberSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::filteredReduced(QLinkedList(numberLinkedList), + &Number::isEven, + NumberSumReduce()); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::filteredReduced(numberLinkedList.begin(), + numberLinkedList.end(), + &Number::isEven, + NumberSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(numberLinkedList.constBegin(), + numberLinkedList.constEnd(), + &Number::isEven, + NumberSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(numberLinkedList, &Number::isEven, NumberSumReduce()); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::blockingFilteredReduced(QLinkedList(numberLinkedList), + &Number::isEven, + NumberSumReduce()); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(numberLinkedList.begin(), + numberLinkedList.end(), + &Number::isEven, + NumberSumReduce()); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(numberLinkedList.constBegin(), + numberLinkedList.constEnd(), + &Number::isEven, + NumberSumReduce()); + QCOMPARE(sum, 6); + } + + // member-member + { + QLinkedList numbers; + numbers << 1 << 2 << 3 << 4; + QLinkedList linkedList2 = QtConcurrent::filteredReduced(numbers, + &Number::isEven, + &QLinkedList::append, QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList numbers; + numbers << 1 << 2 << 3 << 4; + QLinkedList linkedList2 = QtConcurrent::filteredReduced(numbers.begin(), + numbers.end(), + &Number::isEven, + &QLinkedList::append, + QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList numbers; + numbers << 1 << 2 << 3 << 4; + QLinkedList linkedList2 = QtConcurrent::filteredReduced(numbers.constBegin(), + numbers.constEnd(), + &Number::isEven, + &QLinkedList::append, + QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList numbers; + numbers << 1 << 2 << 3 << 4; + QLinkedList linkedList2 = QtConcurrent::blockingFilteredReduced(numbers, + &Number::isEven, + &QLinkedList::append, QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList numbers; + numbers << 1 << 2 << 3 << 4; + QLinkedList linkedList2 = QtConcurrent::blockingFilteredReduced(numbers.begin(), + numbers.end(), + &Number::isEven, + &QLinkedList::append, + QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList numbers; + numbers << 1 << 2 << 3 << 4; + QLinkedList linkedList2 = QtConcurrent::blockingFilteredReduced(numbers.constBegin(), + numbers.constEnd(), + &Number::isEven, + &QLinkedList::append, + QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + + // function-member + { + QLinkedList linkedList2 = QtConcurrent::filteredReduced(linkedList, keepEvenIntegers, &QLinkedList::append, QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::filteredReduced(linkedList.begin(), + linkedList.end(), + keepEvenIntegers, + &QLinkedList::append, + QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::filteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + keepEvenIntegers, + &QLinkedList::append, + QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFilteredReduced(linkedList, keepEvenIntegers, &QLinkedList::append, QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFilteredReduced(linkedList.begin(), + linkedList.end(), + keepEvenIntegers, + &QLinkedList::append, + QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingFilteredReduced(linkedList.constBegin(), + linkedList.constEnd(), + keepEvenIntegers, + &QLinkedList::append, + QtConcurrent::OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4); + } + + // member-function + { + int sum = QtConcurrent::filteredReduced(numberLinkedList, &Number::isEven, numberSumReduce); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::filteredReduced(QLinkedList(numberLinkedList), + &Number::isEven, + numberSumReduce); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::filteredReduced(numberLinkedList.begin(), + numberLinkedList.end(), + &Number::isEven, + numberSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::filteredReduced(numberLinkedList.constBegin(), + numberLinkedList.constEnd(), + &Number::isEven, + numberSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(numberLinkedList, &Number::isEven, numberSumReduce); + QCOMPARE(sum, 6); + + int sum2 = QtConcurrent::blockingFilteredReduced(QLinkedList(numberLinkedList), + &Number::isEven, + numberSumReduce); + QCOMPARE(sum2, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(numberLinkedList.begin(), + numberLinkedList.end(), + &Number::isEven, + numberSumReduce); + QCOMPARE(sum, 6); + } + { + int sum = QtConcurrent::blockingFilteredReduced(numberLinkedList.constBegin(), + numberLinkedList.constEnd(), + &Number::isEven, + numberSumReduce); + QCOMPARE(sum, 6); + } + + // ### the same as above, with an initial result value +} + +bool filterfn(int i) +{ + return (i % 2); +} + +void tst_QtConcurrentFilter::resultAt() +{ + + QList ints; + for (int i=0; i < 1000; ++i) + ints << i; + + QFuture future = QtConcurrent::filtered(ints, filterfn); + future.waitForFinished(); + + + for (int i = 0; i < future.resultCount(); ++i) { + QCOMPARE(future.resultAt(i), ints.at(i * 2 + 1)); + } + +} + +bool waitFilterfn(const int &i) +{ + QTest::qWait(1); + return (i % 2); +} + +void tst_QtConcurrentFilter::incrementalResults() +{ + const int count = 200; + QList ints; + for (int i=0; i < count; ++i) + ints << i; + + QFuture future = QtConcurrent::filtered(ints, waitFilterfn); + + QList results; + + while (future.isFinished() == false) { + for (int i = 0; i < future.resultCount(); ++i) { + results += future.resultAt(i); + } + QTest::qWait(1); + } + + QCOMPARE(future.isFinished(), true); + QCOMPARE(future.resultCount(), count / 2); + QCOMPARE(future.results().count(), count / 2); +} + +void tst_QtConcurrentFilter::noDetatch() +{ + { + QList l = QList() << 1; + QVERIFY(l.isDetached()); + + QList ll = l; + QVERIFY(l.isDetached() == false); + + QtConcurrent::filtered(l, waitFilterfn).waitForFinished(); + + QVERIFY(l.isDetached() == false); + QVERIFY(ll.isDetached() == false); + + QtConcurrent::blockingFiltered(l, waitFilterfn); + + QVERIFY(l.isDetached() == false); + QVERIFY(ll.isDetached() == false); + + QtConcurrent::filteredReduced(l, waitFilterfn, intSumReduce).waitForFinished(); + + QVERIFY(l.isDetached() == false); + QVERIFY(ll.isDetached() == false); + + QtConcurrent::filter(l, waitFilterfn).waitForFinished(); + QVERIFY(l.isDetached() == true); + QVERIFY(ll.isDetached() == true); + } + { + const QList l = QList() << 1; + QVERIFY(l.isDetached()); + + const QList ll = l; + QVERIFY(l.isDetached() == false); + + QtConcurrent::filtered(l, waitFilterfn).waitForFinished(); + + QVERIFY(l.isDetached() == false); + QVERIFY(ll.isDetached() == false); + + QtConcurrent::filteredReduced(l, waitFilterfn, intSumReduce).waitForFinished(); + + QVERIFY(l.isDetached() == false); + QVERIFY(ll.isDetached() == false); + } +} + +void tst_QtConcurrentFilter::stlContainers() +{ +#ifdef QT_NO_STL + QSKIP("Qt compiled without STL support", SkipAll); +#else + std::vector vector; + vector.push_back(1); + vector.push_back(2); + + std::vector vector2 = QtConcurrent::blockingFiltered(vector, waitFilterfn); + QCOMPARE(vector2.size(), (std::vector::size_type)(1)); + QCOMPARE(vector2[0], 1); + + std::list list; + list.push_back(1); + list.push_back(2); + + std::list list2 = QtConcurrent::blockingFiltered(list, waitFilterfn); + QCOMPARE(list2.size(), (std::list::size_type)(1)); + QCOMPARE(*list2.begin(), 1); + + QtConcurrent::filtered(list, waitFilterfn).waitForFinished(); + QtConcurrent::filtered(vector, waitFilterfn).waitForFinished(); + QtConcurrent::filtered(vector.begin(), vector.end(), waitFilterfn).waitForFinished(); + + QtConcurrent::blockingFilter(list, waitFilterfn); + QCOMPARE(list2.size(), (std::list::size_type)(1)); + QCOMPARE(*list2.begin(), 1); +#endif +} + +QTEST_MAIN(tst_QtConcurrentFilter) + +#else + +void tst_QtConcurrentFilter::filter() {} +void tst_QtConcurrentFilter::filtered() {} +void tst_QtConcurrentFilter::filteredReduced() {} +void tst_QtConcurrentFilter::resultAt() {} +void tst_QtConcurrentFilter::incrementalResults() {} +void tst_QtConcurrentFilter::stlContainers() {} +void tst_QtConcurrentFilter::noDetatch() {} + +QTEST_NOOP_MAIN +#endif + +#include "tst_qtconcurrentfilter.moc" diff --git a/tests/auto/corelib/concurrent/qtconcurrentiteratekernel/.gitignore b/tests/auto/corelib/concurrent/qtconcurrentiteratekernel/.gitignore new file mode 100644 index 0000000000..ac5dec4db6 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentiteratekernel/.gitignore @@ -0,0 +1 @@ +tst_qtconcurrentiteratekernel diff --git a/tests/auto/corelib/concurrent/qtconcurrentiteratekernel/qtconcurrentiteratekernel.pro b/tests/auto/corelib/concurrent/qtconcurrentiteratekernel/qtconcurrentiteratekernel.pro new file mode 100644 index 0000000000..a61d275241 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentiteratekernel/qtconcurrentiteratekernel.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qtconcurrentiteratekernel.cpp +QT = core +CONFIG += parallel_test +CONFIG += parallel_test diff --git a/tests/auto/corelib/concurrent/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp b/tests/auto/corelib/concurrent/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp new file mode 100644 index 0000000000..521c517d90 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentiteratekernel/tst_qtconcurrentiteratekernel.cpp @@ -0,0 +1,360 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include "../qfuture/versioncheck.h" + +struct TestIterator +{ + TestIterator(int i) + :i(i) { } + + int operator-(const TestIterator &other) + { + return i - other.i; + } + + TestIterator& operator++() + { + ++i; + return *this; + } + + bool operator!=(const TestIterator &other) const + { + return i != other.i; + } + + int i; +}; + +#include +#ifndef QT_NO_STL +namespace std { +template <> +struct iterator_traits +{ + typedef random_access_iterator_tag iterator_category; +}; + +int distance(TestIterator &a, TestIterator &b) +{ + return b - a; +} + +} +#endif + + +#include +#include + +#ifndef QT_NO_CONCURRENT_TEST + +using namespace QtConcurrent; + +class tst_QtConcurrentIterateKernel: public QObject +{ + Q_OBJECT +private slots: + // "for" iteration tests: + void instantiate(); + void cancel(); + void stresstest(); + void noIterations(); + void throttling(); + void blockSize(); + void multipleResults(); +#if 0 + //"while" iterations tests: + void instantiateWhile(); + void stresstestWhile(); +#endif +}; + +QAtomicInt iterations; +class PrintFor : public IterateKernel +{ +public: + PrintFor(TestIterator begin, TestIterator end) : IterateKernel(begin, end) {iterations = 0; } + bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *) + { + iterations.fetchAndAddRelaxed(end - begin); +#ifdef PRINT + qDebug() << QThread::currentThread() << "iteration" << begin << "to" << end << "(exclusive)"; +#endif + return false; + } + bool runIteration(TestIterator it, int index , void *result) + { + return runIterations(it, index, index + 1, result); + } + +}; + +class SleepPrintFor : public IterateKernel +{ +public: + SleepPrintFor(TestIterator begin, TestIterator end) : IterateKernel(begin, end) {iterations = 0; } + inline bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *) + { + QTest::qSleep(200); + iterations.fetchAndAddRelaxed(end - begin); +#ifdef PRINT + qDebug() << QThread::currentThread() << "iteration" << begin << "to" << end << "(exclusive)"; +#endif + return false; + } + bool runIteration(TestIterator it, int index , void *result) + { + return runIterations(it, index, index + 1, result); + } +}; + + +void tst_QtConcurrentIterateKernel::instantiate() +{ + startThreadEngine(new PrintFor(0, 40)).startBlocking(); + QCOMPARE((int)iterations, 40); +} + +void tst_QtConcurrentIterateKernel::cancel() +{ + { + QFuture f = startThreadEngine(new SleepPrintFor(0, 40)).startAsynchronously(); + f.cancel(); + f.waitForFinished(); + QVERIFY(f.isCanceled()); + QVERIFY(int(iterations) <= QThread::idealThreadCount()); // the threads might run one iteration each before they are canceled. + } +} + +QAtomicInt counter; +class CountFor : public IterateKernel +{ +public: + CountFor(TestIterator begin, TestIterator end) : IterateKernel(begin, end) {iterations = 0; } + inline bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *) + { + counter.fetchAndAddRelaxed(end - begin); + return false; + } + bool runIteration(TestIterator it, int index , void *result) + { + return runIterations(it, index, index + 1, result); + } +}; + +void tst_QtConcurrentIterateKernel::stresstest() +{ + const int iterations = 1000; + const int times = 50; + for (int i = 0; i < times; ++i) { + counter = 0; + CountFor f(0, iterations); + f.startBlocking(); + QCOMPARE((int)counter, iterations); + } +} + +void tst_QtConcurrentIterateKernel::noIterations() +{ + const int times = 20000; + for (int i = 0; i < times; ++i) + startThreadEngine(new IterateKernel(0, 0)).startBlocking(); +} + +QMutex threadsMutex; +QSet threads; +class ThrottleFor : public IterateKernel +{ +public: + // this class throttles between iterations 100 and 200, + // and then records how many threads that run between + // iterations 140 and 160. + ThrottleFor(TestIterator begin, TestIterator end) : IterateKernel(begin, end) {iterations = 0; throttling = false; } + inline bool runIterations(TestIterator/*beginIterator*/, int begin, int end, void *) + { + if (200 >= begin && 200 < end) { + throttling = false; + } + + iterations.fetchAndAddRelaxed(end - begin); + + QThread *thread = QThread::currentThread(); + + if (begin > 140 && end < 160) { + QMutexLocker locker(&threadsMutex); + threads.insert(thread); + } + + if (100 >= begin && 100 < end) { + throttling = true; + } + + QTest::qWait(1); + + return false; + } + bool runIteration(TestIterator it, int index , void *result) + { + return runIterations(it, index, index + 1, result); + } + + bool shouldThrottleThread() + { + return (iterations > 100 && iterations < 200); + } + bool throttling; +}; + +void tst_QtConcurrentIterateKernel::throttling() +{ + const int totalIterations = 400; + iterations = 0; + + threads.clear(); + + ThrottleFor f(0, totalIterations); + f.startBlocking(); + + QCOMPARE((int)iterations, totalIterations); + + + QCOMPARE(threads.count(), 1); +} + + +int peakBlockSize = 0; +class BlockSizeRecorder : public IterateKernel +{ +public: + BlockSizeRecorder(TestIterator begin, TestIterator end) : IterateKernel(begin, end) { } + inline bool runIterations(TestIterator, int begin, int end, void *) + { + peakBlockSize = qMax(peakBlockSize, end - begin); + return false; + } +}; + +void tst_QtConcurrentIterateKernel::blockSize() +{ +#ifdef QT_NO_STL + QSKIP("Missing stl iterators prevent correct block size calculation", SkipAll); +#endif + const int expectedMinimumBlockSize = 1024 / QThread::idealThreadCount(); + BlockSizeRecorder(0, 10000).startBlocking(); + if (peakBlockSize < expectedMinimumBlockSize) + qDebug() << "block size" << peakBlockSize; + QVERIFY(peakBlockSize >= expectedMinimumBlockSize); +} + +class MultipleResultsFor : public IterateKernel +{ +public: + MultipleResultsFor(TestIterator begin, TestIterator end) : IterateKernel(begin, end) { } + inline bool runIterations(TestIterator, int begin, int end, int *results) + { + for (int i = begin; i < end; ++i) + results[i - begin] = i; + return true; + } +}; + + +void tst_QtConcurrentIterateKernel::multipleResults() +{ +#ifdef QT_NO_STL + QSKIP("Missing stl iterators prevent correct summation", SkipAll); +#endif + QFuture f = startThreadEngine(new MultipleResultsFor(0, 10)).startAsynchronously(); + QCOMPARE(f.results().count() , 10); + QCOMPARE(f.resultAt(0), 0); + QCOMPARE(f.resultAt(5), 5); + QCOMPARE(f.resultAt(9), 9); + f.waitForFinished(); +} + +#if 0 +class PrintWhile : public IterateKernel +{ +public: + PrintWhile() : IterateKernel(0, 10, WhileIteration) { } + bool runIteration(TestIterator it, TestIterator, void *) + { + return false; + } +}; + +void tst_QtConcurrentIterateKernel::instantiateWhile() +{ + PrintWhile w; + w.startBlocking(); +} + +QAtomicInt iterationCount; +class StressWhile : public IterateKernel +{ +public: + StressWhile(TestIterator iterations) : IterateKernel(0, iterations, WhileIteration) { } + bool runIteration(TestIterator it, TestIterator index, void *) + { + if (it == index) // should match. + ::iterationCount.ref(); + return false; + } +}; + +void tst_QtConcurrentIterateKernel::stresstestWhile() +{ + int iterations = 100000; + StressWhile w(iterations); + w.startBlocking(); + QCOMPARE(int(iterationCount), iterations); +} +#endif + +QTEST_MAIN(tst_QtConcurrentIterateKernel) + +#include "tst_qtconcurrentiteratekernel.moc" + +#else +QTEST_NOOP_MAIN +#endif diff --git a/tests/auto/corelib/concurrent/qtconcurrentmap/.gitignore b/tests/auto/corelib/concurrent/qtconcurrentmap/.gitignore new file mode 100644 index 0000000000..f1c563e979 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentmap/.gitignore @@ -0,0 +1 @@ +tst_qtconcurrentmap diff --git a/tests/auto/corelib/concurrent/qtconcurrentmap/functions.h b/tests/auto/corelib/concurrent/qtconcurrentmap/functions.h new file mode 100644 index 0000000000..a3dcd3c300 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentmap/functions.h @@ -0,0 +1,130 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef FUNCTIONS_H +#define FUNCTIONS_H + +bool keepEvenIntegers(const int &x) +{ + return (x & 1) == 0; +} + +class KeepEvenIntegers +{ +public: + bool operator()(const int &x) + { + return (x & 1) == 0; + } +}; + +class Number +{ + int n; + +public: + Number() + : n(0) + { } + + Number(int n) + : n(n) + { } + + void multiplyBy2() + { + n *= 2; + } + + Number multipliedBy2() const + { + return n * 2; + } + + bool isEven() const + { + return (n & 1) == 0; + } + + int toInt() const + { + return n; + } + + QString toString() const + { + return QString::number(n); + } + + bool operator==(const Number &other) const + { + return n == other.n; + } +}; + +void intSumReduce(int &sum, int x) +{ + sum += x; +} + +class IntSumReduce +{ +public: + void operator()(int &sum, int x) + { + sum += x; + } +}; + +void numberSumReduce(int &sum, const Number &x) +{ + sum += x.toInt(); +} + +class NumberSumReduce +{ +public: + void operator()(int &sum, const Number &x) + { + sum += x.toInt(); + } +}; + +#endif diff --git a/tests/auto/corelib/concurrent/qtconcurrentmap/qtconcurrentmap.pro b/tests/auto/corelib/concurrent/qtconcurrentmap/qtconcurrentmap.pro new file mode 100644 index 0000000000..6fc358514e --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentmap/qtconcurrentmap.pro @@ -0,0 +1,6 @@ +load(qttest_p4) +DEFINES += QT_STRICT_ITERATORS +SOURCES += tst_qtconcurrentmap.cpp +QT = core +CONFIG += parallel_test +CONFIG += parallel_test diff --git a/tests/auto/corelib/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp b/tests/auto/corelib/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp new file mode 100644 index 0000000000..74a254cbf4 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentmap/tst_qtconcurrentmap.cpp @@ -0,0 +1,2448 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include + +#include +#include + +#include + +#include "functions.h" +#include "../qfuture/versioncheck.h" + +Q_DECLARE_METATYPE(QVector); +Q_DECLARE_METATYPE(QVector); +Q_DECLARE_METATYPE(QVector); +Q_DECLARE_METATYPE(QList); +Q_DECLARE_METATYPE(QList); +Q_DECLARE_METATYPE(QList); + +class tst_QtConcurrentMap: public QObject +{ + Q_OBJECT +private slots: + void map(); + void blocking_map(); + void mapped(); + void blocking_mapped(); + void mappedReduced(); + void blocking_mappedReduced(); + void assignResult(); + void functionOverloads(); +#ifndef QT_NO_EXCEPTIONS + void exceptions(); +#endif + void incrementalResults(); + void noDetatch(); + void stlContainers(); + void qFutureAssignmentLeak(); + void stressTest(); +public slots: + void throttling(); +}; + +#if !defined (QT_NO_CONCURRENT_TEST) && !defined(QT_NO_CONCURRENT_MAP) + +using namespace QtConcurrent; + +void multiplyBy2Immutable(int x) +{ + x *= 2; +} + +class MultiplyBy2Immutable +{ +public: + void operator()(int x) + { + x *= 2; + } +}; + +void multiplyBy2InPlace(int &x) +{ + x *= 2; +} + +class MultiplyBy2InPlace +{ +public: + void operator()(int &x) + { + x *= 2; + } +}; + +Q_DECLARE_METATYPE(QList); + +void tst_QtConcurrentMap::map() +{ + // functors take arguments by reference, modifying the sequence in place + { + QList list; + list << 1 << 2 << 3; + + // functor + QtConcurrent::map(list, MultiplyBy2InPlace()).waitForFinished(); + QCOMPARE(list, QList() << 2 << 4 << 6); + QtConcurrent::map(list.begin(), list.end(), MultiplyBy2InPlace()).waitForFinished(); + QCOMPARE(list, QList() << 4 << 8 << 12); + + // function + QtConcurrent::map(list, multiplyBy2InPlace).waitForFinished(); + QCOMPARE(list, QList() << 8 << 16 << 24); + QtConcurrent::map(list.begin(), list.end(), multiplyBy2InPlace).waitForFinished(); + QCOMPARE(list, QList() << 16 << 32 << 48); + + // bound function + QtConcurrent::map(list, multiplyBy2InPlace).waitForFinished(); + QCOMPARE(list, QList() << 32 << 64 << 96); + QtConcurrent::map(list.begin(), list.end(), multiplyBy2InPlace).waitForFinished(); + QCOMPARE(list, QList() << 64 << 128 << 192); + + // member function + QList numberList; + numberList << 1 << 2 << 3; + QtConcurrent::map(numberList, &Number::multiplyBy2).waitForFinished(); + QCOMPARE(numberList, QList() << 2 << 4 << 6); + QtConcurrent::map(numberList.begin(), numberList.end(), &Number::multiplyBy2).waitForFinished(); + QCOMPARE(numberList, QList() << 4 << 8 << 12); + +#ifdef Q_COMPILER_LAMBDA + // lambda + QtConcurrent::map(list, [](int &x){x *= 2;}).waitForFinished(); + QCOMPARE(list, QList() << 128 << 256 << 384); + QtConcurrent::map(list.begin(), list.end(), [](int &x){x *= 2;}).waitForFinished(); + QCOMPARE(list, QList() << 256 << 512 << 768); +#endif + + } + + // functors don't take arguments by reference, making these no-ops + { + QList list; + list << 1 << 2 << 3; + + // functor + QtConcurrent::map(list, MultiplyBy2Immutable()).waitForFinished(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QtConcurrent::map(list.begin(), list.end(), MultiplyBy2Immutable()).waitForFinished(); + QCOMPARE(list, QList() << 1 << 2 << 3); + + // function + QtConcurrent::map(list, multiplyBy2Immutable).waitForFinished(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QtConcurrent::map(list.begin(), list.end(), multiplyBy2Immutable).waitForFinished(); + QCOMPARE(list, QList() << 1 << 2 << 3); + + // bound function + QtConcurrent::map(list, multiplyBy2Immutable).waitForFinished(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QtConcurrent::map(list.begin(), list.end(), multiplyBy2Immutable).waitForFinished(); + QCOMPARE(list, QList() << 1 << 2 << 3); + +#ifdef Q_COMPILER_LAMBDA + // lambda + QtConcurrent::map(list, [](int x){x *= 2;}).waitForFinished(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QtConcurrent::map(list.begin(), list.end(), [](int x){x *= 2;}).waitForFinished(); + QCOMPARE(list, QList() << 1 << 2 << 3); +#endif + } + + // Linked lists and forward iterators + { + QLinkedList list; + list << 1 << 2 << 3; + + // functor + QtConcurrent::map(list, MultiplyBy2InPlace()).waitForFinished(); + QCOMPARE(list, QLinkedList() << 2 << 4 << 6); + QtConcurrent::map(list.begin(), list.end(), MultiplyBy2InPlace()).waitForFinished(); + QCOMPARE(list, QLinkedList() << 4 << 8 << 12); + + // function + QtConcurrent::map(list, multiplyBy2InPlace).waitForFinished(); + QCOMPARE(list, QLinkedList() << 8 << 16 << 24); + QtConcurrent::map(list.begin(), list.end(), multiplyBy2InPlace).waitForFinished(); + QCOMPARE(list, QLinkedList() << 16 << 32 << 48); + + // bound function + QtConcurrent::map(list, multiplyBy2InPlace).waitForFinished(); + QCOMPARE(list, QLinkedList() << 32 << 64 << 96); + QtConcurrent::map(list.begin(), list.end(), multiplyBy2InPlace).waitForFinished(); + QCOMPARE(list, QLinkedList() << 64 << 128 << 192); + + // member function + QLinkedList numberList; + numberList << 1 << 2 << 3; + QtConcurrent::map(numberList, &Number::multiplyBy2).waitForFinished(); + QCOMPARE(numberList, QLinkedList() << 2 << 4 << 6); + QtConcurrent::map(numberList.begin(), numberList.end(), &Number::multiplyBy2).waitForFinished(); + QCOMPARE(numberList, QLinkedList() << 4 << 8 << 12); + } + +#if 0 + // not allowed: map() with immutable sequences makes no sense + { + const QList list = QList() << 1 << 2 << 3; + + QtConcurrent::map(list, MultiplyBy2Immutable()); + QtConcurrent::map(list, multiplyBy2Immutable); + QtConcurrent::map(list, multiplyBy2Immutable); + } +#endif + +#if 0 + // not allowed: in place modification of a temp copy (since temp copy goes out of scope) + { + QList list; + list << 1 << 2 << 3; + + QtConcurrent::map(QList(list), MultiplyBy2InPlace()); + QtConcurrent::map(QList(list), multiplyBy2); + QtConcurrent::map(QList(list), multiplyBy2InPlace); + + QList numberList; + numberList << 1 << 2 << 3; + QtConcurrent::map(QList(numberList), &Number::multiplyBy2); + } +#endif + +#if 0 + // not allowed: map() on a const list, where functors try to modify the items in the list + { + const QList list = QList() << 1 << 2 << 3;; + + QtConcurrent::map(list, MultiplyBy2InPlace()); + QtConcurrent::map(list, multiplyBy2InPlace); + QtConcurrent::map(list, multiplyBy2InPlace); + + const QList numberList = QList() << 1 << 2 << 3; + QtConcurrent::map(numberList, &Number::multiplyBy2); + } +#endif +} + +void tst_QtConcurrentMap::blocking_map() +{ + // functors take arguments by reference, modifying the sequence in place + { + QList list; + list << 1 << 2 << 3; + + // functor + QtConcurrent::blockingMap(list, MultiplyBy2InPlace()); + QCOMPARE(list, QList() << 2 << 4 << 6); + QtConcurrent::blockingMap(list.begin(), list.end(), MultiplyBy2InPlace()); + QCOMPARE(list, QList() << 4 << 8 << 12); + + // function + QtConcurrent::blockingMap(list, multiplyBy2InPlace); + QCOMPARE(list, QList() << 8 << 16 << 24); + QtConcurrent::blockingMap(list.begin(), list.end(), multiplyBy2InPlace); + QCOMPARE(list, QList() << 16 << 32 << 48); + + // bound function + QtConcurrent::blockingMap(list, multiplyBy2InPlace); + QCOMPARE(list, QList() << 32 << 64 << 96); + QtConcurrent::blockingMap(list.begin(), list.end(), multiplyBy2InPlace); + QCOMPARE(list, QList() << 64 << 128 << 192); + + // member function + QList numberList; + numberList << 1 << 2 << 3; + QtConcurrent::blockingMap(numberList, &Number::multiplyBy2); + QCOMPARE(numberList, QList() << 2 << 4 << 6); + QtConcurrent::blockingMap(numberList.begin(), numberList.end(), &Number::multiplyBy2); + QCOMPARE(numberList, QList() << 4 << 8 << 12); + } + + // functors don't take arguments by reference, making these no-ops + { + QList list; + list << 1 << 2 << 3; + + // functor + QtConcurrent::blockingMap(list, MultiplyBy2Immutable()); + QCOMPARE(list, QList() << 1 << 2 << 3); + QtConcurrent::blockingMap(list.begin(), list.end(), MultiplyBy2Immutable()); + QCOMPARE(list, QList() << 1 << 2 << 3); + + // function + QtConcurrent::blockingMap(list, multiplyBy2Immutable); + QCOMPARE(list, QList() << 1 << 2 << 3); + QtConcurrent::blockingMap(list.begin(), list.end(), multiplyBy2Immutable); + QCOMPARE(list, QList() << 1 << 2 << 3); + + // bound function + QtConcurrent::blockingMap(list, multiplyBy2Immutable); + QCOMPARE(list, QList() << 1 << 2 << 3); + QtConcurrent::blockingMap(list.begin(), list.end(), multiplyBy2Immutable); + QCOMPARE(list, QList() << 1 << 2 << 3); + } + + // Linked lists and forward iterators + { + QLinkedList list; + list << 1 << 2 << 3; + + // functor + QtConcurrent::blockingMap(list, MultiplyBy2InPlace()); + QCOMPARE(list, QLinkedList() << 2 << 4 << 6); + QtConcurrent::blockingMap(list.begin(), list.end(), MultiplyBy2InPlace()); + QCOMPARE(list, QLinkedList() << 4 << 8 << 12); + + // function + QtConcurrent::blockingMap(list, multiplyBy2InPlace); + QCOMPARE(list, QLinkedList() << 8 << 16 << 24); + QtConcurrent::blockingMap(list.begin(), list.end(), multiplyBy2InPlace); + QCOMPARE(list, QLinkedList() << 16 << 32 << 48); + + // bound function + QtConcurrent::blockingMap(list, multiplyBy2InPlace); + QCOMPARE(list, QLinkedList() << 32 << 64 << 96); + QtConcurrent::blockingMap(list.begin(), list.end(), multiplyBy2InPlace); + QCOMPARE(list, QLinkedList() << 64 << 128 << 192); + + // member function + QLinkedList numberList; + numberList << 1 << 2 << 3; + QtConcurrent::blockingMap(numberList, &Number::multiplyBy2); + QCOMPARE(numberList, QLinkedList() << 2 << 4 << 6); + QtConcurrent::blockingMap(numberList.begin(), numberList.end(), &Number::multiplyBy2); + QCOMPARE(numberList, QLinkedList() << 4 << 8 << 12); + } + +#if 0 + // not allowed: map() with immutable sequences makes no sense + { + const QList list = QList() << 1 << 2 << 3; + + QtConcurrent::blockingMap(list, MultiplyBy2Immutable()); + QtConcurrent::blockkng::map(list, multiplyBy2Immutable); + QtConcurrent::blockingMap(list, multiplyBy2Immutable); + } +#endif + +#if 0 + // not allowed: in place modification of a temp copy (since temp copy goes out of scope) + { + QList list; + list << 1 << 2 << 3; + + QtConcurrent::blockingMap(QList(list), MultiplyBy2InPlace()); + QtConcurrent::blockingMap(QList(list), multiplyBy2); + QtConcurrent::blockingMap(QList(list), multiplyBy2InPlace); + + QList numberList; + numberList << 1 << 2 << 3; + QtConcurrent::blockingMap(QList(numberList), &Number::multiplyBy2); + } +#endif + +#if 0 + // not allowed: map() on a const list, where functors try to modify the items in the list + { + const QList list = QList() << 1 << 2 << 3;; + + QtConcurrent::blockingMap(list, MultiplyBy2InPlace()); + QtConcurrent::blockingMap(list, multiplyBy2InPlace); + QtConcurrent::blockingMap(list, multiplyBy2InPlace); + + const QList numberList = QList() << 1 << 2 << 3; + QtConcurrent::blockingMap(numberList, &Number::multiplyBy2); + } +#endif +} + +int multiplyBy2(int x) +{ + int y = x * 2; + return y; +} + +class MultiplyBy2 +{ +public: + typedef int result_type; + + int operator()(int x) const + { + int y = x * 2; + return y; + } +}; + +double intToDouble(int x) +{ + return double(x); +} + +class IntToDouble +{ +public: + typedef double result_type; + + double operator()(int x) const + { + return double(x); + } +}; + +int stringToInt(const QString &string) +{ + return string.toInt(); +} + +class StringToInt +{ +public: + typedef int result_type; + + int operator()(const QString &string) const + { + return string.toInt(); + } +}; + +void tst_QtConcurrentMap::mapped() +{ + QList list; + list << 1 << 2 << 3; + QLinkedList linkedList; + linkedList << 1 << 2 << 3; + QList numberList; + numberList << 1 << 2 << 3; + QLinkedList numberLinkedList; + numberLinkedList << 1 << 2 << 3; + + // functor + { + QList list2 = QtConcurrent::mapped(list, MultiplyBy2()).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 2 << 4 << 6); + + QList list3 = QtConcurrent::mapped(list.constBegin(), + list.constEnd(), + MultiplyBy2()).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 2 << 4 << 6); + + QList list4 = QtConcurrent::mapped(QList(list), MultiplyBy2()).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 2 << 4 << 6); + } + { + QList list2 = QtConcurrent::mapped(linkedList, MultiplyBy2()).results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 2 << 4 << 6); + + QList list3 = QtConcurrent::mapped(linkedList.constBegin(), + linkedList.constEnd(), + MultiplyBy2()).results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 2 << 4 << 6); + + QList list4 = + QtConcurrent::mapped(QLinkedList(linkedList), MultiplyBy2()).results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 2 << 4 << 6); + } + + // function + { + QList list2 = QtConcurrent::mapped(list, multiplyBy2).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 2 << 4 << 6); + + QList list3 = QtConcurrent::mapped(list.constBegin(), + list.constEnd(), + multiplyBy2).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 2 << 4 << 6); + + QList list4 = QtConcurrent::mapped(QList(list), multiplyBy2).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 2 << 4 << 6); + } + { + QList list2 = QtConcurrent::mapped(linkedList, multiplyBy2).results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 2 << 4 << 6); + + QList list3 = QtConcurrent::mapped(linkedList.constBegin(), + linkedList.constEnd(), + multiplyBy2).results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 2 << 4 << 6); + + QList list4 = + QtConcurrent::mapped(QLinkedList(linkedList), multiplyBy2).results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 2 << 4 << 6); + } + + // bound function + { + QList list2 = QtConcurrent::mapped(list, multiplyBy2).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 2 << 4 << 6); + + QList list3 = QtConcurrent::mapped(list.constBegin(), + list.constEnd(), + multiplyBy2).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 2 << 4 << 6); + + QList list4 = QtConcurrent::mapped(QList(list), multiplyBy2).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 2 << 4 << 6); + } + { + QList list2 = QtConcurrent::mapped(linkedList, multiplyBy2).results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 2 << 4 << 6); + + QList list3 = QtConcurrent::mapped(linkedList.constBegin(), + linkedList.constEnd(), + multiplyBy2) + .results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 2 << 4 << 6); + + QList list4 = QtConcurrent::mapped(QLinkedList(linkedList), multiplyBy2) + .results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 2 << 4 << 6); + } + + // const member function + { + QList numberList2 = QtConcurrent::mapped(numberList, &Number::multipliedBy2) + .results(); + QCOMPARE(numberList, QList() << 1 << 2 << 3); + QCOMPARE(numberList2, QList() << 2 << 4 << 6); + + QList numberList3 = QtConcurrent::mapped(numberList.constBegin(), + numberList.constEnd(), + &Number::multipliedBy2) + .results(); + QCOMPARE(numberList, QList() << 1 << 2 << 3); + QCOMPARE(numberList3, QList() << 2 << 4 << 6); + + QList numberList4 = QtConcurrent::mapped(QList(numberList), + &Number::multipliedBy2) + .results(); + QCOMPARE(numberList, QList() << 1 << 2 << 3); + QCOMPARE(numberList4, QList() << 2 << 4 << 6); + } + { + QList numberList2 = QtConcurrent::mapped(numberLinkedList, &Number::multipliedBy2) + .results(); + QCOMPARE(numberLinkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(numberList2, QList() << 2 << 4 << 6); + + QList numberList3 = QtConcurrent::mapped(numberLinkedList.constBegin(), + numberLinkedList.constEnd(), + &Number::multipliedBy2) + .results(); + QCOMPARE(numberLinkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(numberList3, QList() << 2 << 4 << 6); + + QList numberList4 = QtConcurrent::mapped(QLinkedList(numberLinkedList), + &Number::multipliedBy2) + .results(); + QCOMPARE(numberLinkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(numberList4, QList() << 2 << 4 << 6); + } + + // change the value_type, same container + + // functor + { + QList list2 = QtConcurrent::mapped(list, IntToDouble()).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 1.0 << 2.0 << 3.0); + + QList list3 = QtConcurrent::mapped(list.constBegin(), + list.constEnd(), + IntToDouble()) + .results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 1.0 << 2.0 << 3.0); + + QList list4 = QtConcurrent::mapped(QList(list), + IntToDouble()) + .results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 1.0 << 2.0 << 3.0); + } + { + QList list2 = QtConcurrent::mapped(linkedList, IntToDouble()).results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 1.0 << 2.0 << 3.0); + + QList list3 = QtConcurrent::mapped(linkedList.constBegin(), + linkedList.constEnd(), + IntToDouble()) + .results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 1.0 << 2.0 << 3.0); + + QList list4 = QtConcurrent::mapped(QLinkedList(linkedList), + IntToDouble()) + .results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 1.0 << 2.0 << 3.0); + } + + // function + { + QList list2 = QtConcurrent::mapped(list, intToDouble).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 1.0 << 2.0 << 3.0); + + QList list3 = QtConcurrent::mapped(list.constBegin(), + list.constEnd(), + intToDouble) + .results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 1.0 << 2.0 << 3.0); + + QList list4 = QtConcurrent::mapped(QList(list), intToDouble).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 1.0 << 2.0 << 3.0); + } + { + QList list2 = QtConcurrent::mapped(linkedList, intToDouble).results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 1.0 << 2.0 << 3.0); + + QList list3 = QtConcurrent::mapped(linkedList.constBegin(), + linkedList.constEnd(), + intToDouble) + .results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 1.0 << 2.0 << 3.0); + + QList list4 = QtConcurrent::mapped(QLinkedList(linkedList), intToDouble) + .results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 1.0 << 2.0 << 3.0); + } + + // bound function + { + QList list2 = QtConcurrent::mapped(list, intToDouble).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 1.0 << 2.0 << 3.0); + + QList list3 = QtConcurrent::mapped(list.constBegin(), + list.constEnd(), + intToDouble) + .results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 1.0 << 2.0 << 3.0); + + + QList list4 = QtConcurrent::mapped(QList(list), + intToDouble) + .results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 1.0 << 2.0 << 3.0); + } + { + QList list2 = QtConcurrent::mapped(linkedList, intToDouble).results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 1.0 << 2.0 << 3.0); + + QList list3 = QtConcurrent::mapped(linkedList.constBegin(), + linkedList.constEnd(), + intToDouble) + .results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 1.0 << 2.0 << 3.0); + + + QList list4 = QtConcurrent::mapped(QLinkedList(linkedList), + intToDouble) + .results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 1.0 << 2.0 << 3.0); + } + + // const member function + { + QList list2 = QtConcurrent::mapped(numberList, &Number::toString).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << "1" << "2" << "3"); + + QList list3 = QtConcurrent::mapped(numberList.constBegin(), + numberList.constEnd(), + &Number::toString) + .results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << "1" << "2" << "3"); + + QList list4 = QtConcurrent::mapped(QList(numberList), &Number::toString) + .results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << "1" << "2" << "3"); + } + { + QList list2 = QtConcurrent::mapped(numberLinkedList, &Number::toString).results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << "1" << "2" << "3"); + + QList list3 = QtConcurrent::mapped(numberLinkedList.constBegin(), + numberLinkedList.constEnd(), + &Number::toString) + .results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << "1" << "2" << "3"); + + QList list4 = QtConcurrent::mapped(QLinkedList(numberLinkedList), + &Number::toString) + .results(); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << "1" << "2" << "3"); + } + + // change the value_type + { + QList strings = QStringList() << "1" << "2" << "3"; + QList list = QtConcurrent::mapped(strings, StringToInt()).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + + QList list2 = QtConcurrent::mapped(strings.constBegin(), + strings.constEnd(), + StringToInt()) + .results(); + QCOMPARE(list2, QList() << 1 << 2 << 3); + } + { + QList strings = QStringList() << "1" << "2" << "3"; + QList list = QtConcurrent::mapped(strings, stringToInt).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + + QList list2 = QtConcurrent::mapped(strings.constBegin(), + strings.constEnd(), + stringToInt).results(); + QCOMPARE(list2, QList() << 1 << 2 << 3); + } + + { + QList numberList2 = QtConcurrent::mapped(numberList, &Number::toInt).results(); + QCOMPARE(numberList2, QList() << 1 << 2 << 3); + + QList numberList3 = QtConcurrent::mapped(numberList.constBegin(), + numberList.constEnd(), + &Number::toInt) + .results(); + QCOMPARE(numberList3, QList() << 1 << 2 << 3); + } + + // change the value_type from QStringList + { + QStringList strings = QStringList() << "1" << "2" << "3"; + QList list = QtConcurrent::mapped(strings, StringToInt()).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + + QList list2 = QtConcurrent::mapped(strings.constBegin(), + strings.constEnd(), + StringToInt()) + .results(); + QCOMPARE(list2, QList() << 1 << 2 << 3); + } + { + QStringList strings = QStringList() << "1" << "2" << "3"; + QList list = QtConcurrent::mapped(strings, stringToInt).results(); + QCOMPARE(list, QList() << 1 << 2 << 3); + + QList list2 = QtConcurrent::mapped(strings.constBegin(), + strings.constEnd(), + stringToInt) + .results(); + QCOMPARE(list2, QList() << 1 << 2 << 3); + } +} + +void tst_QtConcurrentMap::blocking_mapped() +{ + QList list; + list << 1 << 2 << 3; + QLinkedList linkedList; + linkedList << 1 << 2 << 3; + QList numberList; + numberList << 1 << 2 << 3; + QLinkedList numberLinkedList; + numberLinkedList << 1 << 2 << 3; + + // functor + { + QList list2 = QtConcurrent::blockingMapped(list, MultiplyBy2()); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 2 << 4 << 6); + + QList list3 = QtConcurrent::blockingMapped >(list.constBegin(), + list.constEnd(), + MultiplyBy2()); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 2 << 4 << 6); + + QList list4 = QtConcurrent::blockingMapped(QList(list), MultiplyBy2()); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 2 << 4 << 6); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingMapped(linkedList, MultiplyBy2()); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4 << 6); + + QLinkedList linkedList3 = QtConcurrent::blockingMapped >(linkedList.constBegin(), + linkedList.constEnd(), + MultiplyBy2()); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList3, QLinkedList() << 2 << 4 << 6); + + QLinkedList linkedList4 = QtConcurrent::blockingMapped(QLinkedList(linkedList), MultiplyBy2()); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList4, QLinkedList() << 2 << 4 << 6); + } + + // function + { + QList list2 = QtConcurrent::blockingMapped(list, multiplyBy2); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 2 << 4 << 6); + + QList list3 = QtConcurrent::blockingMapped >(list.constBegin(), + list.constEnd(), + multiplyBy2); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 2 << 4 << 6); + + QList list4 = QtConcurrent::blockingMapped(QList(list), multiplyBy2); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 2 << 4 << 6); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingMapped(linkedList, multiplyBy2); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4 << 6); + + QLinkedList linkedList3 = QtConcurrent::blockingMapped >(linkedList.constBegin(), + linkedList.constEnd(), + multiplyBy2); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList3, QLinkedList() << 2 << 4 << 6); + + QLinkedList linkedList4 = QtConcurrent::blockingMapped(QLinkedList(linkedList), multiplyBy2); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList4, QLinkedList() << 2 << 4 << 6); + } + + // bound function + { + QList list2 = QtConcurrent::blockingMapped(list, multiplyBy2); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 2 << 4 << 6); + + QList list3 = QtConcurrent::blockingMapped >(list.constBegin(), + list.constEnd(), + multiplyBy2); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 2 << 4 << 6); + + QList list4 = QtConcurrent::blockingMapped(QList(list), multiplyBy2); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 2 << 4 << 6); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingMapped(linkedList, multiplyBy2); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList2, QLinkedList() << 2 << 4 << 6); + + QLinkedList linkedList3 = QtConcurrent::blockingMapped >(linkedList.constBegin(), + linkedList.constEnd(), + multiplyBy2); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList3, QLinkedList() << 2 << 4 << 6); + + QLinkedList linkedList4 = QtConcurrent::blockingMapped(QLinkedList(linkedList), multiplyBy2); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList4, QLinkedList() << 2 << 4 << 6); + } + + // const member function + { + QList numberList2 = QtConcurrent::blockingMapped(numberList, &Number::multipliedBy2); + QCOMPARE(numberList, QList() << 1 << 2 << 3); + QCOMPARE(numberList2, QList() << 2 << 4 << 6); + + QList numberList3 = QtConcurrent::blockingMapped >(numberList.constBegin(), + numberList.constEnd(), + &Number::multipliedBy2); + QCOMPARE(numberList, QList() << 1 << 2 << 3); + QCOMPARE(numberList3, QList() << 2 << 4 << 6); + + QList numberList4 = QtConcurrent::blockingMapped(QList(numberList), + &Number::multipliedBy2); + QCOMPARE(numberList, QList() << 1 << 2 << 3); + QCOMPARE(numberList4, QList() << 2 << 4 << 6); + } + { + QLinkedList numberLinkedList2 = QtConcurrent::blockingMapped(numberLinkedList, &Number::multipliedBy2); + QCOMPARE(numberLinkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(numberLinkedList2, QLinkedList() << 2 << 4 << 6); + + QLinkedList numberLinkedList3 = QtConcurrent::blockingMapped >(numberLinkedList.constBegin(), + numberLinkedList.constEnd(), + &Number::multipliedBy2); + QCOMPARE(numberLinkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(numberLinkedList3, QLinkedList() << 2 << 4 << 6); + + QLinkedList numberLinkedList4 = QtConcurrent::blockingMapped(QLinkedList(numberLinkedList), + &Number::multipliedBy2); + QCOMPARE(numberLinkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(numberLinkedList4, QLinkedList() << 2 << 4 << 6); + } + + // change the value_type, same container + + // functor + { + QList list2 = QtConcurrent::blockingMapped >(list, IntToDouble()); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 1.0 << 2.0 << 3.0); + + QList list3 = QtConcurrent::blockingMapped >(list.constBegin(), + list.constEnd(), + IntToDouble()); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 1.0 << 2.0 << 3.0); + + QList list4 = QtConcurrent::blockingMapped >(QList(list), + IntToDouble()); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 1.0 << 2.0 << 3.0); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingMapped >(linkedList, IntToDouble()); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList2, QLinkedList() << 1.0 << 2.0 << 3.0); + + QLinkedList linkedList3 = QtConcurrent::blockingMapped >(linkedList.constBegin(), + linkedList.constEnd(), + IntToDouble()); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList3, QLinkedList() << 1.0 << 2.0 << 3.0); + + QLinkedList linkedList4 = QtConcurrent::blockingMapped >(QLinkedList(linkedList), + IntToDouble()); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList4, QLinkedList() << 1.0 << 2.0 << 3.0); + } + + // function + { + QList list2 = QtConcurrent::blockingMapped >(list, intToDouble); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 1.0 << 2.0 << 3.0); + + QList list3 = QtConcurrent::blockingMapped >(list.constBegin(), + list.constEnd(), + intToDouble); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 1.0 << 2.0 << 3.0); + + QList list4 = QtConcurrent::blockingMapped >(QList(list), intToDouble); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 1.0 << 2.0 << 3.0); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingMapped >(linkedList, intToDouble); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList2, QLinkedList() << 1.0 << 2.0 << 3.0); + + QLinkedList linkedList3 = QtConcurrent::blockingMapped >(linkedList.constBegin(), + linkedList.constEnd(), + intToDouble); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList3, QLinkedList() << 1.0 << 2.0 << 3.0); + + QLinkedList linkedList4 = QtConcurrent::blockingMapped >(QLinkedList(linkedList), intToDouble); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList4, QLinkedList() << 1.0 << 2.0 << 3.0); + } + + // bound function + { + QList list2 = QtConcurrent::blockingMapped >(list, intToDouble); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 1.0 << 2.0 << 3.0); + + QList list3 = QtConcurrent::blockingMapped >(list.constBegin(), + list.constEnd(), + intToDouble); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 1.0 << 2.0 << 3.0); + + + QList list4 = QtConcurrent::blockingMapped >(QList(list), + intToDouble); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 1.0 << 2.0 << 3.0); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingMapped >(linkedList, intToDouble); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList2, QLinkedList() << 1.0 << 2.0 << 3.0); + + QLinkedList linkedList3 = QtConcurrent::blockingMapped >(linkedList.constBegin(), + linkedList.constEnd(), + intToDouble); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList3, QLinkedList() << 1.0 << 2.0 << 3.0); + + + QLinkedList linkedList4 = QtConcurrent::blockingMapped >(QLinkedList(linkedList), + intToDouble); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList4, QLinkedList() << 1.0 << 2.0 << 3.0); + } + + // const member function + { + QList list2 = + QtConcurrent::blockingMapped >(numberList, &Number::toString); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << "1" << "2" << "3"); + + QList list3 = QtConcurrent::blockingMapped >(numberList.constBegin(), + numberList.constEnd() + , &Number::toString); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << "1" << "2" << "3"); + + QList list4 = + QtConcurrent::blockingMapped >(QList(numberList), &Number::toString); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << "1" << "2" << "3"); + } + { + QLinkedList linkedList2 = + QtConcurrent::blockingMapped >(numberLinkedList, &Number::toString); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList2, QLinkedList() << "1" << "2" << "3"); + + QLinkedList linkedList3 = QtConcurrent::blockingMapped >(numberLinkedList.constBegin(), + numberLinkedList.constEnd() + , &Number::toString); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList3, QLinkedList() << "1" << "2" << "3"); + + QLinkedList linkedList4 = + QtConcurrent::blockingMapped >(QLinkedList(numberLinkedList), &Number::toString); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList4, QLinkedList() << "1" << "2" << "3"); + } + + // change the value_type + { + QList strings = QStringList() << "1" << "2" << "3"; + QList list = QtConcurrent::blockingMapped(strings, StringToInt()); + QCOMPARE(list, QList() << 1 << 2 << 3); + + QList list2 = QtConcurrent::blockingMapped >(strings.constBegin(), + strings.constEnd(), + StringToInt()); + QCOMPARE(list2, QList() << 1 << 2 << 3); + } + { + QList strings = QStringList() << "1" << "2" << "3"; + QList list = QtConcurrent::blockingMapped(strings, stringToInt); + QCOMPARE(list, QList() << 1 << 2 << 3); + + QList list2 = QtConcurrent::blockingMapped >(strings.constBegin(), + strings.constEnd(), + stringToInt); + QCOMPARE(list2, QList() << 1 << 2 << 3); + } + + { + QList numberList2 = QtConcurrent::blockingMapped(numberList, &Number::toInt); + QCOMPARE(numberList2, QList() << 1 << 2 << 3); + + QList numberList3 = QtConcurrent::blockingMapped >(numberList.constBegin(), + numberList.constEnd(), + &Number::toInt); + QCOMPARE(numberList3, QList() << 1 << 2 << 3); + } + + // change the value_type from QStringList + { + QStringList strings = QStringList() << "1" << "2" << "3"; + QList list = QtConcurrent::blockingMapped(strings, StringToInt()); + QCOMPARE(list, QList() << 1 << 2 << 3); + + QList list2 = QtConcurrent::blockingMapped >(strings.constBegin(), + strings.constEnd(), + StringToInt()); + QCOMPARE(list2, QList() << 1 << 2 << 3); + } + { + QStringList strings = QStringList() << "1" << "2" << "3"; + QList list = QtConcurrent::blockingMapped(strings, stringToInt); + QCOMPARE(list, QList() << 1 << 2 << 3); + + QList list2 = QtConcurrent::blockingMapped >(strings.constBegin(), + strings.constEnd(), + stringToInt); + QCOMPARE(list2, QList() << 1 << 2 << 3); + } + + // functor + { + QVector list2 = QtConcurrent::blockingMapped >(list, IntToDouble()); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QVector() << 1.0 << 2.0 << 3.0); + + QVector list3 = QtConcurrent::blockingMapped >(list.constBegin(), + list.constEnd(), + IntToDouble()); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QVector() << 1.0 << 2.0 << 3.0); + + QVector list4 = QtConcurrent::blockingMapped >(QList(list), + IntToDouble()); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QVector() << 1.0 << 2.0 << 3.0); + + QStringList strings = QStringList() << "1" << "2" << "3"; + QVector list5 = QtConcurrent::blockingMapped >(strings, StringToInt()); + QCOMPARE(list5, QVector() << 1 << 2 << 3); + + QVector list6 = QtConcurrent::blockingMapped >(strings.constBegin(), + strings.constEnd(), + StringToInt()); + QCOMPARE(list6, QVector() << 1 << 2 << 3); + + QVector list7 = QtConcurrent::blockingMapped >(QStringList(strings), + StringToInt()); + QCOMPARE(list7, QVector() << 1 << 2 << 3); + } + + // function + { + QVector list2 = QtConcurrent::blockingMapped >(list, intToDouble); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QVector() << 1.0 << 2.0 << 3.0); + + QVector list3 = QtConcurrent::blockingMapped >(list.constBegin(), + list.constEnd(), + intToDouble); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QVector() << 1.0 << 2.0 << 3.0); + + QVector list4 = QtConcurrent::blockingMapped >(QList(list), + intToDouble); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QVector() << 1.0 << 2.0 << 3.0); + + QStringList strings = QStringList() << "1" << "2" << "3"; + QVector list5 = QtConcurrent::blockingMapped >(strings, stringToInt); + QCOMPARE(list5, QVector() << 1 << 2 << 3); + + QVector list6 = QtConcurrent::blockingMapped >(strings.constBegin(), + strings.constEnd(), + stringToInt); + QCOMPARE(list6, QVector() << 1 << 2 << 3); + + QVector list7 = QtConcurrent::blockingMapped >(QStringList(strings), + stringToInt); + QCOMPARE(list7, QVector() << 1 << 2 << 3); + } + + // bound function + { + QVector list2 = QtConcurrent::blockingMapped >(list, intToDouble); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QVector() << 1.0 << 2.0 << 3.0); + + QVector list3 = QtConcurrent::blockingMapped >(QList(list), intToDouble); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QVector() << 1.0 << 2.0 << 3.0); + + QStringList strings = QStringList() << "1" << "2" << "3"; + QVector list4 = QtConcurrent::blockingMapped >(strings, stringToInt); + QCOMPARE(list4, QVector() << 1 << 2 << 3); + + QVector list5 = QtConcurrent::blockingMapped >(QStringList(strings), stringToInt); + QCOMPARE(list5, QVector() << 1 << 2 << 3); + } + + // const member function + { + QVector list2 = QtConcurrent::blockingMapped >(numberList, &Number::toString); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QVector() << "1" << "2" << "3"); + + QVector list3 = + QtConcurrent::blockingMapped >(QList(numberList), &Number::toString); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QVector() << "1" << "2" << "3"); + + // not allowed: const member function where all arguments have default values +#if 0 + QStringList strings = QStringList() << "1" << "2" << "3"; + QVector list4 = QtConcurrent::blockingMapped >(strings, &QString::toInt); + QCOMPARE(list4, QVector() << 1 << 2 << 3); + + QVector list5 = QtConcurrent::blockingMapped >(QStringList(strings), &QString::toInt); + QCOMPARE(list5, QVector() << 1 << 2 << 3); +#endif + } +} + +int intSquare(int x) +{ + return x * x; +} + +class IntSquare +{ +public: + typedef int result_type; + + int operator()(int x) + { + return x * x; + } +}; + +void tst_QtConcurrentMap::mappedReduced() +{ + QList list; + list << 1 << 2 << 3; + QLinkedList linkedList; + linkedList << 1 << 2 << 3; + QList numberList; + numberList << 1 << 2 << 3; + QLinkedList numberLinkedList; + numberLinkedList << 1 << 2 << 3; + + // test Q_DECLARE_OPERATORS_FOR_FLAGS + QtConcurrent::ReduceOptions opt = (QtConcurrent::UnorderedReduce | QtConcurrent::SequentialReduce); + + // functor-functor + { + int sum = QtConcurrent::mappedReduced(list, IntSquare(), IntSumReduce()); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::mappedReduced(list.constBegin(), + list.constEnd(), + IntSquare(), + IntSumReduce()); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::mappedReduced(QList(list), IntSquare(), IntSumReduce()); + QCOMPARE(sum3, 14); + + int sum4 = QtConcurrent::mappedReduced(list, intSquare, intSumReduce); + QCOMPARE(sum4, 14); + int sum5 = QtConcurrent::mappedReduced(list.constBegin(), + list.constEnd(), + intSquare, + intSumReduce); + QCOMPARE(sum5, 14); + + int sum6 = QtConcurrent::mappedReduced(QList(list), + intSquare, + intSumReduce); + QCOMPARE(sum6, 14); + } + { + int sum = QtConcurrent::mappedReduced(linkedList, IntSquare(), IntSumReduce()); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::mappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + IntSquare(), + IntSumReduce()); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::mappedReduced(QLinkedList(linkedList), IntSquare(), IntSumReduce()); + QCOMPARE(sum3, 14); + + int sum4 = QtConcurrent::mappedReduced(linkedList, intSquare, intSumReduce); + QCOMPARE(sum4, 14); + int sum5 = QtConcurrent::mappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + intSquare, + intSumReduce); + QCOMPARE(sum5, 14); + + int sum6 = QtConcurrent::mappedReduced(QLinkedList(linkedList), + intSquare, + intSumReduce); + QCOMPARE(sum6, 14); + } + + // function-functor + { + int sum = QtConcurrent::mappedReduced(list, intSquare, IntSumReduce()); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::mappedReduced(list.constBegin(), + list.constEnd(), + intSquare, + IntSumReduce()); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::mappedReduced(QList(list), intSquare, IntSumReduce()); + QCOMPARE(sum3, 14); + } + { + int sum = QtConcurrent::mappedReduced(linkedList, intSquare, IntSumReduce()); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::mappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + intSquare, + IntSumReduce()); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::mappedReduced(QLinkedList(linkedList), intSquare, IntSumReduce()); + QCOMPARE(sum3, 14); + } + + // functor-function + { + int sum = QtConcurrent::mappedReduced(list, IntSquare(), intSumReduce); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::mappedReduced(list.constBegin(), + list.constEnd(), + IntSquare(), + intSumReduce); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::mappedReduced(QList(list), IntSquare(), intSumReduce); + QCOMPARE(sum3, 14); + } + { + int sum = QtConcurrent::mappedReduced(linkedList, IntSquare(), intSumReduce); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::mappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + IntSquare(), + intSumReduce); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::mappedReduced(QLinkedList(linkedList), IntSquare(), intSumReduce); + QCOMPARE(sum3, 14); + } + + // function-function + { + int sum = QtConcurrent::mappedReduced(list, intSquare, intSumReduce); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::mappedReduced(list.constBegin(), + list.constEnd(), + intSquare, + intSumReduce); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::mappedReduced(QList(list), intSquare, intSumReduce); + QCOMPARE(sum3, 14); + } + { + int sum = QtConcurrent::mappedReduced(linkedList, intSquare, intSumReduce); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::mappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + intSquare, + intSumReduce); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::mappedReduced(QLinkedList(linkedList), intSquare, intSumReduce); + QCOMPARE(sum3, 14); + } + + // functor-member + { + QList list2 = QtConcurrent::mappedReduced(list, + IntSquare(), + &QList::push_back, + OrderedReduce); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 1 << 4 << 9); + + QList list3 = QtConcurrent::mappedReduced(list.constBegin(), + list.constEnd(), + IntSquare(), + &QList::push_back, + OrderedReduce); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 1 << 4 << 9); + + QList list4 = QtConcurrent::mappedReduced(QList(list), + IntSquare(), + &QList::push_back, + OrderedReduce); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 1 << 4 << 9); + } + { + QLinkedList linkedList2 = QtConcurrent::mappedReduced(linkedList, + IntSquare(), + &QLinkedList::push_back, + OrderedReduce); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList2, QLinkedList() << 1 << 4 << 9); + + QLinkedList linkedList3 = QtConcurrent::mappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + IntSquare(), + &QLinkedList::push_back, + OrderedReduce); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList3, QLinkedList() << 1 << 4 << 9); + + QLinkedList linkedList4 = QtConcurrent::mappedReduced(QLinkedList(linkedList), + IntSquare(), + &QLinkedList::push_back, + OrderedReduce); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList4, QLinkedList() << 1 << 4 << 9); + } + + // member-functor + { + int sum = QtConcurrent::mappedReduced(numberList, &Number::toInt, IntSumReduce()); + QCOMPARE(sum, 6); + int sum2 = QtConcurrent::mappedReduced(numberList.constBegin(), + numberList.constEnd(), + &Number::toInt, + IntSumReduce()); + QCOMPARE(sum2, 6); + + int sum3 = QtConcurrent::mappedReduced(QList(numberList), + &Number::toInt, + IntSumReduce()); + QCOMPARE(sum3, 6); + } + { + int sum = QtConcurrent::mappedReduced(numberLinkedList, &Number::toInt, IntSumReduce()); + QCOMPARE(sum, 6); + int sum2 = QtConcurrent::mappedReduced(numberLinkedList.constBegin(), + numberLinkedList.constEnd(), + &Number::toInt, + IntSumReduce()); + QCOMPARE(sum2, 6); + + int sum3 = QtConcurrent::mappedReduced(QLinkedList(numberLinkedList), + &Number::toInt, + IntSumReduce()); + QCOMPARE(sum3, 6); + } + + // member-member + { + QList list2 = QtConcurrent::mappedReduced(numberList, + &Number::toInt, + &QList::push_back, + OrderedReduce); + QCOMPARE(list2, QList() << 1 << 2 << 3); + + QList list3 = QtConcurrent::mappedReduced(numberList.constBegin(), + numberList.constEnd(), + &Number::toInt, + &QList::push_back, + OrderedReduce); + QCOMPARE(list3, QList() << 1 << 2 << 3); + + QList list4 = QtConcurrent::mappedReduced(QList(numberList), + &Number::toInt, + &QList::push_back, OrderedReduce); + QCOMPARE(list4, QList() << 1 << 2 << 3); + } + { + QLinkedList linkedList2 = QtConcurrent::mappedReduced(numberLinkedList, + &Number::toInt, + &QLinkedList::push_back, + OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 1 << 2 << 3); + + QLinkedList linkedList3 = QtConcurrent::mappedReduced(numberLinkedList.constBegin(), + numberLinkedList.constEnd(), + &Number::toInt, + &QLinkedList::push_back, + OrderedReduce); + QCOMPARE(linkedList3, QLinkedList() << 1 << 2 << 3); + + QLinkedList linkedList4 = QtConcurrent::mappedReduced(QLinkedList(numberLinkedList), + &Number::toInt, + &QLinkedList::push_back, OrderedReduce); + QCOMPARE(linkedList4, QLinkedList() << 1 << 2 << 3); + } + + // function-member + { + QList list2 = QtConcurrent::mappedReduced(list, + intSquare, + &QList::push_back, + OrderedReduce); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 1 << 4 << 9); + + QList list3 = QtConcurrent::mappedReduced(list.constBegin(), + list.constEnd(), + intSquare, + &QList::push_back, + OrderedReduce); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 1 << 4 << 9); + + QList list4 = QtConcurrent::mappedReduced(QList(list), + intSquare, + &QList::push_back, + OrderedReduce); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 1 << 4 << 9); + } + { + QLinkedList linkedList2 = QtConcurrent::mappedReduced(linkedList, + intSquare, + &QLinkedList::append, + OrderedReduce); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList2, QLinkedList() << 1 << 4 << 9); + + QLinkedList linkedList3 = QtConcurrent::mappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + intSquare, + &QLinkedList::append, + OrderedReduce); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList3, QLinkedList() << 1 << 4 << 9); + + QLinkedList linkedList4 = QtConcurrent::mappedReduced(QLinkedList(linkedList), + intSquare, + &QLinkedList::append, + OrderedReduce); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList4, QLinkedList() << 1 << 4 << 9); + } + + // member-function + { + int sum = QtConcurrent::mappedReduced(numberList, + &Number::toInt, + intSumReduce); + QCOMPARE(sum, 6); + int sum2 = QtConcurrent::mappedReduced(numberList.constBegin(), + numberList.constEnd(), + &Number::toInt, + intSumReduce); + QCOMPARE(sum2, 6); + + int sum3 = QtConcurrent::mappedReduced(QList(numberList), + &Number::toInt, + intSumReduce); + QCOMPARE(sum3, 6); + } + { + int sum = QtConcurrent::mappedReduced(numberLinkedList, + &Number::toInt, + intSumReduce); + QCOMPARE(sum, 6); + int sum2 = QtConcurrent::mappedReduced(numberLinkedList.constBegin(), + numberLinkedList.constEnd(), + &Number::toInt, + intSumReduce); + QCOMPARE(sum2, 6); + + int sum3 = QtConcurrent::mappedReduced(QLinkedList(numberLinkedList), + &Number::toInt, + intSumReduce); + QCOMPARE(sum3, 6); + } + + // linked lists + { + + QLinkedList list; + list << 1 << 2 << 3; + + QLinkedList numberList; + numberList << 1 << 2 << 3; + + int sum = QtConcurrent::mappedReduced(list, IntSquare(), IntSumReduce()); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::mappedReduced(list.constBegin(), + list.constEnd(), + IntSquare(), + IntSumReduce()); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::mappedReduced(QLinkedList(list), IntSquare(), IntSumReduce()); + QCOMPARE(sum3, 14); + + int sum4 = QtConcurrent::mappedReduced(list, intSquare, intSumReduce); + QCOMPARE(sum4, 14); + int sum5 = QtConcurrent::mappedReduced(list.constBegin(), + list.constEnd(), + intSquare, + intSumReduce); + QCOMPARE(sum5, 14); + + int sum6 = QtConcurrent::mappedReduced(QLinkedList(list), + intSquare, + intSumReduce); + QCOMPARE(sum6, 14); + } + + // ### the same as above, with an initial result value +} + +void tst_QtConcurrentMap::blocking_mappedReduced() +{ + QList list; + list << 1 << 2 << 3; + QLinkedList linkedList; + linkedList << 1 << 2 << 3; + QList numberList; + numberList << 1 << 2 << 3; + QLinkedList numberLinkedList; + numberLinkedList << 1 << 2 << 3; + + // functor-functor + { + int sum = QtConcurrent::blockingMappedReduced(list, IntSquare(), IntSumReduce()); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::blockingMappedReduced(list.constBegin(), + list.constEnd(), + IntSquare(), + IntSumReduce()); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::blockingMappedReduced(QList(list), IntSquare(), IntSumReduce()); + QCOMPARE(sum3, 14); + + int sum4 = QtConcurrent::blockingMappedReduced(list, intSquare, intSumReduce); + QCOMPARE(sum4, 14); + int sum5 = QtConcurrent::blockingMappedReduced(list.constBegin(), + list.constEnd(), + intSquare, + intSumReduce); + QCOMPARE(sum5, 14); + + int sum6 = QtConcurrent::blockingMappedReduced(QList(list), + intSquare, + intSumReduce); + QCOMPARE(sum6, 14); + } + { + int sum = QtConcurrent::blockingMappedReduced(linkedList, IntSquare(), IntSumReduce()); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::blockingMappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + IntSquare(), + IntSumReduce()); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::blockingMappedReduced(QLinkedList(linkedList), IntSquare(), IntSumReduce()); + QCOMPARE(sum3, 14); + + int sum4 = QtConcurrent::blockingMappedReduced(linkedList, intSquare, intSumReduce); + QCOMPARE(sum4, 14); + int sum5 = QtConcurrent::blockingMappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + intSquare, + intSumReduce); + QCOMPARE(sum5, 14); + + int sum6 = QtConcurrent::blockingMappedReduced(QLinkedList(linkedList), + intSquare, + intSumReduce); + QCOMPARE(sum6, 14); + } + + // function-functor + { + int sum = QtConcurrent::blockingMappedReduced(list, intSquare, IntSumReduce()); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::blockingMappedReduced(list.constBegin(), + list.constEnd(), + intSquare, + IntSumReduce()); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::blockingMappedReduced(QList(list), intSquare, IntSumReduce()); + QCOMPARE(sum3, 14); + } + { + int sum = QtConcurrent::blockingMappedReduced(linkedList, intSquare, IntSumReduce()); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::blockingMappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + intSquare, + IntSumReduce()); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::blockingMappedReduced(QLinkedList(linkedList), intSquare, IntSumReduce()); + QCOMPARE(sum3, 14); + } + + // functor-function + { + int sum = QtConcurrent::blockingMappedReduced(list, IntSquare(), intSumReduce); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::blockingMappedReduced(list.constBegin(), + list.constEnd(), + IntSquare(), + intSumReduce); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::blockingMappedReduced(QList(list), IntSquare(), intSumReduce); + QCOMPARE(sum3, 14); + } + { + int sum = QtConcurrent::blockingMappedReduced(linkedList, IntSquare(), intSumReduce); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::blockingMappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + IntSquare(), + intSumReduce); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::blockingMappedReduced(QLinkedList(linkedList), IntSquare(), intSumReduce); + QCOMPARE(sum3, 14); + } + + // function-function + { + int sum = QtConcurrent::blockingMappedReduced(list, intSquare, intSumReduce); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::blockingMappedReduced(list.constBegin(), + list.constEnd(), + intSquare, + intSumReduce); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::blockingMappedReduced(QList(list), intSquare, intSumReduce); + QCOMPARE(sum3, 14); + } + { + int sum = QtConcurrent::blockingMappedReduced(linkedList, intSquare, intSumReduce); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::blockingMappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + intSquare, + intSumReduce); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::blockingMappedReduced(QLinkedList(linkedList), intSquare, intSumReduce); + QCOMPARE(sum3, 14); + } + + // functor-member + { + QList list2 = QtConcurrent::blockingMappedReduced(list, + IntSquare(), + &QList::push_back, + OrderedReduce); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 1 << 4 << 9); + + QList list3 = QtConcurrent::blockingMappedReduced(list.constBegin(), + list.constEnd(), + IntSquare(), + &QList::push_back, + OrderedReduce); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 1 << 4 << 9); + + QList list4 = QtConcurrent::blockingMappedReduced(QList(list), + IntSquare(), + &QList::push_back, + OrderedReduce); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 1 << 4 << 9); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingMappedReduced(linkedList, + IntSquare(), + &QLinkedList::append, + OrderedReduce); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList2, QLinkedList() << 1 << 4 << 9); + + QLinkedList linkedList3 = QtConcurrent::blockingMappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + IntSquare(), + &QLinkedList::append, + OrderedReduce); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList3, QLinkedList() << 1 << 4 << 9); + + QLinkedList linkedList4 = QtConcurrent::blockingMappedReduced(QLinkedList(linkedList), + IntSquare(), + &QLinkedList::append, + OrderedReduce); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList4, QLinkedList() << 1 << 4 << 9); + } + + // member-functor + { + int sum = QtConcurrent::blockingMappedReduced(numberList, &Number::toInt, + IntSumReduce()); + QCOMPARE(sum, 6); + int sum2 = QtConcurrent::blockingMappedReduced(numberList.constBegin(), + numberList.constEnd(), + &Number::toInt, + IntSumReduce()); + QCOMPARE(sum2, 6); + + int sum3 = QtConcurrent::blockingMappedReduced(QList(numberList), + &Number::toInt, + IntSumReduce()); + QCOMPARE(sum3, 6); + } + { + int sum = QtConcurrent::blockingMappedReduced(numberLinkedList, &Number::toInt, IntSumReduce()); + QCOMPARE(sum, 6); + int sum2 = QtConcurrent::blockingMappedReduced(numberLinkedList.constBegin(), + numberLinkedList.constEnd(), + &Number::toInt, + IntSumReduce()); + QCOMPARE(sum2, 6); + + int sum3 = QtConcurrent::blockingMappedReduced(QLinkedList(numberLinkedList), + &Number::toInt, + IntSumReduce()); + QCOMPARE(sum3, 6); + } + + // member-member + { + QList list2 = QtConcurrent::blockingMappedReduced(numberList, + &Number::toInt, + &QList::push_back, + OrderedReduce); + QCOMPARE(list2, QList() << 1 << 2 << 3); + + QList list3 = QtConcurrent::blockingMappedReduced(numberList.constBegin(), + numberList.constEnd(), + &Number::toInt, + &QList::push_back, + OrderedReduce); + QCOMPARE(list3, QList() << 1 << 2 << 3); + + QList list4 = QtConcurrent::blockingMappedReduced(QList(numberList), + &Number::toInt, + &QList::push_back, OrderedReduce); + QCOMPARE(list4, QList() << 1 << 2 << 3); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingMappedReduced(numberLinkedList, + &Number::toInt, + &QLinkedList::append, + OrderedReduce); + QCOMPARE(linkedList2, QLinkedList() << 1 << 2 << 3); + + QLinkedList linkedList3 = QtConcurrent::blockingMappedReduced(numberLinkedList.constBegin(), + numberLinkedList.constEnd(), + &Number::toInt, + &QLinkedList::append, + OrderedReduce); + QCOMPARE(linkedList3, QLinkedList() << 1 << 2 << 3); + + QLinkedList linkedList4 = QtConcurrent::blockingMappedReduced(QLinkedList(numberLinkedList), + &Number::toInt, + &QLinkedList::append, OrderedReduce); + QCOMPARE(linkedList4, QLinkedList() << 1 << 2 << 3); + } + + // function-member + { + QList list2 = QtConcurrent::blockingMappedReduced(list, + intSquare, + &QList::push_back, + OrderedReduce); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list2, QList() << 1 << 4 << 9); + + QList list3 = QtConcurrent::blockingMappedReduced(list.constBegin(), + list.constEnd(), + intSquare, + &QList::push_back, + OrderedReduce); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list3, QList() << 1 << 4 << 9); + + QList list4 = QtConcurrent::blockingMappedReduced(QList(list), + intSquare, + &QList::push_back, + OrderedReduce); + QCOMPARE(list, QList() << 1 << 2 << 3); + QCOMPARE(list4, QList() << 1 << 4 << 9); + } + { + QLinkedList linkedList2 = QtConcurrent::blockingMappedReduced(linkedList, + intSquare, + &QLinkedList::append, + OrderedReduce); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList2, QLinkedList() << 1 << 4 << 9); + + QLinkedList linkedList3 = QtConcurrent::blockingMappedReduced(linkedList.constBegin(), + linkedList.constEnd(), + intSquare, + &QLinkedList::append, + OrderedReduce); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList3, QLinkedList() << 1 << 4 << 9); + + QLinkedList linkedList4 = QtConcurrent::blockingMappedReduced(QLinkedList(linkedList), + intSquare, + &QLinkedList::append, + OrderedReduce); + QCOMPARE(linkedList, QLinkedList() << 1 << 2 << 3); + QCOMPARE(linkedList4, QLinkedList() << 1 << 4 << 9); + } + + // member-function + { + int sum = QtConcurrent::blockingMappedReduced(numberList, + &Number::toInt, + intSumReduce); + QCOMPARE(sum, 6); + int sum2 = QtConcurrent::blockingMappedReduced(numberList.constBegin(), + numberList.constEnd(), + &Number::toInt, + intSumReduce); + QCOMPARE(sum2, 6); + + int sum3 = QtConcurrent::blockingMappedReduced(QList(numberList), + &Number::toInt, + intSumReduce); + QCOMPARE(sum3, 6); + } + { + int sum = QtConcurrent::blockingMappedReduced(numberLinkedList, + &Number::toInt, + intSumReduce); + QCOMPARE(sum, 6); + int sum2 = QtConcurrent::blockingMappedReduced(numberLinkedList.constBegin(), + numberLinkedList.constEnd(), + &Number::toInt, + intSumReduce); + QCOMPARE(sum2, 6); + + int sum3 = QtConcurrent::blockingMappedReduced(QLinkedList(numberLinkedList), + &Number::toInt, + intSumReduce); + QCOMPARE(sum3, 6); + } + + // linked lists + { + + QLinkedList list; + list << 1 << 2 << 3; + + QLinkedList numberList; + numberList << 1 << 2 << 3; + + int sum = QtConcurrent::blockingMappedReduced(list, IntSquare(), IntSumReduce()); + QCOMPARE(sum, 14); + int sum2 = QtConcurrent::blockingMappedReduced(list.constBegin(), + list.constEnd(), + IntSquare(), + IntSumReduce()); + QCOMPARE(sum2, 14); + + int sum3 = QtConcurrent::blockingMappedReduced(QLinkedList(list), IntSquare(), IntSumReduce()); + QCOMPARE(sum3, 14); + + int sum4 = QtConcurrent::blockingMappedReduced(list, intSquare, intSumReduce); + QCOMPARE(sum4, 14); + int sum5 = QtConcurrent::blockingMappedReduced(list.constBegin(), + list.constEnd(), + intSquare, + intSumReduce); + QCOMPARE(sum5, 14); + + int sum6 = QtConcurrent::blockingMappedReduced(QLinkedList(list), + intSquare, + intSumReduce); + QCOMPARE(sum6, 14); + } + + // ### the same as above, with an initial result value +} + +int sleeper(int val) +{ + QTest::qSleep(100); + return val; +} + +void tst_QtConcurrentMap::assignResult() +{ + const QList startList = QList() << 0 << 1 << 2; + QList list = QtConcurrent::blockingMapped(startList, sleeper); + QCOMPARE(list.at(0), 0); + QCOMPARE(list.at(1), 1); +} + +int fnConst(const int &i) +{ + return i; +} + +int fn(int &i) +{ + return i; +} + +QString changeTypeConst(const int &) +{ + return QString(); +} + +QString changeType(int &) +{ + return QString(); +} + +int changeTypeQStringListConst(const QStringList &) +{ + return 0; +} + +int changeTypeQStringList(QStringList &) +{ + return 0; +} + +class MemFnTester +{ +public: + MemFnTester() {} + + MemFnTester fn() + { + return MemFnTester(); + } + + MemFnTester fnConst() const + { + return MemFnTester(); + } + + QString changeType() + { + return QString(); + } + + QString changeTypeConst() const + { + return QString(); + } +}; + +Q_DECLARE_METATYPE(QVector); +Q_DECLARE_METATYPE(QList); + +void tst_QtConcurrentMap::functionOverloads() +{ + QList intList; + const QList constIntList; + QList classList; + const QList constMemFnTesterList; + + QtConcurrent::mapped(intList, fnConst); + QtConcurrent::mapped(constIntList, fnConst); + QtConcurrent::mapped(classList, &MemFnTester::fnConst); + QtConcurrent::mapped(constMemFnTesterList, &MemFnTester::fnConst); + + QtConcurrent::blockingMapped >(intList, fnConst); + QtConcurrent::blockingMapped >(constIntList, fnConst); + QtConcurrent::blockingMapped >(classList, &MemFnTester::fnConst); + QtConcurrent::blockingMapped >(constMemFnTesterList, &MemFnTester::fnConst); + + QtConcurrent::blockingMapped >(intList, changeTypeConst); + QtConcurrent::blockingMapped >(constIntList, changeTypeConst); + QtConcurrent::blockingMapped >(classList, &MemFnTester::changeTypeConst); + QtConcurrent::blockingMapped >(constMemFnTesterList, &MemFnTester::changeTypeConst); + + QStringList stringList; + const QStringList constStringList; + // QtConcurrent::map(stringList, changeTypeQStringListConst); + // QtConcurrent::map(intList, changeTypeNonConst); + // QList(QtConcurrent::map(constStringList, changeTypeQStringList)); + // QtConcurrent::map(classList, &MemFnTester::changeType); + // QtConcurrent::map(classList, &MemFnTester::changeTypeConst); + // QtConcurrent::map(constMemFnTesterList, &MemFnTester::changeTypeConst); +} + +QAtomicInt currentInstanceCount; +QAtomicInt peakInstanceCount; +class InstanceCounter +{ +public: + inline InstanceCounter() + { currentInstanceCount.fetchAndAddRelaxed(1); updatePeak(); } + inline ~InstanceCounter() + { currentInstanceCount.fetchAndAddRelaxed(-1);} + inline InstanceCounter(const InstanceCounter &) + { currentInstanceCount.fetchAndAddRelaxed(1); updatePeak(); } + + void updatePeak() + { + forever { + const int localPeak = peakInstanceCount; + const int localCurrent = currentInstanceCount; + if (localCurrent <= localPeak) + break; + if (peakInstanceCount.testAndSetOrdered(localPeak, localCurrent)) + break; + } + } +}; + +InstanceCounter slowMap(const InstanceCounter &in) +{ + QTest::qSleep(2); + return in; +} + +InstanceCounter fastMap(const InstanceCounter &in) +{ + QTest::qSleep(rand() % 2 + 1); +// qDebug() << "map " << QThread::currentThread(); + return in; +} + +void slowReduce(int &result, const InstanceCounter&) +{ + QTest::qSleep(rand() % 4 + 1); +// qDebug() << "reduce" << QThread::currentThread(); + ++result; +} + +void fastReduce(int &result, const InstanceCounter&) +{ + ++result; +} + +void tst_QtConcurrentMap::throttling() +{ + const int itemcount = 100; + const int allowedTemporaries = QThread::idealThreadCount() * 40; + + { + currentInstanceCount = 0; + peakInstanceCount = 0; + + QList instances; + for (int i = 0; i < itemcount; ++i) + instances.append(InstanceCounter()); + + QCOMPARE((int)currentInstanceCount, itemcount); + + int results = QtConcurrent::blockingMappedReduced(instances, slowMap, fastReduce); + QCOMPARE(results, itemcount); + qDebug() << (int)currentInstanceCount; + qDebug() << (int)peakInstanceCount; + QCOMPARE(int(currentInstanceCount), itemcount); + QVERIFY(int(peakInstanceCount) < itemcount + allowedTemporaries); + } + + { + QCOMPARE(int(currentInstanceCount), 0); + peakInstanceCount = 0; + + QList instances; + for (int i = 0; i < itemcount; ++i) + instances.append(InstanceCounter()); + + QCOMPARE(int(currentInstanceCount), itemcount); + int results = QtConcurrent::blockingMappedReduced(instances, fastMap, slowReduce); + + QCOMPARE(results, itemcount); + qDebug() << (int)currentInstanceCount; + qDebug() << (int)peakInstanceCount; + QCOMPARE((int)currentInstanceCount, itemcount); + QVERIFY(int(peakInstanceCount) < itemcount + allowedTemporaries); + } +} + +#ifndef QT_NO_EXCEPTIONS +void throwMapper(int &e) +{ + Q_UNUSED(e); + throw QtConcurrent::Exception(); +} + +void tst_QtConcurrentMap::exceptions() +{ + bool caught = false; + try { + QList list = QList() << 1 << 2 << 3; + QtConcurrent::map(list, throwMapper).waitForFinished(); + } catch (Exception &e) { + caught = true; + } + if (!caught) + QFAIL("did not get exception"); +} +#endif + +int mapper(const int &i) +{ + QTest::qWait(1); + return i; +} + +void tst_QtConcurrentMap::incrementalResults() +{ + const int count = 200; + QList ints; + for (int i=0; i < count; ++i) + ints << i; + + QFuture future = QtConcurrent::mapped(ints, mapper); + + QList results; + + while (future.isFinished() == false) { + for (int i = 0; i < future.resultCount(); ++i) { + results += future.resultAt(i); + } + + QTest::qWait(1); + } + + QCOMPARE(future.isFinished(), true); + QCOMPARE(future.resultCount(), count); + QCOMPARE(future.results().count(), count); +} + +/* + Test that mapped does not cause deep copies when holding + references to Qt containers. +*/ +void tst_QtConcurrentMap::noDetatch() +{ + { + QList l = QList() << 1; + QVERIFY(l.isDetached()); + + QList ll = l; + QVERIFY(l.isDetached() == false); + + QtConcurrent::mapped(l, mapper).waitForFinished(); + + QVERIFY(l.isDetached() == false); + QVERIFY(ll.isDetached() == false); + + QtConcurrent::mappedReduced(l, mapper, intSumReduce).waitForFinished(); + + QVERIFY(l.isDetached() == false); + QVERIFY(ll.isDetached() == false); + + QtConcurrent::map(l, multiplyBy2Immutable).waitForFinished(); + QVERIFY(l.isDetached() == true); + QVERIFY(ll.isDetached() == true); + } + { + const QList l = QList() << 1; + QVERIFY(l.isDetached()); + + const QList ll = l; + QVERIFY(l.isDetached() == false); + + QtConcurrent::mapped(l, mapper).waitForFinished(); + + QVERIFY(l.isDetached() == false); + QVERIFY(ll.isDetached() == false); + + QtConcurrent::mappedReduced(l, mapper, intSumReduce).waitForFinished(); + + QVERIFY(l.isDetached() == false); + QVERIFY(ll.isDetached() == false); + } + +} + +void tst_QtConcurrentMap::stlContainers() +{ +#ifdef QT_NO_STL + QSKIP("Qt compiled without STL support", SkipAll); +#elif defined(Q_COMPILER_RVALUE_REFS) + //mapped uses &Container::push_back, but in c++0x, std::vector has two overload of it + // meaning it is not possible to take the address of that function anymore. + QSKIP("mapped do not work with c++0x stl vector", SkipAll); +#else + std::vector vector; + vector.push_back(1); + vector.push_back(2); + + std::vector vector2 = QtConcurrent::blockingMapped >(vector, mapper); + QCOMPARE(vector2.size(), (std::vector::size_type)(2)); + + std::list list; + list.push_back(1); + list.push_back(2); + + std::list list2 = QtConcurrent::blockingMapped >(list, mapper); + QCOMPARE(list2.size(), (std::vector::size_type)(2)); + + QtConcurrent::mapped(list, mapper).waitForFinished(); + + QtConcurrent::blockingMap(list, multiplyBy2Immutable); +#endif +} + +InstanceCounter ic_fn(const InstanceCounter & ic) +{ + return InstanceCounter(ic); +}; + +// Verify that held results are deleted when a future is +// assigned over with operator == +void tst_QtConcurrentMap::qFutureAssignmentLeak() +{ + currentInstanceCount = 0; + peakInstanceCount = 0; + QFuture future; + { + QList list; + for (int i=0;i<1000;++i) + list += InstanceCounter(); + future = QtConcurrent::mapped(list, ic_fn); + future.waitForFinished(); + + future = QtConcurrent::mapped(list, ic_fn); + future.waitForFinished(); + + future = QtConcurrent::mapped(list, ic_fn); + future.waitForFinished(); + } + + QCOMPARE(int(currentInstanceCount), 1000); + future = QFuture(); + QCOMPARE(int(currentInstanceCount), 0); +} + +inline void increment(int &num) +{ + ++num; +} + +inline int echo(const int &num) +{ + return num; +} + +void add(int &result, const int &sum) +{ + result += sum; +} + +void tst_QtConcurrentMap::stressTest() +{ + const int listSize = 1000; + const int sum = (listSize - 1) * (listSize / 2); + QList list; + + + for (int i = 0; i < listSize; ++i) { + list.append(i); + } + + for (int i =0 ; i < 100; ++i) { + QList result = QtConcurrent::blockingMapped(list, echo); + for (int j = 0; j < listSize; ++j) + QCOMPARE(result.at(j), j); + } + + for (int i = 0 ; i < 100; ++i) { + int result = QtConcurrent::blockingMappedReduced(list, echo, add); + QCOMPARE(result, sum); + } + + for (int i = 0 ; i < 100; ++i) { + QtConcurrent::map(list, increment).waitForFinished(); + for (int j = 0; j < listSize; ++j) + QCOMPARE(list.at(j), i + j + 1); + } +} + +QTEST_MAIN(tst_QtConcurrentMap) + +#else + +void tst_QtConcurrentMap::map() {} +void tst_QtConcurrentMap::blocking_map() {} +void tst_QtConcurrentMap::mapped() {} +void tst_QtConcurrentMap::blocking_mapped() {} +void tst_QtConcurrentMap::mappedReduced() {} +void tst_QtConcurrentMap::blocking_mappedReduced() {} +void tst_QtConcurrentMap::assignResult() {} +void tst_QtConcurrentMap::functionOverloads() {} +#ifndef QT_NO_EXCEPTIONS +void tst_QtConcurrentMap::exceptions() {} +#endif +void tst_QtConcurrentMap::incrementalResults() {} +void tst_QtConcurrentMap::stressTest() {} +void tst_QtConcurrentMap::throttling() {} +void tst_QtConcurrentMap::stlContainers() {} +void tst_QtConcurrentMap::noDetatch() {} + +QTEST_NOOP_MAIN + +#endif + +#include "tst_qtconcurrentmap.moc" diff --git a/tests/auto/corelib/concurrent/qtconcurrentresultstore/qtconcurrentresultstore.pro b/tests/auto/corelib/concurrent/qtconcurrentresultstore/qtconcurrentresultstore.pro new file mode 100644 index 0000000000..8bc20c3f13 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentresultstore/qtconcurrentresultstore.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +DEFINES += QT_STRICT_ITERATORS +SOURCES += tst_qtconcurrentresultstore.cpp +QT = core core-private +CONFIG += parallel_test diff --git a/tests/auto/corelib/concurrent/qtconcurrentresultstore/tst_qtconcurrentresultstore.cpp b/tests/auto/corelib/concurrent/qtconcurrentresultstore/tst_qtconcurrentresultstore.cpp new file mode 100644 index 0000000000..1728be68fe --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentresultstore/tst_qtconcurrentresultstore.cpp @@ -0,0 +1,491 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include + +#include + +using namespace QtConcurrent; + +class tst_QtConcurrentResultStore : public QObject +{ + Q_OBJECT +public slots: + void init(); +private slots: + void construction(); + void iterators(); + void addResult(); + void addResults(); + void resultIndex(); + void resultAt(); + void contains(); + void filterMode(); + void addCanceledResult(); + void count(); +private: + int int0; + int int1; + int int2; + QVector vec0; + QVector vec1; +}; + +void tst_QtConcurrentResultStore::init() +{ + int0 = 0; + int1 = 1; + int2 = 2; + vec0 = QVector() << 2 << 3; + vec1 = QVector() << 4 << 5; +} + +void tst_QtConcurrentResultStore::construction() +{ + ResultStore store; + QCOMPARE(store.count(), 0); +} + +void tst_QtConcurrentResultStore::iterators() +{ + { + ResultStore store; + ResultIteratorBase it = store.begin(); + QVERIFY(store.begin() == store.end()); + QVERIFY(store.resultAt(0) == store.end()); + QVERIFY(store.resultAt(1) == store.end()); + } + { + ResultStoreBase storebase; + storebase.addResult(-1, &int0); // note to self: adding a pointer to the stack here is ok since + storebase.addResult(1, &int1); // ResultStoreBase does not take ownership, only ResultStore<> does. + ResultIteratorBase it = storebase.begin(); + QCOMPARE(it.resultIndex(), 0); + QVERIFY(it == storebase.begin()); + QVERIFY(it != storebase.end()); + + ++it; + QCOMPARE(it.resultIndex(), 1); + QVERIFY(it != storebase.begin()); + QVERIFY(it != storebase.end()); + + ++it; + QVERIFY(it != storebase.begin()); + QVERIFY(it == storebase.end()); + } +} + +void tst_QtConcurrentResultStore::addResult() +{ + { + // test addResult return value + ResultStore store; + store.setFilterMode(true); + + QCOMPARE(store.addResult(0, &int0), 0); + QCOMPARE(store.count(), 1); // result 0 becomes available + QCOMPARE(store.contains(0), true); + + QCOMPARE(store.addResult(2, &int0), 2); + QCOMPARE(store.count(), 1); + QCOMPARE(store.contains(2), false); + + QCOMPARE(store.addCanceledResult(1), 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); + + QCOMPARE(store.addResult(3, &int0), 3); + QCOMPARE(store.count(), 3); + QCOMPARE(store.contains(2), true); + + QCOMPARE(store.addResult(6, &int0), 6); + QCOMPARE(store.count(), 3); + QCOMPARE(store.addResult(7, &int0), 7); + QCOMPARE(store.count(), 3); + QCOMPARE(store.contains(3), false); + + QCOMPARE(store.addCanceledResult(4), 4); + QCOMPARE(store.addCanceledResult(5), 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); + + QCOMPARE(store.addResult(8, &int0), 8); + QCOMPARE(store.contains(5), true); + QCOMPARE(store.count(), 6); + + QCOMPARE(store.contains(6), false); + QCOMPARE(store.contains(7), false); + } +} + +void tst_QtConcurrentResultStore::addResults() +{ + + 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()); +} + +void tst_QtConcurrentResultStore::resultIndex() +{ + ResultStore 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); +} + +void tst_QtConcurrentResultStore::resultAt() +{ + { + ResultStore 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 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); + } +} + +void tst_QtConcurrentResultStore::contains() +{ + { + ResultStore store; + QCOMPARE(store.contains(0), false); + QCOMPARE(store.contains(1), false); + QCOMPARE(store.contains(INT_MAX), false); + store.addResult(1, &int1); + QVERIFY(store.contains(int1)); + store.addResult(0, &int0); + QVERIFY(store.contains(int0)); + store.addResult(-1, &int2); + QVERIFY(store.contains(int2)); + } + { + ResultStore 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 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 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_QtConcurrentResultStore::filterMode() +{ + // Test filter mode, where "gaps" in the result array aren't allowed. + ResultStore store; + QCOMPARE(store.filterMode(), false); + store.setFilterMode(true); + QVERIFY(store.filterMode()); + + 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); +} + +void tst_QtConcurrentResultStore::addCanceledResult() +{ + // test canceled results + ResultStore 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); +} + +void tst_QtConcurrentResultStore::count() +{ + { + // test resultCount in non-filtered mode. It should always be possible + // to iterate through the results 0 to resultCount. + ResultStore 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 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 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 store; + store.addResults(2, &vec1); + QCOMPARE(store.count(), 0); + + store.addResults(0, &vec0); + QCOMPARE(store.count(), 4); + } + { + ResultStore 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 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 store; + store.setFilterMode(true); + store.addResults(3, &vec1); + QCOMPARE(store.count(), 0); + + store.addCanceledResults(0, 3); + QCOMPARE(store.count(), 2); + } + + { + ResultStore 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 + } +} + +QTEST_MAIN(tst_QtConcurrentResultStore) +#include "tst_qtconcurrentresultstore.moc" diff --git a/tests/auto/corelib/concurrent/qtconcurrentrun/.gitignore b/tests/auto/corelib/concurrent/qtconcurrentrun/.gitignore new file mode 100644 index 0000000000..d7a8334ec4 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentrun/.gitignore @@ -0,0 +1 @@ +tst_qtconcurrentrun diff --git a/tests/auto/corelib/concurrent/qtconcurrentrun/qtconcurrentrun.pro b/tests/auto/corelib/concurrent/qtconcurrentrun/qtconcurrentrun.pro new file mode 100644 index 0000000000..24576048e9 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentrun/qtconcurrentrun.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qtconcurrentrun.cpp +QT = core +CONFIG += parallel_test +CONFIG += parallel_test diff --git a/tests/auto/corelib/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp b/tests/auto/corelib/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp new file mode 100644 index 0000000000..cacb09aae1 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentrun/tst_qtconcurrentrun.cpp @@ -0,0 +1,518 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +// #include +#include +#include +#include +#include "../qfuture/versioncheck.h" + +#ifndef QT_NO_CONCURRENT_TEST + +using namespace QtConcurrent; + +class tst_QtConcurrentRun: public QObject +{ + Q_OBJECT +private slots: + void runLightFunction(); + void runHeavyFunction(); + void returnValue(); + void functionObject(); + void memberFunctions(); + void implicitConvertibleTypes(); + void runWaitLoop(); + void recursive(); +#ifndef QT_NO_EXCEPTIONS + void exceptions(); +#endif +#if 0 + void createFunctor(); +#endif + void functor(); + void lambda(); +}; + +#if 0 +# define F(X) createFunctor(X) +#else +# define F(X) X +#endif + + +QTEST_MAIN(tst_QtConcurrentRun) + +void light() +{ + qDebug("in function"); + qDebug("done function"); +} + +void heavy() +{ + qDebug("in function"); + QString str; + for (int i = 0; i < 1000000; ++i) + str.append("a"); + qDebug("done function"); +} + + +void tst_QtConcurrentRun::runLightFunction() +{ + qDebug("starting function"); + QFuture future = run(F(light)); + qDebug("waiting"); + future.waitForFinished(); + qDebug("done"); +} + +void tst_QtConcurrentRun::runHeavyFunction() +{ + qDebug("starting function"); + QFuture future = run(F(heavy)); + qDebug("waiting"); + future.waitForFinished(); + qDebug("done"); +} + +int returnInt0() +{ + return 10; +} + +int returnInt1(int i) +{ + return i; +} + +class A +{ +public: + int member0() { return 10; } + int member1(int in) { return in; } + + typedef int result_type; + int operator()() { return 10; } + int operator()(int in) { return in; } +}; + +class AConst +{ +public: + int member0() const { return 10; } + int member1(int in) const { return in; } + + typedef int result_type; + int operator()() const { return 10; } + int operator()(int in) const { return in; } +}; + +void tst_QtConcurrentRun::returnValue() +{ + QFuture f; + + f = run(F(returnInt0)); + QCOMPARE(f.result(), 10); + + A a; + f = run(&a, F(&A::member0)); + QCOMPARE(f.result(), 10); + + f = run(&a, F(&A::member1), 20); + QCOMPARE(f.result(), 20); + + f = run(a, F(&A::member0)); + QCOMPARE(f.result(), 10); + + f = run(a, F(&A::member1), 20); + QCOMPARE(f.result(), 20); + + f = run(a); + QCOMPARE(f.result(), 10); + + f = run(&a); + QCOMPARE(f.result(), 10); + + f = run(a, 20); + QCOMPARE(f.result(), 20); + + f = run(&a, 20); + QCOMPARE(f.result(), 20); + + const AConst aConst = AConst(); + f = run(&aConst, &AConst::member0); + QCOMPARE(f.result(), 10); + + f = run(&aConst, F(&AConst::member1), 20); + QCOMPARE(f.result(), 20); + + f = run(aConst, F(&AConst::member0)); + QCOMPARE(f.result(), 10); + + f = run(aConst, F(&AConst::member1), 20); + QCOMPARE(f.result(), 20); + + f = run(aConst); + QCOMPARE(f.result(), 10); + + f = run(&aConst); + QCOMPARE(f.result(), 10); + + f = run(aConst, 20); + QCOMPARE(f.result(), 20); + + f = run(&aConst, 20); + QCOMPARE(f.result(), 20); +} + +struct TestClass +{ + void foo() { } + typedef void result_type; + void operator()() { } + void operator()(int) { } + void fooInt(int){ }; +}; + +struct TestConstClass +{ + void foo() const { } + typedef void result_type; + void operator()() const { } + void operator()(int) const { } + void fooInt(int) const { }; +}; + +void tst_QtConcurrentRun::functionObject() +{ + QFuture f; + TestClass c; + + f = run(c); + f = run(F(&c)); + f = run(c, 10); + f = run(F(&c), 10); + + const TestConstClass cc = TestConstClass(); + f = run(cc); + f = run(F(&cc)); + f = run(cc, 10); + f = run(F(&cc), 10); +} + + +void tst_QtConcurrentRun::memberFunctions() +{ + TestClass c; + + run(c, F(&TestClass::foo)).waitForFinished(); + run(&c, F(&TestClass::foo)).waitForFinished(); + run(c, F(&TestClass::fooInt), 10).waitForFinished(); + run(&c, F(&TestClass::fooInt), 10).waitForFinished(); + + const TestConstClass cc = TestConstClass(); + run(cc, F(&TestConstClass::foo)).waitForFinished(); + run(&cc, F(&TestConstClass::foo)).waitForFinished(); + run(cc, F(&TestConstClass::fooInt), 10).waitForFinished(); + run(&cc, F(&TestConstClass::fooInt), 10).waitForFinished(); +} + + +void doubleFunction(double) +{ + +} + +void stringConstRefFunction(const QString &) +{ + +} + +void stringRefFunction(QString &) +{ + +} + +void stringFunction(QString) +{ + +} + +void stringIntFunction(QString) +{ + +} + + +void tst_QtConcurrentRun::implicitConvertibleTypes() +{ + double d; + run(F(doubleFunction), d).waitForFinished(); + int i; + run(F(doubleFunction), d).waitForFinished(); + run(F(doubleFunction), i).waitForFinished(); + run(F(doubleFunction), 10).waitForFinished(); + run(F(stringFunction), QLatin1String("Foo")).waitForFinished(); + run(F(stringConstRefFunction), QLatin1String("Foo")).waitForFinished(); + QString string; + run(F(stringRefFunction), string).waitForFinished(); +} + +void fn() { } + +void tst_QtConcurrentRun::runWaitLoop() +{ + for (int i = 0; i < 1000; ++i) + run(fn).waitForFinished(); +} + +QAtomicInt count; + +void recursiveRun(int level) +{ + count.ref(); + if (--level > 0) { + QFuture f1 = run(recursiveRun, level); + QFuture f2 = run(recursiveRun, level); + f1.waitForFinished(); + f2.waitForFinished(); + } +} + +int recursiveResult(int level) +{ + count.ref(); + if (--level > 0) { + QFuture f1 = run(recursiveResult, level); + QFuture f2 = run(recursiveResult, level); + return f1.result() + f2.result(); + } + return 1; +} + +void tst_QtConcurrentRun::recursive() +{ + int levels = 15; + + for (int i = 0; i < QThread::idealThreadCount(); ++i) { + count = 0; + QThreadPool::globalInstance()->setMaxThreadCount(i); + recursiveRun(levels); + QCOMPARE((int)count, (int)pow(2.0, levels) - 1); + } + + for (int i = 0; i < QThread::idealThreadCount(); ++i) { + count = 0; + QThreadPool::globalInstance()->setMaxThreadCount(i); + recursiveResult(levels); + QCOMPARE((int)count, (int)pow(2.0, levels) - 1); + } +} + +int e; +void vfn0() +{ + ++e; +} + +int fn0() +{ + return 1; +} + +void vfn1(double) +{ + ++e; +} + +int fn1(int) +{ + return 1; +} + +void vfn2(double, int *) +{ + ++e; +} + +int fn2(double, int *) +{ + return 1; +} + + +#ifndef QT_NO_EXCEPTIONS +void throwFunction() +{ + throw QtConcurrent::Exception(); +} + +int throwFunctionReturn() +{ + throw QtConcurrent::Exception(); + return 0; +} + +void tst_QtConcurrentRun::exceptions() +{ + bool caught = false; + try { + QtConcurrent::run(throwFunction).waitForFinished(); + } catch (Exception &e) { + caught = true; + } + if (!caught) + QFAIL("did not get exception"); + + caught = false; + try { + QtConcurrent::run(throwFunctionReturn).waitForFinished(); + } catch (Exception &e) { + caught = true; + } + if (!caught) + QFAIL("did not get exception"); +} +#endif + +#if 0 +void tst_QtConcurrentRun::createFunctor() +{ + e = 0; + ::QtConcurrent::createFunctor(vfn0)(); + e += QtConcurrent::createFunctor(fn0)(); + ::QtConcurrent::createFunctor(vfn1)(1); // implicit conversions should work + e += QtConcurrent::createFunctor(fn1)(2); + ::QtConcurrent::createFunctor(vfn2)(1.0, &e); + e += QtConcurrent::createFunctor(fn2)(2, &e); + QCOMPARE(e, 6); + + + e = 0; + TestClass c; + +// ::QtConcurrent::createFunctor(c, &TestClass::foo)(); + ::QtConcurrent::createFunctor(&c, &TestClass::foo)(); +// ::QtConcurrent::createFunctor(c, &TestClass::fooInt)(10); + ::QtConcurrent::createFunctor(&c, &TestClass::fooInt)(10); + + const TestConstClass cc = TestConstClass(); +/* + ::QtConcurrent::createFunctor(cc, &TestConstClass::foo)(); + ::QtConcurrent::createFunctor(&cc, &TestConstClass::foo)(); + ::QtConcurrent::createFunctor(cc, &TestConstClass::fooInt(10); + ::QtConcurrent::createFunctor(&cc, &TestConstClass::fooInt)(10); +*/ + qDebug() << e; +} +#endif + +struct Functor { + int operator()() { return 42; } + double operator()(double a, double b) { return a/b; } + int operator()(int a, int b) { return a/b; } + void operator()(int) { } + void operator()(int, int, int) { } + void operator()(int, int, int, int) { } + void operator()(int, int, int, int, int) { } + void operator()(int, int, int, int, int, int) { } +}; + +void tst_QtConcurrentRun::functor() +{ + //this test functor without result_type, decltype need to be supported by the compiler +#ifndef Q_COMPILER_DECLTYPE + QSKIP("Compiler do not suport decltype", SkipAll); +#else + Functor f; + { + QFuture fut = QtConcurrent::run(f); + QCOMPARE(fut.result(), 42); + } + { + QFuture fut = QtConcurrent::run(f, 8.5, 1.8); + QCOMPARE(fut.result(), (8.5/1.8)); + } + { + QFuture fut = QtConcurrent::run(f, 19, 3); + QCOMPARE(fut.result(), int(19/3)); + } + { + QtConcurrent::run(f, 1).waitForFinished(); + QtConcurrent::run(f, 1,2).waitForFinished(); + QtConcurrent::run(f, 1,2,3).waitForFinished(); + QtConcurrent::run(f, 1,2,3,4).waitForFinished(); + QtConcurrent::run(f, 1,2,3,4,5).waitForFinished(); + } +#endif +} + + +void tst_QtConcurrentRun::lambda() +{ +#ifndef Q_COMPILER_LAMBDA + QSKIP("Compiler do not suport lambda", SkipAll); +#else + + QCOMPARE(QtConcurrent::run([](){ return 45; }).result(), 45); + QCOMPARE(QtConcurrent::run([](int a){ return a+15; }, 12).result(), 12+15); + QCOMPARE(QtConcurrent::run([](int a, double b){ return a + b; }, 12, 15).result(), double(12+15)); + QCOMPARE(QtConcurrent::run([](int a , int, int, int, int b){ return a + b; }, 1, 2, 3, 4, 5).result(), 1 + 5); + +#ifdef Q_COMPILER_INITIALIZER_LISTS + { + QString str { "Hello World Foo" }; + QFuture f1 = QtConcurrent::run([&](){ return str.split(' '); }); + auto r = f1.result(); + QCOMPARE(r, QStringList({"Hello", "World", "Foo"})); + } +#endif + +#endif +} + + +#include "tst_qtconcurrentrun.moc" + +#else +QTEST_NOOP_MAIN +#endif diff --git a/tests/auto/corelib/concurrent/qtconcurrentthreadengine/.gitignore b/tests/auto/corelib/concurrent/qtconcurrentthreadengine/.gitignore new file mode 100644 index 0000000000..a2e2896246 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentthreadengine/.gitignore @@ -0,0 +1 @@ +tst_qtconcurrentthreadengine diff --git a/tests/auto/corelib/concurrent/qtconcurrentthreadengine/qtconcurrentthreadengine.pro b/tests/auto/corelib/concurrent/qtconcurrentthreadengine/qtconcurrentthreadengine.pro new file mode 100644 index 0000000000..bbfcf5ebe3 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentthreadengine/qtconcurrentthreadengine.pro @@ -0,0 +1,5 @@ +load(qttest_p4) +SOURCES += tst_qtconcurrentthreadengine.cpp +QT = core +CONFIG += parallel_test +CONFIG += parallel_test diff --git a/tests/auto/corelib/concurrent/qtconcurrentthreadengine/tst_qtconcurrentthreadengine.cpp b/tests/auto/corelib/concurrent/qtconcurrentthreadengine/tst_qtconcurrentthreadengine.cpp new file mode 100644 index 0000000000..772c749711 --- /dev/null +++ b/tests/auto/corelib/concurrent/qtconcurrentthreadengine/tst_qtconcurrentthreadengine.cpp @@ -0,0 +1,536 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include "../qfuture/versioncheck.h" + +#ifndef QT_NO_CONCURRENT_TEST + +using namespace QtConcurrent; + +class tst_QtConcurrentThreadEngine: public QObject +{ + Q_OBJECT +public: + void threadCount(); +private slots: + void runDirectly(); + void result(); + void runThroughStarter(); + void cancel(); + void throttle(); + void multipleResults(); + void stresstest(); + void cancelQueuedSlowUser(); +#ifndef QT_NO_EXCEPTIONS + void exceptions(); +#endif +}; + + +class PrintUser : public ThreadEngine +{ +public: + ThreadFunctionResult threadFunction() + { + QTest::qSleep(50); + QTest::qSleep(100); + return ThreadFinished; + } +}; + +void tst_QtConcurrentThreadEngine::runDirectly() +{ + { + PrintUser engine; + engine.startSingleThreaded(); + engine.startBlocking(); + } + { + PrintUser *engine = new PrintUser(); + QFuture f = engine->startAsynchronously(); + f.waitForFinished(); + } +} + +class StringResultUser : public ThreadEngine +{ +public: + typedef QString ResultType; + StringResultUser() + : done(false) { } + + bool shouldStartThread() + { + return !done; + } + + ThreadFunctionResult threadFunction() + { + done = true; + return ThreadFinished; + } + + QString *result() + { + foo = "Foo"; + return &foo; + } + QString foo; + bool done; +}; + +void tst_QtConcurrentThreadEngine::result() +{ + StringResultUser engine; + QCOMPARE(*engine.startBlocking(), QString("Foo")); +} + +class VoidResultUser : public ThreadEngine +{ +public: + bool shouldStartThread() + { + return !done; + } + + ThreadFunctionResult threadFunction() + { + done = true; + return ThreadFinished; + } + + void *result() + { + return 0; + } + bool done; +}; + +void tst_QtConcurrentThreadEngine::runThroughStarter() +{ + { + ThreadEngineStarter starter = startThreadEngine(new StringResultUser()); + QFuture f = starter.startAsynchronously(); + QCOMPARE(f.result(), QString("Foo")); + } + + { + ThreadEngineStarter starter = startThreadEngine(new StringResultUser()); + QString str = starter.startBlocking(); + QCOMPARE(str, QString("Foo")); + } +} + +class CancelUser : public ThreadEngine +{ +public: + void *result() + { + return 0; + } + + ThreadFunctionResult threadFunction() + { + while (this->isCanceled() == false) + { + QTest::qSleep(10); + } + return ThreadFinished; + } +}; + +void tst_QtConcurrentThreadEngine::cancel() +{ + { + CancelUser *engine = new CancelUser(); + QFuture f = engine->startAsynchronously(); + f.cancel(); + f.waitForFinished(); + } + { + CancelUser *engine = new CancelUser(); + QFuture f = engine->startAsynchronously(); + QTest::qSleep(10); + f.cancel(); + f.waitForFinished(); + } +} + +QAtomicInt count; +class ThrottleAlwaysUser : public ThreadEngine +{ +public: + ThrottleAlwaysUser() + { + count = initialCount = 100; + finishing = false; + } + + bool shouldStartThread() + { + return !finishing; + } + + ThreadFunctionResult threadFunction() + { + forever { + const int local = count; + if (local == 0) { + finishing = true; + return ThreadFinished; + } + + if (count.testAndSetOrdered(local, local - 1)) + break; + } + return ThrottleThread; + } + + bool finishing; + int initialCount; +}; + +// Test that a user task with a thread function that always +// want to be throttled still completes. The thread engine +// should make keep one thread running at all times. +void tst_QtConcurrentThreadEngine::throttle() +{ + const int repeats = 10; + for (int i = 0; i < repeats; ++i) { + QFuture f = (new ThrottleAlwaysUser())->startAsynchronously(); + f.waitForFinished(); + QCOMPARE(int(count), 0); + } + + for (int i = 0; i < repeats; ++i) { + ThrottleAlwaysUser t; + t.startBlocking(); + QCOMPARE(int(count), 0); + } +} + +QSet threads; +QMutex mutex; +class ThreadCountUser : public ThreadEngine +{ +public: + ThreadCountUser(bool finishImmediately = false) + { + threads.clear(); + finishing = finishImmediately; + } + + bool shouldStartThread() + { + return !finishing; + } + + ThreadFunctionResult threadFunction() + { + { + QMutexLocker lock(&mutex); + threads.insert(QThread::currentThread()); + } + QTest::qSleep(10); + finishing = true; + return ThreadFinished; + } + + bool finishing; +}; + +void tst_QtConcurrentThreadEngine::threadCount() +{ + const int repeats = 10; + for (int i = 0; i < repeats; ++i) { + ThreadCountUser t; + t.startBlocking(); + QCOMPARE(threads.count(), QThreadPool::globalInstance()->maxThreadCount() + 1); // +1 for the main thread. + + (new ThreadCountUser())->startAsynchronously().waitForFinished(); + QCOMPARE(threads.count(), QThreadPool::globalInstance()->maxThreadCount()); + } + + // Set the finish flag immediately, this should give us one thread only. + for (int i = 0; i < repeats; ++i) { + ThreadCountUser t(true /*finishImmediately*/); + t.startBlocking(); + QCOMPARE(threads.count(), 1); + + (new ThreadCountUser(true /*finishImmediately*/))->startAsynchronously().waitForFinished(); + QCOMPARE(threads.count(), 1); + } +} + +class MultipleResultsUser : public ThreadEngine +{ +public: + bool shouldStartThread() + { + return false; + } + + ThreadFunctionResult threadFunction() + { + for (int i = 0; i < 10; ++i) + this->reportResult(&i); + return ThreadFinished; + } +}; + + +void tst_QtConcurrentThreadEngine::multipleResults() +{ + MultipleResultsUser *engine = new MultipleResultsUser(); + QFuture f = engine->startAsynchronously(); + QCOMPARE(f.results().count() , 10); + QCOMPARE(f.resultAt(0), 0); + QCOMPARE(f.resultAt(5), 5); + QCOMPARE(f.resultAt(9), 9); + f.waitForFinished(); +} + + +class NoThreadsUser : public ThreadEngine +{ +public: + bool shouldStartThread() + { + return false; + } + + ThreadFunctionResult threadFunction() + { + return ThreadFinished; + } + + void *result() + { + return 0; + } +}; + +void tst_QtConcurrentThreadEngine::stresstest() +{ + const int times = 20000; + + for (int i = 0; i < times; ++i) { + VoidResultUser *engine = new VoidResultUser(); + engine->startAsynchronously().waitForFinished(); + } + + for (int i = 0; i < times; ++i) { + VoidResultUser *engine = new VoidResultUser(); + engine->startAsynchronously(); + } + + for (int i = 0; i < times; ++i) { + VoidResultUser *engine = new VoidResultUser(); + engine->startAsynchronously().waitForFinished(); + } +} + +const int sleepTime = 20; +class SlowUser : public ThreadEngine +{ +public: + bool shouldStartThread() { return false; } + ThreadFunctionResult threadFunction() { QTest::qSleep(sleepTime); return ThreadFinished; } +}; + +void tst_QtConcurrentThreadEngine::cancelQueuedSlowUser() +{ + const int times = 100; + + QTime t; + t.start(); + + { + QList > futures; + for (int i = 0; i < times; ++i) { + SlowUser *engine = new SlowUser(); + futures.append(engine->startAsynchronously()); + } + + foreach(QFuture future, futures) + future.cancel(); + } + + QVERIFY(t.elapsed() < (sleepTime * times) / 2); +} + +#ifndef QT_NO_EXCEPTIONS + +class QtConcurrentExceptionThrower : public ThreadEngine +{ +public: + QtConcurrentExceptionThrower(QThread *blockThread = 0) + { + this->blockThread = blockThread; + } + + ThreadFunctionResult threadFunction() + { + QTest::qSleep(50); + throw QtConcurrent::Exception(); + return ThreadFinished; + } + QThread *blockThread; +}; + +class UnrelatedExceptionThrower : public ThreadEngine +{ +public: + UnrelatedExceptionThrower(QThread *blockThread = 0) + { + this->blockThread = blockThread; + } + + ThreadFunctionResult threadFunction() + { + QTest::qSleep(50); + throw int(); + return ThreadFinished; + } + QThread *blockThread; +}; + +void tst_QtConcurrentThreadEngine::exceptions() +{ + // Asynchronous mode: + { + bool caught = false; + try { + QtConcurrentExceptionThrower *e = new QtConcurrentExceptionThrower(); + QFuture f = e->startAsynchronously(); + f.waitForFinished(); + } catch (Exception &e) { + caught = true; + } + if (!caught) + QFAIL("did not get exception"); + } + + // Blocking mode: + // test throwing the exception from a worker thread. + { + bool caught = false; + try { + QtConcurrentExceptionThrower e(QThread::currentThread()); + e.startBlocking(); + } catch (Exception &e) { + caught = true; + } + + if (!caught) + QFAIL("did not get exception"); + } + + // test throwing the exception from the main thread (different code path) + { + bool caught = false; + try { + QtConcurrentExceptionThrower e(0); + e.startBlocking(); + } catch (Exception &e) { + caught = true; + } + + if (!caught) + QFAIL("did not get exception"); + } + + // Asynchronous mode: + { + bool caught = false; + try { + UnrelatedExceptionThrower *e = new UnrelatedExceptionThrower(); + QFuture f = e->startAsynchronously(); + f.waitForFinished(); + } catch (QtConcurrent::UnhandledException &e) { + caught = true; + } + if (!caught) + QFAIL("did not get exception"); + } + + // Blocking mode: + // test throwing the exception from a worker thread. + { + bool caught = false; + try { + UnrelatedExceptionThrower e(QThread::currentThread()); + e.startBlocking(); + } catch (QtConcurrent::UnhandledException &e) { + caught = true; + } + + if (!caught) + QFAIL("did not get exception"); + } + + // test throwing the exception from the main thread (different code path) + { + bool caught = false; + try { + UnrelatedExceptionThrower e(0); + e.startBlocking(); + } catch (QtConcurrent::UnhandledException &e) { + caught = true; + } + + if (!caught) + QFAIL("did not get exception"); + } +} + +#endif + +QTEST_MAIN(tst_QtConcurrentThreadEngine) + +#include "tst_qtconcurrentthreadengine.moc" + +#else +QTEST_NOOP_MAIN +#endif diff --git a/tests/auto/corelib/concurrent/qthreadpool/.gitignore b/tests/auto/corelib/concurrent/qthreadpool/.gitignore new file mode 100644 index 0000000000..16105821a2 --- /dev/null +++ b/tests/auto/corelib/concurrent/qthreadpool/.gitignore @@ -0,0 +1 @@ +tst_qthreadpool diff --git a/tests/auto/corelib/concurrent/qthreadpool/qthreadpool.pro b/tests/auto/corelib/concurrent/qthreadpool/qthreadpool.pro new file mode 100644 index 0000000000..dbaeb208dd --- /dev/null +++ b/tests/auto/corelib/concurrent/qthreadpool/qthreadpool.pro @@ -0,0 +1,4 @@ +load(qttest_p4) +SOURCES += tst_qthreadpool.cpp +QT = core +CONFIG += parallel_test diff --git a/tests/auto/corelib/concurrent/qthreadpool/tst_qthreadpool.cpp b/tests/auto/corelib/concurrent/qthreadpool/tst_qthreadpool.cpp new file mode 100644 index 0000000000..49c517a569 --- /dev/null +++ b/tests/auto/corelib/concurrent/qthreadpool/tst_qthreadpool.cpp @@ -0,0 +1,870 @@ +/**************************************************************************** +** +** 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$ +** GNU Lesser General Public License Usage +** 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. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include +#include +#include +#include +#include + +typedef void (*FunctionPointer)(); + +class FunctionPointerTask : public QRunnable +{ +public: + FunctionPointerTask(FunctionPointer function) + :function(function) {} + void run() { function(); } +private: + FunctionPointer function; +}; + +QRunnable *createTask(FunctionPointer pointer) +{ + return new FunctionPointerTask(pointer); +} + +class tst_QThreadPool : public QObject +{ + Q_OBJECT +private slots: + void runFunction(); + void createThreadRunFunction(); + void runMultiple(); + void waitcomplete(); + void runTask(); + void singleton(); + void destruction(); + void threadRecycling(); + void expiryTimeout(); + void exceptions(); + void maxThreadCount(); + void setMaxThreadCount_data(); + void setMaxThreadCount(); + void setMaxThreadCountStartsAndStopsThreads(); + void activeThreadCount(); + void reserveThread_data(); + void reserveThread(); + void releaseThread_data(); + void releaseThread(); + void start(); + void tryStart(); + void tryStartPeakThreadCount(); + void tryStartCount(); + void waitForDone(); + void waitForDoneTimeout(); + void destroyingWaitsForTasksToFinish(); + void stressTest(); +}; + +int testFunctionCount; + +void sleepTestFunction() +{ + QTest::qSleep(1000); + ++testFunctionCount; +} + +void emptyFunct() +{ + +} + +void noSleepTestFunction() +{ + ++testFunctionCount; +} + +void sleepTestFunctionMutex() +{ + static QMutex testMutex; + QTest::qSleep(1000); + testMutex.lock(); + ++testFunctionCount; + testMutex.unlock(); +} + +void noSleepTestFunctionMutex() +{ + static QMutex testMutex; + testMutex.lock(); + ++testFunctionCount; + testMutex.unlock(); +} + +void tst_QThreadPool::runFunction() +{ + { + QThreadPool manager; + testFunctionCount = 0; + manager.start(createTask(noSleepTestFunction)); + } + QCOMPARE(testFunctionCount, 1); +} + +void tst_QThreadPool::createThreadRunFunction() +{ + { + QThreadPool manager; + testFunctionCount = 0; + manager.start(createTask(noSleepTestFunction)); + } + + QCOMPARE(testFunctionCount, 1); +} + +void tst_QThreadPool::runMultiple() +{ + const int runs = 10; + + { + QThreadPool manager; + testFunctionCount = 0; + for (int i = 0; i < runs; ++i) { + manager.start(createTask(sleepTestFunctionMutex)); + } + } + QCOMPARE(testFunctionCount, runs); + + { + QThreadPool manager; + testFunctionCount = 0; + for (int i = 0; i < runs; ++i) { + manager.start(createTask(noSleepTestFunctionMutex)); + } + } + QCOMPARE(testFunctionCount, runs); + + { + QThreadPool manager; + for (int i = 0; i < 500; ++i) + manager.start(createTask(emptyFunct)); + } +} + +void tst_QThreadPool::waitcomplete() +{ + testFunctionCount = 0; + const int runs = 500; + for (int i = 0; i < 500; ++i) { + QThreadPool pool; + pool.start(createTask(noSleepTestFunction)); + } + QCOMPARE(testFunctionCount, runs); +} + +volatile bool ran; +class TestTask : public QRunnable +{ +public: + void run() + { + ran = true; + } +}; + +void tst_QThreadPool::runTask() +{ + QThreadPool manager; + ran = false; + manager.start(new TestTask()); + // Hang if task is not runned. + while (ran == false) + QTest::qSleep(100); // no busy loop - this doesn't work with FIFO schedulers +} + +/* + Test running via QThreadPool::globalInstance() +*/ +void tst_QThreadPool::singleton() +{ + ran = false; + QThreadPool::globalInstance()->start(new TestTask()); + while (ran == false) + QTest::qSleep(100); // no busy loop - this doesn't work with FIFO schedulers +} + +int *value = 0; +class IntAccessor : public QRunnable +{ +public: + void run() + { + for (int i = 0; i < 100; ++i) { + ++(*value); + QTest::qSleep(1); + } + } +}; + +/* + Test that the ThreadManager destructor waits until + all threads have completed. +*/ +void tst_QThreadPool::destruction() +{ + value = new int; + QThreadPool *threadManager = new QThreadPool(); + threadManager->start(new IntAccessor()); + threadManager->start(new IntAccessor()); + delete threadManager; + delete value; + value = 0; +} + +QSemaphore threadRecyclingSemaphore; +QThread *recycledThread = 0; + +class ThreadRecorderTask : public QRunnable +{ +public: + void run() + { + recycledThread = QThread::currentThread(); + threadRecyclingSemaphore.release(); + } +}; + +/* + Test that the thread pool really reuses threads. +*/ +void tst_QThreadPool::threadRecycling() +{ + QThreadPool threadPool; + + threadPool.start(new ThreadRecorderTask()); + threadRecyclingSemaphore.acquire(); + QThread *thread1 = recycledThread; + + QTest::qSleep(100); + + threadPool.start(new ThreadRecorderTask()); + threadRecyclingSemaphore.acquire(); + QThread *thread2 = recycledThread; + QCOMPARE(thread1, thread2); + + QTest::qSleep(100); + + threadPool.start(new ThreadRecorderTask()); + threadRecyclingSemaphore.acquire(); + QThread *thread3 = recycledThread; + QCOMPARE(thread2, thread3); +} + +class ExpiryTimeoutTask : public QRunnable +{ +public: + QThread *thread; + int runCount; + QSemaphore semaphore; + + ExpiryTimeoutTask() + : thread(0), runCount(0) + { + setAutoDelete(false); + } + + void run() + { + thread = QThread::currentThread(); + ++runCount; + semaphore.release(); + } +}; + +void tst_QThreadPool::expiryTimeout() +{ + ExpiryTimeoutTask task; + + QThreadPool threadPool; + threadPool.setMaxThreadCount(1); + + int expiryTimeout = threadPool.expiryTimeout(); + threadPool.setExpiryTimeout(1000); + QCOMPARE(threadPool.expiryTimeout(), 1000); + + // run the task + threadPool.start(&task); + QVERIFY(task.semaphore.tryAcquire(1, 10000)); + QCOMPARE(task.runCount, 1); + QVERIFY(!task.thread->wait(100)); + // thread should expire + QThread *firstThread = task.thread; + QVERIFY(task.thread->wait(10000)); + + // run task again, thread should be restarted + threadPool.start(&task); + QVERIFY(task.semaphore.tryAcquire(1, 10000)); + QCOMPARE(task.runCount, 2); + QVERIFY(!task.thread->wait(100)); + // thread should expire again + QVERIFY(task.thread->wait(10000)); + + // thread pool should have reused the expired thread (instead of + // starting a new one) + QCOMPARE(firstThread, task.thread); + + threadPool.setExpiryTimeout(expiryTimeout); + QCOMPARE(threadPool.expiryTimeout(), expiryTimeout); +} + +#ifndef QT_NO_EXCEPTIONS +class ExceptionTask : public QRunnable +{ +public: + void run() + { + throw new int; + } +}; +#endif + +void tst_QThreadPool::exceptions() +{ +#ifndef QT_NO_EXCEPTIONS + ExceptionTask task; + { + QThreadPool threadPool; +// Uncomment this for a nice crash. +// threadPool.start(&task); + } +#else + QSKIP("No exception support", SkipAll); +#endif +} + +void tst_QThreadPool::maxThreadCount() +{ + DEPENDS_ON("setMaxThreadCount()"); +} + +void tst_QThreadPool::setMaxThreadCount_data() +{ + QTest::addColumn("limit"); + + QTest::newRow("") << 1; + QTest::newRow("") << -1; + QTest::newRow("") << 2; + QTest::newRow("") << -2; + QTest::newRow("") << 4; + QTest::newRow("") << -4; + QTest::newRow("") << 0; + QTest::newRow("") << 12345; + QTest::newRow("") << -6789; + QTest::newRow("") << 42; + QTest::newRow("") << -666; +} + +void tst_QThreadPool::setMaxThreadCount() +{ + QFETCH(int, limit); + QThreadPool *threadPool = QThreadPool::globalInstance(); + int savedLimit = threadPool->maxThreadCount(); + + // maxThreadCount() should always return the previous argument to + // setMaxThreadCount(), regardless of input + threadPool->setMaxThreadCount(limit); + QCOMPARE(threadPool->maxThreadCount(), limit); + + // the value returned from maxThreadCount() should always be valid input for setMaxThreadCount() + threadPool->setMaxThreadCount(savedLimit); + QCOMPARE(threadPool->maxThreadCount(), savedLimit); + + // setting the limit on children should have no effect on the parent + { + QThreadPool threadPool2(threadPool); + savedLimit = threadPool2.maxThreadCount(); + + // maxThreadCount() should always return the previous argument to + // setMaxThreadCount(), regardless of input + threadPool2.setMaxThreadCount(limit); + QCOMPARE(threadPool2.maxThreadCount(), limit); + + // the value returned from maxThreadCount() should always be valid input for setMaxThreadCount() + threadPool2.setMaxThreadCount(savedLimit); + QCOMPARE(threadPool2.maxThreadCount(), savedLimit); + } +} + +void tst_QThreadPool::setMaxThreadCountStartsAndStopsThreads() +{ + class WaitingTask : public QRunnable + { + public: + QSemaphore waitForStarted, waitToFinish; + + WaitingTask() { setAutoDelete(false); } + + void run() + { + waitForStarted.release(); + waitToFinish.acquire(); + } + }; + + QThreadPool threadPool; + threadPool.setMaxThreadCount(1); + + WaitingTask *task = new WaitingTask; + threadPool.start(task); + QVERIFY(task->waitForStarted.tryAcquire(1, 1000)); + + // thread limit is 1, cannot start more tasks + threadPool.start(task); + QVERIFY(!task->waitForStarted.tryAcquire(1, 1000)); + + // increasing the limit by 1 should start the task immediately + threadPool.setMaxThreadCount(2); + QVERIFY(task->waitForStarted.tryAcquire(1, 1000)); + + // ... but we still cannot start more tasks + threadPool.start(task); + QVERIFY(!task->waitForStarted.tryAcquire(1, 1000)); + + // increasing the limit should be able to start more than one at a time + threadPool.start(task); + threadPool.setMaxThreadCount(4); + QVERIFY(task->waitForStarted.tryAcquire(2, 1000)); + + // ... but we still cannot start more tasks + threadPool.start(task); + threadPool.start(task); + QVERIFY(!task->waitForStarted.tryAcquire(2, 1000)); + + // decreasing the thread limit should cause the active thread count to go down + threadPool.setMaxThreadCount(2); + QCOMPARE(threadPool.activeThreadCount(), 4); + task->waitToFinish.release(2); + QTest::qWait(1000); + QCOMPARE(threadPool.activeThreadCount(), 2); + + // ... and we still cannot start more tasks + threadPool.start(task); + threadPool.start(task); + QVERIFY(!task->waitForStarted.tryAcquire(2, 1000)); + + // start all remaining tasks + threadPool.start(task); + threadPool.start(task); + threadPool.start(task); + threadPool.start(task); + threadPool.setMaxThreadCount(8); + QVERIFY(task->waitForStarted.tryAcquire(6, 1000)); + + task->waitToFinish.release(10); +// delete task; +} + + +void tst_QThreadPool::activeThreadCount() +{ + DEPENDS_ON("tryReserveThread()"); + DEPENDS_ON("reserveThread()"); + DEPENDS_ON("releaseThread()"); +} + +void tst_QThreadPool::reserveThread_data() +{ + setMaxThreadCount_data(); +} + +void tst_QThreadPool::reserveThread() +{ + QFETCH(int, limit); + QThreadPool *threadpool = QThreadPool::globalInstance(); + int savedLimit = threadpool->maxThreadCount(); + threadpool->setMaxThreadCount(limit); + + // reserve up to the limit + for (int i = 0; i < limit; ++i) + threadpool->reserveThread(); + + // reserveThread() should always reserve a thread, regardless of + // how many have been previously reserved + threadpool->reserveThread(); + QCOMPARE(threadpool->activeThreadCount(), (limit > 0 ? limit : 0) + 1); + threadpool->reserveThread(); + QCOMPARE(threadpool->activeThreadCount(), (limit > 0 ? limit : 0) + 2); + + // cleanup + threadpool->releaseThread(); + threadpool->releaseThread(); + for (int i = 0; i < limit; ++i) + threadpool->releaseThread(); + + // reserving threads in children should not effect the parent + { + QThreadPool threadpool2(threadpool); + threadpool2.setMaxThreadCount(limit); + + // reserve up to the limit + for (int i = 0; i < limit; ++i) + threadpool2.reserveThread(); + + // reserveThread() should always reserve a thread, regardless + // of how many have been previously reserved + threadpool2.reserveThread(); + QCOMPARE(threadpool2.activeThreadCount(), (limit > 0 ? limit : 0) + 1); + threadpool2.reserveThread(); + QCOMPARE(threadpool2.activeThreadCount(), (limit > 0 ? limit : 0) + 2); + + threadpool->reserveThread(); + QCOMPARE(threadpool->activeThreadCount(), 1); + threadpool->reserveThread(); + QCOMPARE(threadpool->activeThreadCount(), 2); + + // cleanup + threadpool2.releaseThread(); + threadpool2.releaseThread(); + threadpool->releaseThread(); + threadpool->releaseThread(); + while (threadpool2.activeThreadCount() > 0) + threadpool2.releaseThread(); + } + + // reset limit on global QThreadPool + threadpool->setMaxThreadCount(savedLimit); +} + +void tst_QThreadPool::releaseThread_data() +{ + setMaxThreadCount_data(); +} + +void tst_QThreadPool::releaseThread() +{ + QFETCH(int, limit); + QThreadPool *threadpool = QThreadPool::globalInstance(); + int savedLimit = threadpool->maxThreadCount(); + threadpool->setMaxThreadCount(limit); + + // reserve up to the limit + for (int i = 0; i < limit; ++i) + threadpool->reserveThread(); + + // release should decrease the number of reserved threads + int reserved = threadpool->activeThreadCount(); + while (reserved-- > 0) { + threadpool->releaseThread(); + QCOMPARE(threadpool->activeThreadCount(), reserved); + } + QCOMPARE(threadpool->activeThreadCount(), 0); + + // releaseThread() can release more than have been reserved + threadpool->releaseThread(); + QCOMPARE(threadpool->activeThreadCount(), -1); + threadpool->reserveThread(); + QCOMPARE(threadpool->activeThreadCount(), 0); + + // releasing threads in children should not effect the parent + { + QThreadPool threadpool2(threadpool); + threadpool2.setMaxThreadCount(limit); + + // reserve up to the limit + for (int i = 0; i < limit; ++i) + threadpool2.reserveThread(); + + // release should decrease the number of reserved threads + int reserved = threadpool2.activeThreadCount(); + while (reserved-- > 0) { + threadpool2.releaseThread(); + QCOMPARE(threadpool2.activeThreadCount(), reserved); + QCOMPARE(threadpool->activeThreadCount(), 0); + } + QCOMPARE(threadpool2.activeThreadCount(), 0); + QCOMPARE(threadpool->activeThreadCount(), 0); + + // releaseThread() can release more than have been reserved + threadpool2.releaseThread(); + QCOMPARE(threadpool2.activeThreadCount(), -1); + QCOMPARE(threadpool->activeThreadCount(), 0); + threadpool2.reserveThread(); + QCOMPARE(threadpool2.activeThreadCount(), 0); + QCOMPARE(threadpool->activeThreadCount(), 0); + } + + // reset limit on global QThreadPool + threadpool->setMaxThreadCount(savedLimit); +} + +QAtomicInt count; +class CountingRunnable : public QRunnable +{ + public: void run() + { + count.ref(); + } +}; + +void tst_QThreadPool::start() +{ + const int runs = 1000; + count = 0; + { + QThreadPool threadPool; + for (int i = 0; i< runs; ++i) { + threadPool.start(new CountingRunnable()); + } + } + QCOMPARE(int(count), runs); +} + +void tst_QThreadPool::tryStart() +{ + class WaitingTask : public QRunnable + { + public: + QSemaphore semaphore; + + WaitingTask() { setAutoDelete(false); } + + void run() + { + semaphore.acquire(); + count.ref(); + } + }; + + count = 0; + + WaitingTask task; + QThreadPool threadPool; + for (int i = 0; i < threadPool.maxThreadCount(); ++i) { + threadPool.start(&task); + } + QVERIFY(!threadPool.tryStart(&task)); + task.semaphore.release(threadPool.maxThreadCount()); + threadPool.waitForDone(); + QCOMPARE(int(count), threadPool.maxThreadCount()); +} + +QMutex mutex; +int activeThreads = 0; +int peakActiveThreads = 0; +void tst_QThreadPool::tryStartPeakThreadCount() +{ + class CounterTask : public QRunnable + { + public: + CounterTask() { setAutoDelete(false); } + + void run() + { + { + QMutexLocker lock(&mutex); + ++activeThreads; + peakActiveThreads = qMax(peakActiveThreads, activeThreads); + } + + QTest::qWait(100); + { + QMutexLocker lock(&mutex); + --activeThreads; + } + } + }; + + CounterTask task; + QThreadPool threadPool; + + for (int i = 0; i < 20; ++i) { + if (threadPool.tryStart(&task) == false) + QTest::qWait(10); + } + QCOMPARE(peakActiveThreads, QThread::idealThreadCount()); + + for (int i = 0; i < 20; ++i) { + if (threadPool.tryStart(&task) == false) + QTest::qWait(10); + } + QCOMPARE(peakActiveThreads, QThread::idealThreadCount()); +} + +void tst_QThreadPool::tryStartCount() +{ + class SleeperTask : public QRunnable + { + public: + SleeperTask() { setAutoDelete(false); } + + void run() + { + QTest::qWait(50); + } + }; + + SleeperTask task; + QThreadPool threadPool; + const int runs = 5; + + for (int i = 0; i < runs; ++i) { +// qDebug() << "iteration" << i; + int count = 0; + while (threadPool.tryStart(&task)) + ++count; + QCOMPARE(count, QThread::idealThreadCount()); + + QTest::qWait(100); + } +} + +void tst_QThreadPool::waitForDone() +{ + QTime total, pass; + total.start(); + + QThreadPool threadPool; + while (total.elapsed() < 10000) { + int runs; + runs = count = 0; + pass.restart(); + while (pass.elapsed() < 100) { + threadPool.start(new CountingRunnable()); + ++runs; + } + threadPool.waitForDone(); + QCOMPARE(int(count), runs); + + runs = count = 0; + pass.restart(); + while (pass.elapsed() < 100) { + threadPool.start(new CountingRunnable()); + threadPool.start(new CountingRunnable()); + runs += 2; + } + threadPool.waitForDone(); + QCOMPARE(int(count), runs); + } +} + +void tst_QThreadPool::waitForDoneTimeout() +{ + class BlockedTask : public QRunnable + { + public: + QMutex mutex; + BlockedTask() { setAutoDelete(false); } + + void run() + { + mutex.lock(); + mutex.unlock(); + QTest::qSleep(50); + } + }; + + QThreadPool threadPool; + + BlockedTask *task = new BlockedTask; + task->mutex.lock(); + threadPool.start(task); + QVERIFY(!threadPool.waitForDone(100)); + task->mutex.unlock(); + QVERIFY(threadPool.waitForDone(400)); +} + +void tst_QThreadPool::destroyingWaitsForTasksToFinish() +{ + QTime total, pass; + total.start(); + + while (total.elapsed() < 10000) { + int runs; + runs = count = 0; + { + QThreadPool threadPool; + pass.restart(); + while (pass.elapsed() < 100) { + threadPool.start(new CountingRunnable()); + ++runs; + } + } + QCOMPARE(int(count), runs); + + runs = count = 0; + { + QThreadPool threadPool; + pass.restart(); + while (pass.elapsed() < 100) { + threadPool.start(new CountingRunnable()); + threadPool.start(new CountingRunnable()); + runs += 2; + } + } + QCOMPARE(int(count), runs); + } +} + +void tst_QThreadPool::stressTest() +{ + class Task : public QRunnable + { + QSemaphore semaphore; + public: + Task() { setAutoDelete(false); } + + void start() + { + QThreadPool::globalInstance()->start(this); + } + + void wait() + { + semaphore.acquire(); + } + + void run() + { + semaphore.release(); + } + }; + + QTime total; + total.start(); + while (total.elapsed() < 30000) { + Task t; + t.start(); + t.wait(); + } +} + +QTEST_MAIN(tst_QThreadPool); +#include "tst_qthreadpool.moc" -- cgit v1.2.3