22using namespace std::chrono_literals;
26 void CoroTaskTest::testReturn ()
28 auto task = [] () -> Task<int> {
co_return 42; } ();
30 QCOMPARE (result, 42);
33 void CoroTaskTest::testWait ()
38 auto task = [] () -> Task<int>
46 QCOMPARE (result, 42);
47 QVERIFY (timer.elapsed () > 50);
50 void CoroTaskTest::testTaskDestr ()
52 bool continued =
false;
54 [] (
auto& continued) -> Task<void>
60 QTRY_VERIFY_WITH_TIMEOUT (continued, 20);
66 class MockReply :
public QNetworkReply
70 using QNetworkReply::QNetworkReply;
72 using QNetworkReply::setAttribute;
73 using QNetworkReply::setError;
74 using QNetworkReply::setFinished;
75 using QNetworkReply::setHeader;
76 using QNetworkReply::setOperation;
77 using QNetworkReply::setRawHeader;
78 using QNetworkReply::setRequest;
79 using QNetworkReply::setUrl;
81 void SetData (
const QByteArray& data)
83 Buffer_.setData (data);
84 Buffer_.open (QIODevice::ReadOnly);
85 open (QIODevice::ReadOnly);
88 qint64 readData (
char *data, qint64 maxSize)
override
90 return Buffer_.read (data, maxSize);
93 void abort ()
override
98 class MockNAM :
public QNetworkAccessManager
100 std::unique_ptr<MockReply> Reply_;
102 explicit MockNAM (std::unique_ptr<MockReply> reply)
103 : Reply_ { std::move (reply) }
107 MockReply& GetReply ()
112 QNetworkReply* createRequest (Operation op,
const QNetworkRequest& req, QIODevice*)
override
114 Reply_->setUrl (req.url ());
115 Reply_->setOperation (op);
116 Reply_->setRequest (req);
117 return Reply_.get ();
121 auto MkSuccessfulReply (
const QByteArray& data)
123 auto reply = std::make_unique<MockReply> ();
124 reply->setAttribute (QNetworkRequest::HttpStatusCodeAttribute, 200);
125 reply->SetData (data);
131 auto reply = std::make_unique<MockReply> ();
132 reply->setAttribute (QNetworkRequest::HttpStatusCodeAttribute, 404);
133 reply->setError (QNetworkReply::NetworkError::ContentAccessDenied,
"well, 404!"_qs);
137 void TestGoodReply (
auto finishMarker)
139 const QByteArray data {
"this is some test data" };
140 MockNAM nam { MkSuccessfulReply (data) };
141 finishMarker (nam.GetReply ());
145 auto reply =
co_await *nam.get (QNetworkRequest { QUrl {
"http://example.com/foo.txt"_qs } });
146 co_return reply.GetReplyData ();
150 QCOMPARE (result, data);
153 void TestBadReply (
auto finishMarker)
155 MockNAM nam { MkErrorReply () };
156 finishMarker (nam.GetReply ());
160 auto reply =
co_await *nam.get (QNetworkRequest { QUrl {
"http://example.com/foo.txt"_qs } });
161 co_return reply.GetReplyData ();
164 QVERIFY_EXCEPTION_THROWN (
GetTaskResult (task), LC::Util::NetworkReplyErrorException);
167 void ImmediateFinishMarker (MockReply& reply)
169 reply.setFinished (
true);
172 void DelayedFinishMarker (MockReply& reply)
174 QTimer::singleShot (10ms,
177 reply.setFinished (
true);
178 emit reply.finished ();
183 void CoroTaskTest::testNetworkReplyGoodNoWait ()
185 TestGoodReply (&ImmediateFinishMarker);
188 void CoroTaskTest::testNetworkReplyGoodWait ()
190 TestGoodReply (&DelayedFinishMarker);
193 void CoroTaskTest::testNetworkReplyBadNoWait ()
195 TestBadReply (&ImmediateFinishMarker);
198 void CoroTaskTest::testNetworkReplyBadWait ()
200 TestBadReply (&DelayedFinishMarker);
203 void CoroTaskTest::testContextDestrBeforeFinish ()
205 auto context = std::make_unique<QObject> ();
206 auto task = [] (QObject *context) -> Task<int, ContextExtensions>
208 co_await AddContextObject { *context };
210 co_return context->children ().size ();
214 QVERIFY_EXCEPTION_THROWN (
GetTaskResult (task), LC::Util::ContextDeadException);
217 void CoroTaskTest::testContextDestrAfterFinish ()
219 auto context = std::make_unique<QObject> ();
220 auto task = [] (QObject *context) -> Task<int, ContextExtensions>
222 co_await AddContextObject { *context };
224 co_return context->children ().size ();
230 void CoroTaskTest::testWaitMany ()
232 constexpr auto max = 100;
233 auto mkTask = [] (
int index) -> Task<int>
235 co_await Precisely { std::chrono::milliseconds {
max - index } };
241 QVector<Task<int>> tasks;
242 QVector<int> expected;
243 for (
int i = 0; i <
max; ++i)
248 const auto creationElapsed = timer.elapsed ();
252 const auto executionElapsed = timer.elapsed ();
254 QCOMPARE (result, expected);
255 QVERIFY (creationElapsed < 1);
256 constexpr auto tolerance = 1.05;
257 QVERIFY (executionElapsed < max * tolerance);
260 void CoroTaskTest::testWaitManyTuple ()
262 auto mkTask = [] (
int delay) -> Task<int>
264 co_await Precisely { std::chrono::milliseconds { delay } };
271 const auto executionElapsed = timer.elapsed ();
273 QCOMPARE (result, (std::tuple { 10, 9, 2, 1 }));
274 constexpr auto tolerance = 1.05;
275 QVERIFY (executionElapsed < 10 * tolerance);
278 void CoroTaskTest::testEither ()
280 using Result_t = Either<QString, bool>;
282 auto immediatelyFailing = [] () -> Task<Result_t>
285 co_return Result_t::Right (theInt > 420);
287 QCOMPARE (
GetTaskResult (immediatelyFailing), Result_t::Left (
"meh"));
289 auto earlyFailing = [] () -> Task<Result_t>
293 co_return Result_t::Right (theInt > 420);
295 QCOMPARE (
GetTaskResult (earlyFailing), Result_t::Left (
"meh"));
297 auto successful = [] () -> Task<Result_t>
301 co_return Result_t::Right (theInt > 420);
303 QCOMPARE (
GetTaskResult (successful), Result_t::Right (
false));
306 void CoroTaskTest::testThrottleSameCoro ()
309 constexpr auto count = 10;
313 auto task = [] (
auto& t) -> Task<int>
316 for (
int i = 0; i <
count; ++i)
324 const auto time = timer.elapsed ();
326 QCOMPARE (result, count * (count - 1) / 2);
327 QVERIFY (time >= count * t.GetInterval ().count ());
330 void CoroTaskTest::testThrottleSameCoroSlow ()
333 constexpr auto count = 10;
337 auto task = [] (
auto& t) -> Task<void>
339 for (
int i = 0; i <
count; ++i)
347 const auto time = timer.elapsed ();
349 const auto expectedMinTime =
count * t.GetInterval ().count ();
350 QVERIFY (time >= expectedMinTime);
351 QVERIFY (time - expectedMinTime <= expectedMinTime * 0.05);
354 void CoroTaskTest::testThrottleManyCoros ()
356 Throttle t { 1ms, Qt::TimerType::PreciseTimer };
357 constexpr auto count = 10;
361 auto mkTask = [] (
auto& t) -> Task<void>
363 for (
int i = 0; i <
count; ++i)
366 QVector tasks { mkTask (t), mkTask (t), mkTask (t) };
367 for (
auto& task : tasks)
369 const auto time = timer.elapsed ();
371 QVERIFY (time >= count * tasks.size () * t.GetInterval ().count ());
static Either Left(const L &l)
static Either Right(R &&r)
constexpr detail::AggregateType< detail::AggregateFunction::Count, Ptr > count
constexpr detail::AggregateType< detail::AggregateFunction::Max, Ptr > max
Task< QVector< T >, Exts... > InParallel(QVector< Task< T, Exts... > > tasks)
WithPrecision< Qt::PreciseTimer > Precisely
T GetTaskResult(Task< T, Extensions... > task)