/* * Copyright 2014 Daniel Vrátil * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License or (at your option) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ #include "../src/async.h" #include #include #include #include #include class AsyncTest : public QObject { Q_OBJECT public: AsyncTest() {} ~AsyncTest() {} private Q_SLOTS: void testSyncPromises(); void testAsyncPromises(); void testAsyncPromises2(); void testNestedAsync(); void testStartValue(); void testAsyncThen(); void testSyncThen(); void testJoinedThen(); void testAsyncEach(); void testSyncEach(); void testJoinedEach(); void testAsyncReduce(); void testSyncReduce(); void testJoinedReduce(); void testErrorHandler(); void benchmarkSyncThenExecutor(); private: template class AsyncSimulator { public: AsyncSimulator(Async::Future &future, const T &result) : mFuture(future) , mResult(result) { QObject::connect(&mTimer, &QTimer::timeout, [this]() { mFuture.setValue(mResult); mFuture.setFinished(); }); QObject::connect(&mTimer, &QTimer::timeout, [this]() { delete this; }); mTimer.setSingleShot(true); mTimer.start(200); } private: Async::Future mFuture; T mResult; QTimer mTimer; }; }; void AsyncTest::testSyncPromises() { auto baseJob = Async::start( [](Async::Future &f) { f.setValue(42); f.setFinished(); }) .then( [](int v, Async::Future &f) { f.setValue("Result is " + QString::number(v)); f.setFinished(); }); auto job = baseJob.then( [](const QString &v, Async::Future &f) { f.setValue(v.toUpper()); f.setFinished(); }); Async::Future future = job.exec(); QVERIFY(future.isFinished()); QCOMPARE(future.value(), QString::fromLatin1("RESULT IS 42")); } void AsyncTest::testAsyncPromises() { auto job = Async::start( [](Async::Future &future) { new AsyncSimulator(future, 42); }); Async::Future future = job.exec(); future.waitForFinished(); QCOMPARE(future.value(), 42); } void AsyncTest::testAsyncPromises2() { bool done = false; auto job = Async::start( [](Async::Future &future) { new AsyncSimulator(future, 42); } ).then([&done](int result, Async::Future &future) { done = true; future.setValue(result); future.setFinished(); }); auto future = job.exec(); QTRY_VERIFY(done); QCOMPARE(future.value(), 42); } void AsyncTest::testNestedAsync() { bool done = false; auto job = Async::start( [](Async::Future &future) { auto innerJob = Async::start([](Async::Future &innerFuture) { new AsyncSimulator(innerFuture, 42); }).then([&future](Async::Future &innerThenFuture) { future.setFinished(); innerThenFuture.setFinished(); }); innerJob.exec().waitForFinished(); } ).then([&done](int result, Async::Future &future) { done = true; future.setValue(result); future.setFinished(); }); job.exec(); QTRY_VERIFY(done); } void AsyncTest::testStartValue() { auto job = Async::start( [](int in, Async::Future &future) { future.setValue(in); future.setFinished(); }); auto future = job.exec(42); QVERIFY(future.isFinished()); QCOMPARE(future.value(), 42); } void AsyncTest::testAsyncThen() { auto job = Async::start( [](Async::Future &future) { new AsyncSimulator(future, 42); }); auto future = job.exec(); future.waitForFinished(); QVERIFY(future.isFinished()); QCOMPARE(future.value(), 42); } void AsyncTest::testSyncThen() { auto job = Async::start( []() -> int { return 42; }).then( [](int in) -> int { return in * 2; }); auto future = job.exec(); QVERIFY(future.isFinished()); QCOMPARE(future.value(), 84); } void AsyncTest::testJoinedThen() { auto job1 = Async::start( [](int in, Async::Future &future) { new AsyncSimulator(future, in * 2); }); auto job2 = Async::start( [](Async::Future &future) { new AsyncSimulator(future, 42); }) .then(job1); auto future = job2.exec(); future.waitForFinished(); QVERIFY(future.isFinished()); QCOMPARE(future.value(), 84); } void AsyncTest::testAsyncEach() { auto job = Async::start>( [](Async::Future> &future) { new AsyncSimulator>(future, { 1, 2, 3, 4 }); }) .each, int>( [](const int &v, Async::Future> &future) { new AsyncSimulator>(future, { v + 1 }); }); auto future = job.exec(); future.waitForFinished(); const QList expected({ 2, 3, 4, 5 }); QVERIFY(future.isFinished()); QCOMPARE(future.value(), expected); } void AsyncTest::testSyncEach() { auto job = Async::start>( []() -> QList { return { 1, 2, 3, 4 }; }) .each, int>( [](const int &v) -> QList { return { v + 1 }; }); Async::Future> future = job.exec(); const QList expected({ 2, 3, 4, 5 }); QVERIFY(future.isFinished()); QCOMPARE(future.value(), expected); } void AsyncTest::testJoinedEach() { auto job1 = Async::start, int>( [](int v, Async::Future> &future) { new AsyncSimulator>(future, { v * 2 }); }); auto job = Async::start>( []() -> QList { return { 1, 2, 3, 4 }; }) .each(job1); auto future = job.exec(); future.waitForFinished(); const QList expected({ 2, 4, 6, 8 }); QVERIFY(future.isFinished()); QCOMPARE(future.value(), expected); } void AsyncTest::testAsyncReduce() { auto job = Async::start>( [](Async::Future> &future) { new AsyncSimulator>(future, { 1, 2, 3, 4 }); }) .reduce>( [](const QList &list, Async::Future &future) { QTimer *timer = new QTimer(); QObject::connect(timer, &QTimer::timeout, [list, &future]() { int sum = 0; for (int i : list) sum += i; future.setValue(sum); future.setFinished(); }); QObject::connect(timer, &QTimer::timeout, timer, &QObject::deleteLater); timer->setSingleShot(true); timer->start(0); }); Async::Future future = job.exec(); future.waitForFinished(); QVERIFY(future.isFinished()); QCOMPARE(future.value(), 10); } void AsyncTest::testSyncReduce() { auto job = Async::start>( []() -> QList { return { 1, 2, 3, 4 }; }) .reduce>( [](const QList &list) -> int { int sum = 0; for (int i : list) sum += i; return sum; }); Async::Future future = job.exec(); QVERIFY(future.isFinished()); QCOMPARE(future.value(), 10); } void AsyncTest::testJoinedReduce() { auto job1 = Async::start>( [](const QList &list, Async::Future &future) { int sum = 0; for (int i : list) sum += i; new AsyncSimulator(future, sum); }); auto job = Async::start>( []() -> QList { return { 1, 2, 3, 4 }; }) .reduce(job1); auto future = job.exec(); future.waitForFinished(); QVERIFY(future.isFinished()); QCOMPARE(future.value(), 10); } void AsyncTest::testErrorHandler() { int error = 0; auto job = Async::start( [](Async::Future &f) { f.setError(1, "error"); }) .then( [](int v, Async::Future &f) { f.setFinished(); }, [&error](int errorCode, const QString &errorMessage) { error = errorCode; } ); auto future = job.exec(); future.waitForFinished(); QCOMPARE(error, 1); QVERIFY(future.isFinished()); } void AsyncTest::benchmarkSyncThenExecutor() { auto job = Async::start( []() -> int { return 0; }); QBENCHMARK { job.exec(); } } QTEST_MAIN(AsyncTest); #include "asynctest.moc"