libcopp 2.3.2
Loading...
Searching...
No Matches
task_promise_test.cpp
Go to the documentation of this file.
1// Copyright 2026 owent
2
7
8#include <cstdio>
9#include <cstring>
10#include <iostream>
11#include <list>
12#include <string>
13#include <vector>
14
15#include "frame/test_macros.h"
16
17#if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
18
19namespace {
20struct task_future_private_data {
21 int data;
22};
23
24using task_future_int_type = cotask::task_future<int, task_future_private_data>;
25using task_future_void_type = cotask::task_future<void, task_future_private_data>;
26using task_future_int_type_no_private_data = cotask::task_future<int, void>;
27using task_future_void_type_no_private_data = cotask::task_future<void, void>;
28using callable_future_int_type = copp::callable_future<int>;
29using callable_future_void_type = copp::callable_future<void>;
30using generator_future_int_type = copp::generator_future<int>;
31using generator_future_void_type = copp::generator_future<void>;
32
33std::list<generator_future_int_type::context_pointer_type> g_task_future_pending_int_contexts;
34std::list<generator_future_void_type::context_pointer_type> g_task_future_pending_void_contexts;
35size_t g_task_future_resume_generator_count = 0;
36size_t g_task_future_suspend_generator_count = 0;
37
38static size_t resume_pending_contexts(std::list<int> values, int max_count = 32767) {
39 size_t ret = 0;
40 while (max_count > 0 &&
41 (!g_task_future_pending_int_contexts.empty() || !g_task_future_pending_void_contexts.empty())) {
42 --max_count;
43 if (!g_task_future_pending_int_contexts.empty()) {
44 auto ctx = *g_task_future_pending_int_contexts.begin();
45 g_task_future_pending_int_contexts.pop_front();
46
47 if (!values.empty()) {
48 int val = values.front();
49 values.pop_front();
50 ctx->set_value(val);
51 } else {
52 ctx->set_value(0);
53 }
54
55 ++ret;
56 }
57
58 if (!g_task_future_pending_void_contexts.empty()) {
59 auto ctx = *g_task_future_pending_void_contexts.begin();
60 g_task_future_pending_void_contexts.pop_front();
61 ctx->set_value();
62
63 ++ret;
64 }
65 }
66
67 return ret;
68}
69
70static void generator_int_suspend_callback(generator_future_int_type::context_pointer_type ctx) {
71 ++g_task_future_suspend_generator_count;
72 g_task_future_pending_int_contexts.push_back(ctx);
73}
74static void generator_int_resume_callback(const generator_future_int_type::context_type &) {
75 ++g_task_future_resume_generator_count;
76}
77
78static callable_future_int_type task_future_func_int_l1(int inout) {
79 CASE_MSG_INFO() << "callable inner future ready int: " << inout << std::endl;
80 co_return inout;
81}
82
83static callable_future_int_type task_future_func_int_l2(int inout) {
84 generator_future_int_type generator{generator_int_suspend_callback, generator_int_resume_callback};
85 auto gen_res = co_await generator;
86 if (gen_res < 0) {
87 co_return gen_res;
88 }
89 co_return inout + gen_res;
90}
91
92static callable_future_int_type task_future_func_await_int() {
93 auto v = task_future_func_int_l1(3);
94 auto u = task_future_func_int_l2(11);
95 int x = (co_await v + co_await u);
96 co_return x;
97}
98
99static task_future_int_type task_func_await_int() {
100 auto current_status = co_yield task_future_void_type::yield_status();
101 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(current_status));
102 auto private_data = co_yield task_future_int_type::yield_private_data();
103 private_data->data = 121000;
104
105 CASE_MSG_INFO() << "task await int" << std::endl;
106 auto v = task_future_func_await_int();
107 int x = co_await v;
108 CASE_MSG_INFO() << "task return int" << std::endl;
109 co_return x;
110}
111
112static callable_future_int_type task_future_func_no_wait_int() {
113 auto v = task_future_func_int_l1(7);
114 auto u = task_future_func_int_l1(19);
115 int x = (co_await v + co_await u);
116 co_return x;
117}
118
119static task_future_int_type task_func_no_wait_int() {
120 auto current_status = co_yield task_future_void_type::yield_status();
121 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(current_status));
122 auto private_data = co_yield cotask::task_private_data<task_future_private_data>();
123 private_data->data = 121000;
124
125 CASE_MSG_INFO() << "task await int" << std::endl;
126 auto v = task_future_func_no_wait_int();
127 int x = co_await v;
128 CASE_MSG_INFO() << "task return int" << std::endl;
129 co_return x;
130}
131
132static void generator_void_suspend_callback(generator_future_void_type::context_pointer_type ctx) {
133 ++g_task_future_suspend_generator_count;
134 g_task_future_pending_void_contexts.push_back(ctx);
135}
136static void generator_void_resume_callback(const generator_future_void_type::context_type &) {
137 ++g_task_future_resume_generator_count;
138}
139
140static callable_future_void_type task_future_func_void_l1() {
141 CASE_MSG_INFO() << "callable inner future ready void" << std::endl;
142 co_return;
143}
144
145static callable_future_void_type task_future_func_void_l2() {
146 generator_future_void_type generator{generator_void_suspend_callback, generator_void_resume_callback};
147 co_await generator;
148 co_return;
149}
150
151static callable_future_void_type task_future_func_await_void() {
152 auto v = task_future_func_void_l1();
153 auto u = task_future_func_void_l2();
154 co_await v;
155 co_await u;
156 co_return;
157}
158
159static task_future_void_type task_func_await_void() {
160 auto current_status = co_yield task_future_void_type::yield_status();
161 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(current_status));
162 auto private_data = co_yield task_future_void_type::yield_private_data();
163 private_data->data = 123000;
164
165 CASE_MSG_INFO() << "task await void" << std::endl;
166 auto v = task_future_func_await_void();
167 co_await v;
168 CASE_MSG_INFO() << "task return void" << std::endl;
169 co_return;
170}
171
172static callable_future_void_type task_future_func_no_wait_void() {
173 auto v = task_future_func_void_l1();
174 auto u = task_future_func_void_l1();
175 co_await v;
176 co_await u;
177 co_return;
178}
179
180static task_future_void_type task_func_no_wait_void() {
181 auto current_status = co_yield task_future_void_type::yield_status();
182 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(current_status));
183 auto private_data = co_yield cotask::task_private_data<task_future_private_data>();
184 private_data->data = 123000;
185
186 CASE_MSG_INFO() << "task await void" << std::endl;
187 auto v = task_future_func_no_wait_void();
188 co_await v;
189 CASE_MSG_INFO() << "task return void" << std::endl;
190 co_return;
191}
192
193static task_future_void_type_no_private_data task_func_await_pick_task_id(
194 task_future_void_type_no_private_data::id_type &output) {
195 output = co_yield task_future_void_type_no_private_data::yield_task_id();
196
197 co_return;
198}
199
200} // namespace
201
202CASE_TEST(task_promise, task_future_void_yield_task_id) {
203 task_future_void_type_no_private_data::id_type task_id = 0;
204 task_future_void_type_no_private_data t = task_func_await_pick_task_id(task_id);
205
206 CASE_EXPECT_NE(0, t.get_id());
207 CASE_EXPECT_EQ(0, task_id);
208 CASE_EXPECT_TRUE(t.start());
209
210 CASE_EXPECT_EQ(t.get_id(), task_id);
211
212 CASE_EXPECT_TRUE(t.valid());
214}
215
216CASE_TEST(task_promise, task_future_integer_need_resume) {
217 size_t old_resume_generator_count = g_task_future_resume_generator_count;
218 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
219
220 task_future_int_type t = task_func_await_int();
221 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kCreated), static_cast<int>(t.get_status()));
222 CASE_EXPECT_FALSE(t.is_canceled());
223 CASE_EXPECT_FALSE(t.is_faulted());
224 CASE_EXPECT_FALSE(t.is_timeout());
225 CASE_EXPECT_FALSE(t.is_exiting());
226 CASE_EXPECT_FALSE(t.is_completed());
227
228 CASE_EXPECT_TRUE(t.start());
229 CASE_EXPECT_EQ(121000, t.get_private_data()->data);
230 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(t.get_status()));
231 CASE_EXPECT_FALSE(t.is_canceled());
232 CASE_EXPECT_FALSE(t.is_faulted());
233 CASE_EXPECT_FALSE(t.is_timeout());
234 CASE_EXPECT_FALSE(t.is_exiting());
235 CASE_EXPECT_FALSE(t.is_completed());
236
237 resume_pending_contexts({100});
238 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kDone), static_cast<int>(t.get_status()));
239 CASE_EXPECT_FALSE(t.is_canceled());
240 CASE_EXPECT_FALSE(t.is_faulted());
241 CASE_EXPECT_FALSE(t.is_timeout());
242 CASE_EXPECT_TRUE(t.is_exiting());
243 CASE_EXPECT_TRUE(t.is_completed());
244 CASE_EXPECT_EQ(114, *t.get_context()->data());
245
246 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
247 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
248}
249
250CASE_TEST(task_promise, task_future_void_need_resume) {
251 size_t old_resume_generator_count = g_task_future_resume_generator_count;
252 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
253
254 task_future_void_type t = task_func_await_void();
255 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kCreated), static_cast<int>(t.get_status()));
256 CASE_EXPECT_FALSE(t.is_canceled());
257 CASE_EXPECT_FALSE(t.is_faulted());
258 CASE_EXPECT_FALSE(t.is_timeout());
259 CASE_EXPECT_FALSE(t.is_exiting());
260 CASE_EXPECT_FALSE(t.is_completed());
261
262 CASE_EXPECT_TRUE(t.start());
263 CASE_EXPECT_EQ(123000, t.get_private_data()->data);
264 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(t.get_status()));
265 CASE_EXPECT_FALSE(t.is_canceled());
266 CASE_EXPECT_FALSE(t.is_faulted());
267 CASE_EXPECT_FALSE(t.is_timeout());
268 CASE_EXPECT_FALSE(t.is_exiting());
269 CASE_EXPECT_FALSE(t.is_completed());
270
271 resume_pending_contexts({100});
272 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kDone), static_cast<int>(t.get_status()));
273 CASE_EXPECT_FALSE(t.is_canceled());
274 CASE_EXPECT_FALSE(t.is_faulted());
275 CASE_EXPECT_FALSE(t.is_timeout());
276 CASE_EXPECT_TRUE(t.is_exiting());
277 CASE_EXPECT_TRUE(t.is_completed());
278
279 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
280 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
281}
282
283CASE_TEST(task_promise, task_future_integer_no_resume) {
284 size_t old_resume_generator_count = g_task_future_resume_generator_count;
285 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
286
287 task_future_int_type t = task_func_no_wait_int();
288 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kCreated), static_cast<int>(t.get_status()));
289 CASE_EXPECT_FALSE(t.is_canceled());
290 CASE_EXPECT_FALSE(t.is_faulted());
291 CASE_EXPECT_FALSE(t.is_timeout());
292 CASE_EXPECT_FALSE(t.is_exiting());
293 CASE_EXPECT_FALSE(t.is_completed());
294
295 CASE_EXPECT_TRUE(t.start());
296 CASE_EXPECT_EQ(121000, t.get_private_data()->data);
297 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kDone), static_cast<int>(t.get_status()));
298 CASE_EXPECT_FALSE(t.is_canceled());
299 CASE_EXPECT_FALSE(t.is_faulted());
300 CASE_EXPECT_FALSE(t.is_timeout());
301 CASE_EXPECT_TRUE(t.is_exiting());
302 CASE_EXPECT_TRUE(t.is_completed());
303 CASE_EXPECT_EQ(26, *t.get_context()->data());
304
305 CASE_EXPECT_EQ(old_resume_generator_count, g_task_future_resume_generator_count);
306 CASE_EXPECT_EQ(old_suspend_generator_count, g_task_future_suspend_generator_count);
307}
308
309CASE_TEST(task_promise, task_future_void_no_resume) {
310 size_t old_resume_generator_count = g_task_future_resume_generator_count;
311 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
312
313 task_future_void_type t = task_func_no_wait_void();
314 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kCreated), static_cast<int>(t.get_status()));
315 CASE_EXPECT_FALSE(t.is_canceled());
316 CASE_EXPECT_FALSE(t.is_faulted());
317 CASE_EXPECT_FALSE(t.is_timeout());
318 CASE_EXPECT_FALSE(t.is_exiting());
319 CASE_EXPECT_FALSE(t.is_completed());
320
321 CASE_EXPECT_TRUE(t.start());
322 CASE_EXPECT_EQ(123000, t.get_private_data()->data);
323 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kDone), static_cast<int>(t.get_status()));
324 CASE_EXPECT_FALSE(t.is_canceled());
325 CASE_EXPECT_FALSE(t.is_faulted());
326 CASE_EXPECT_FALSE(t.is_timeout());
327 CASE_EXPECT_TRUE(t.is_exiting());
328 CASE_EXPECT_TRUE(t.is_completed());
329
330 CASE_EXPECT_EQ(old_resume_generator_count, g_task_future_resume_generator_count);
331 CASE_EXPECT_EQ(old_suspend_generator_count, g_task_future_suspend_generator_count);
332}
333
334namespace {
335static task_future_int_type task_func_await_int_generator() {
336 generator_future_int_type generator{generator_int_suspend_callback, generator_int_resume_callback};
337 auto res = co_await generator;
338 co_return 235 + res;
339}
340
341static callable_future_int_type task_future_func_await_int_task() {
342 task_future_int_type t = task_func_await_int_generator();
343 t.start();
344 auto res = co_await t;
345 co_return res;
346}
347
348static task_future_int_type task_func_await_int_task() {
349 task_future_int_type t = task_func_await_int_generator();
350 t.start();
351 auto res = co_await t;
352 co_return res;
353}
354} // namespace
355
356CASE_TEST(task_promise, callable_future_await_task) {
357 size_t old_resume_generator_count = g_task_future_resume_generator_count;
358 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
359
360 callable_future_int_type f = task_future_func_await_int_task();
361 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(f.get_status()));
362
363 CASE_EXPECT_FALSE(f.is_ready());
364
365 resume_pending_contexts({1000});
366 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kDone), static_cast<int>(f.get_status()));
367 CASE_EXPECT_TRUE(f.is_ready());
368 CASE_EXPECT_EQ(1235, f.get_internal_promise().data());
369
370 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
371 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
372}
373
374CASE_TEST(task_promise, task_future_await_task) {
375 size_t old_resume_generator_count = g_task_future_resume_generator_count;
376 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
377
378 task_future_int_type t = task_func_await_int_task();
379 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kCreated), static_cast<int>(t.get_status()));
380 CASE_EXPECT_FALSE(t.is_canceled());
381 CASE_EXPECT_FALSE(t.is_faulted());
382 CASE_EXPECT_FALSE(t.is_timeout());
383 CASE_EXPECT_FALSE(t.is_exiting());
384 CASE_EXPECT_FALSE(t.is_completed());
385
386 CASE_EXPECT_TRUE(t.start());
387 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(t.get_status()));
388 CASE_EXPECT_FALSE(t.is_canceled());
389 CASE_EXPECT_FALSE(t.is_faulted());
390 CASE_EXPECT_FALSE(t.is_timeout());
391 CASE_EXPECT_FALSE(t.is_exiting());
392 CASE_EXPECT_FALSE(t.is_completed());
393
394 resume_pending_contexts({2000});
395 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kDone), static_cast<int>(t.get_status()));
396 CASE_EXPECT_FALSE(t.is_canceled());
397 CASE_EXPECT_FALSE(t.is_faulted());
398 CASE_EXPECT_FALSE(t.is_timeout());
399 CASE_EXPECT_TRUE(t.is_exiting());
400 CASE_EXPECT_TRUE(t.is_completed());
401 CASE_EXPECT_EQ(2235, *t.get_context()->data());
402
403 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
404 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
405}
406
407namespace {
408std::list<generator_future_int_type::context_pointer_type> g_task_future_fifo_blocker_contexts;
409std::vector<int> g_task_future_fifo_resume_order;
410
411static void generator_fifo_blocker_suspend_callback(generator_future_int_type::context_pointer_type ctx) {
412 g_task_future_fifo_blocker_contexts.push_back(ctx);
413}
414static void generator_fifo_blocker_resume_callback(const generator_future_int_type::context_type &) {}
415
416static task_future_int_type task_func_fifo_blocker() {
417 generator_future_int_type generator{generator_fifo_blocker_suspend_callback, generator_fifo_blocker_resume_callback};
418 auto res = co_await generator;
419 co_return res;
420}
421
422static callable_future_int_type task_future_func_fifo_waiter(task_future_int_type waiting, int index) {
423 int res = co_await waiting;
424 if (res >= 0) {
425 g_task_future_fifo_resume_order.push_back(index);
426 }
427 co_return res;
428}
429} // namespace
430
431CASE_TEST(task_promise, task_future_multiple_callers_resume_fifo) {
432 g_task_future_fifo_blocker_contexts.clear();
433 g_task_future_fifo_resume_order.clear();
434
435 task_future_int_type blocker = task_func_fifo_blocker();
436 CASE_EXPECT_TRUE(blocker.start());
437 CASE_EXPECT_FALSE(blocker.is_exiting());
438 CASE_EXPECT_EQ(1, static_cast<int>(g_task_future_fifo_blocker_contexts.size()));
439
440 constexpr int k_waiter_count = 8;
441 std::vector<callable_future_int_type> waiters;
442 for (int index = 0; index < k_waiter_count; ++index) {
443 waiters.push_back(task_future_func_fifo_waiter(blocker, index));
444 // Each waiter registers into the blocker's caller manager and stays parked.
445 CASE_EXPECT_FALSE(waiters.back().is_ready());
446 CASE_EXPECT_FALSE(blocker.is_exiting());
447 }
448
449 // Completing the blocker resumes every caller in registration (FIFO) order.
450 auto pending_context = g_task_future_fifo_blocker_contexts.front();
451 g_task_future_fifo_blocker_contexts.pop_front();
452 pending_context->set_value(0);
453
454 CASE_EXPECT_TRUE(blocker.is_exiting());
455 CASE_EXPECT_EQ(k_waiter_count, static_cast<int>(g_task_future_fifo_resume_order.size()));
456 for (int index = 0; index < k_waiter_count; ++index) {
457 CASE_EXPECT_EQ(index, g_task_future_fifo_resume_order[static_cast<size_t>(index)]);
458 CASE_EXPECT_TRUE(waiters[static_cast<size_t>(index)].is_ready());
459 }
460}
461
462CASE_TEST(task_promise, task_future_multiple_callers_resume_fifo_after_first_killed) {
463 g_task_future_fifo_blocker_contexts.clear();
464 g_task_future_fifo_resume_order.clear();
465
466 task_future_int_type blocker = task_func_fifo_blocker();
467 CASE_EXPECT_TRUE(blocker.start());
468 callable_future_int_type waiter0 = task_future_func_fifo_waiter(blocker, 0);
469 callable_future_int_type waiter1 = task_future_func_fifo_waiter(blocker, 1);
470 CASE_EXPECT_FALSE(waiter0.is_ready());
471 CASE_EXPECT_FALSE(waiter1.is_ready());
472
473 // Killing the first waiter detaches it while the second waiter remains queued.
474 CASE_EXPECT_TRUE(waiter0.kill());
475 CASE_EXPECT_TRUE(waiter0.is_ready());
476 CASE_EXPECT_FALSE(blocker.is_exiting());
477 CASE_EXPECT_FALSE(waiter1.is_ready());
478 CASE_EXPECT_TRUE(g_task_future_fifo_resume_order.empty());
479
480 callable_future_int_type waiter2 = task_future_func_fifo_waiter(blocker, 2);
481 CASE_EXPECT_FALSE(waiter2.is_ready());
482 CASE_EXPECT_EQ(1, static_cast<int>(g_task_future_fifo_blocker_contexts.size()));
483 if (!g_task_future_fifo_blocker_contexts.empty()) {
484 auto pending_context = g_task_future_fifo_blocker_contexts.front();
485 g_task_future_fifo_blocker_contexts.pop_front();
486 pending_context->set_value(0);
487 }
488
489 CASE_EXPECT_TRUE(blocker.is_exiting());
490 CASE_EXPECT_TRUE(waiter1.is_ready());
491 CASE_EXPECT_TRUE(waiter2.is_ready());
492 CASE_EXPECT_EQ(2, static_cast<int>(g_task_future_fifo_resume_order.size()));
493 if (g_task_future_fifo_resume_order.size() == 2) {
494 CASE_EXPECT_EQ(1, g_task_future_fifo_resume_order[0]);
495 CASE_EXPECT_EQ(2, g_task_future_fifo_resume_order[1]);
496 }
497}
498
499CASE_TEST(task_promise, task_future_caller_manager_dedup_and_remove) {
500 g_task_future_fifo_blocker_contexts.clear();
501 g_task_future_fifo_resume_order.clear();
502
503 task_future_int_type blocker = task_func_fifo_blocker();
504 CASE_EXPECT_TRUE(blocker.start());
505 CASE_EXPECT_FALSE(blocker.is_exiting());
506
507 // Suspended waiters give us valid, non-done coroutine handles to drive the caller manager directly.
508 callable_future_int_type waiter0 = task_future_func_fifo_waiter(blocker, 0);
509 callable_future_int_type waiter1 = task_future_func_fifo_waiter(blocker, 1);
510 callable_future_int_type waiter2 = task_future_func_fifo_waiter(blocker, 2);
511 CASE_EXPECT_FALSE(waiter0.is_ready());
512 CASE_EXPECT_FALSE(waiter1.is_ready());
513 CASE_EXPECT_FALSE(waiter2.is_ready());
514
515 using caller_delegate = copp::promise_caller_manager::handle_delegate;
516 copp::promise_caller_manager manager;
517 CASE_EXPECT_FALSE(manager.has_multiple_callers());
518
519 // Re-adding the same handle while it's the only caller keeps a single caller.
520 manager.add_caller(caller_delegate{waiter0.get_internal_handle()});
521 manager.add_caller(caller_delegate{waiter0.get_internal_handle()});
522 CASE_EXPECT_FALSE(manager.has_multiple_callers());
523
524 // Removing a handle that was never registered returns false while single caller.
525 CASE_EXPECT_FALSE(manager.remove_caller(caller_delegate{waiter1.get_internal_handle()}));
526
527 // Convert to multiple callers, then a repeated registration is still ignored.
528 manager.add_caller(caller_delegate{waiter1.get_internal_handle()});
529 manager.add_caller(caller_delegate{waiter0.get_internal_handle()});
530 manager.add_caller(caller_delegate{waiter1.get_internal_handle()});
531 CASE_EXPECT_TRUE(manager.has_multiple_callers());
532
533 // Removing a handle not present in multi-caller mode returns false.
534 CASE_EXPECT_FALSE(manager.remove_caller(caller_delegate{waiter2.get_internal_handle()}));
535
536 // Removing the registered handles returns true.
537 CASE_EXPECT_TRUE(manager.remove_caller(caller_delegate{waiter0.get_internal_handle()}));
538 // Re-adding the remaining caller must not duplicate it into the vacant single-caller slot.
539 manager.add_caller(caller_delegate{waiter1.get_internal_handle()});
540 CASE_EXPECT_FALSE(manager.has_multiple_callers());
541 CASE_EXPECT_TRUE(manager.remove_caller(caller_delegate{waiter1.get_internal_handle()}));
542 CASE_EXPECT_FALSE(manager.remove_caller(caller_delegate{waiter1.get_internal_handle()}));
543 CASE_EXPECT_EQ(0, static_cast<int>(manager.resume_callers()));
544
545 // Complete the blocker so the real waiters unwind cleanly.
546 CASE_EXPECT_EQ(1, static_cast<int>(g_task_future_fifo_blocker_contexts.size()));
547 if (!g_task_future_fifo_blocker_contexts.empty()) {
548 auto pending_context = g_task_future_fifo_blocker_contexts.front();
549 g_task_future_fifo_blocker_contexts.pop_front();
550 pending_context->set_value(0);
551 }
552 CASE_EXPECT_TRUE(blocker.is_exiting());
553 CASE_EXPECT_TRUE(waiter0.is_ready());
554 CASE_EXPECT_TRUE(waiter1.is_ready());
555 CASE_EXPECT_TRUE(waiter2.is_ready());
556}
557
558namespace {
559static callable_future_int_type task_func_await_callable_and_be_killed() {
560 auto u = task_future_func_int_l2(13);
561 int x = co_await u;
562 co_return x;
563}
564
565static task_future_int_type task_func_await_and_be_killed_by_caller() {
566 auto v = task_func_await_callable_and_be_killed();
567 int x = co_await v;
568 co_return x;
569}
570
571std::shared_ptr<task_future_int_type> g_task_promise_killed_by_callee;
572static task_future_int_type task_func_await_and_be_killed_by_callee(task_future_int_type::task_status_type status) {
573 g_task_promise_killed_by_callee->kill(status);
574 auto v = task_func_await_callable_and_be_killed();
575 int x = co_await v;
576 co_return x;
577}
578
579} // namespace
580
581// kill
582CASE_TEST(task_promise, killed_by_caller) {
583 size_t old_resume_generator_count = g_task_future_resume_generator_count;
584 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
585
586 task_future_int_type t = task_func_await_and_be_killed_by_caller();
587 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kCreated), static_cast<int>(t.get_status()));
588 CASE_EXPECT_FALSE(t.is_canceled());
589 CASE_EXPECT_FALSE(t.is_faulted());
590 CASE_EXPECT_FALSE(t.is_timeout());
591 CASE_EXPECT_FALSE(t.is_exiting());
592 CASE_EXPECT_FALSE(t.is_completed());
593
594 CASE_EXPECT_TRUE(t.start());
595 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(t.get_status()));
596 CASE_EXPECT_FALSE(t.is_canceled());
597 CASE_EXPECT_FALSE(t.is_faulted());
598 CASE_EXPECT_FALSE(t.is_timeout());
599 CASE_EXPECT_FALSE(t.is_exiting());
600 CASE_EXPECT_FALSE(t.is_completed());
601
602 CASE_EXPECT_TRUE(t.kill(task_future_int_type::task_status_type::kKilled));
603 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kKilled), static_cast<int>(t.get_status()));
604 CASE_EXPECT_FALSE(t.is_canceled());
605 CASE_EXPECT_TRUE(t.is_faulted());
606 CASE_EXPECT_FALSE(t.is_timeout());
607 CASE_EXPECT_TRUE(t.is_exiting());
608 CASE_EXPECT_TRUE(t.is_completed());
609 CASE_EXPECT_EQ(-static_cast<int>(copp::promise_status::kKilled), *t.get_context()->data());
610
611 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
612 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
613
614 resume_pending_contexts({100});
615 CASE_EXPECT_EQ(-static_cast<int>(copp::promise_status::kKilled), *t.get_context()->data());
616 CASE_EXPECT_FALSE(t.is_canceled());
617 CASE_EXPECT_TRUE(t.is_faulted());
618 CASE_EXPECT_FALSE(t.is_timeout());
619 CASE_EXPECT_TRUE(t.is_exiting());
620 CASE_EXPECT_TRUE(t.is_completed());
621
622 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
623 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
624}
625
626CASE_TEST(task_promise, killed_by_callee) {
627 size_t old_resume_generator_count = g_task_future_resume_generator_count;
628 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
629
630 task_future_int_type t = task_func_await_and_be_killed_by_callee(copp::promise_status::kKilled);
631 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kCreated), static_cast<int>(t.get_status()));
632 CASE_EXPECT_FALSE(t.is_canceled());
633 CASE_EXPECT_FALSE(t.is_faulted());
634 CASE_EXPECT_FALSE(t.is_timeout());
635 CASE_EXPECT_FALSE(t.is_exiting());
636 CASE_EXPECT_FALSE(t.is_completed());
637
638 g_task_promise_killed_by_callee = std::make_shared<task_future_int_type>(t);
639 CASE_EXPECT_TRUE(t.start());
640 g_task_promise_killed_by_callee.reset();
641
642 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kKilled), static_cast<int>(t.get_status()));
643 CASE_EXPECT_FALSE(t.is_canceled());
644 CASE_EXPECT_TRUE(t.is_faulted());
645 CASE_EXPECT_FALSE(t.is_timeout());
646 CASE_EXPECT_TRUE(t.is_exiting());
647 CASE_EXPECT_TRUE(t.is_completed());
648 CASE_EXPECT_EQ(-static_cast<int>(copp::promise_status::kKilled), *t.get_context()->data());
649
650 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
651 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
652
653 resume_pending_contexts({100});
654 CASE_EXPECT_EQ(-static_cast<int>(copp::promise_status::kKilled), *t.get_context()->data());
655 CASE_EXPECT_FALSE(t.is_canceled());
656 CASE_EXPECT_TRUE(t.is_faulted());
657 CASE_EXPECT_FALSE(t.is_timeout());
658 CASE_EXPECT_TRUE(t.is_exiting());
659 CASE_EXPECT_TRUE(t.is_completed());
660
661 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
662 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
663}
664
665// Cancel
666CASE_TEST(task_promise, cancel_by_caller) {
667 size_t old_resume_generator_count = g_task_future_resume_generator_count;
668 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
669
670 task_future_int_type t = task_func_await_and_be_killed_by_caller();
671 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kCreated), static_cast<int>(t.get_status()));
672 CASE_EXPECT_FALSE(t.is_canceled());
673 CASE_EXPECT_FALSE(t.is_faulted());
674 CASE_EXPECT_FALSE(t.is_timeout());
675 CASE_EXPECT_FALSE(t.is_exiting());
676 CASE_EXPECT_FALSE(t.is_completed());
677
678 CASE_EXPECT_TRUE(t.start());
679 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(t.get_status()));
680 CASE_EXPECT_FALSE(t.is_canceled());
681 CASE_EXPECT_FALSE(t.is_faulted());
682 CASE_EXPECT_FALSE(t.is_timeout());
683 CASE_EXPECT_FALSE(t.is_exiting());
684 CASE_EXPECT_FALSE(t.is_completed());
685
686 CASE_EXPECT_TRUE(t.kill(task_future_int_type::task_status_type::kCancle));
687 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kCancle), static_cast<int>(t.get_status()));
688 CASE_EXPECT_TRUE(t.is_canceled());
689 CASE_EXPECT_FALSE(t.is_faulted());
690 CASE_EXPECT_FALSE(t.is_timeout());
691 CASE_EXPECT_TRUE(t.is_exiting());
692 CASE_EXPECT_TRUE(t.is_completed());
693 CASE_EXPECT_EQ(-static_cast<int>(copp::promise_status::kCancle), *t.get_context()->data());
694
695 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
696 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
697
698 resume_pending_contexts({100});
699 CASE_EXPECT_EQ(-static_cast<int>(copp::promise_status::kCancle), *t.get_context()->data());
700 CASE_EXPECT_TRUE(t.is_canceled());
701 CASE_EXPECT_FALSE(t.is_faulted());
702 CASE_EXPECT_FALSE(t.is_timeout());
703 CASE_EXPECT_TRUE(t.is_exiting());
704 CASE_EXPECT_TRUE(t.is_completed());
705
706 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
707 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
708}
709
710// Timeout
711CASE_TEST(task_promise, timeout_by_caller) {
712 size_t old_resume_generator_count = g_task_future_resume_generator_count;
713 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
714
715 task_future_int_type t = task_func_await_and_be_killed_by_caller();
716 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kCreated), static_cast<int>(t.get_status()));
717 CASE_EXPECT_FALSE(t.is_canceled());
718 CASE_EXPECT_FALSE(t.is_faulted());
719 CASE_EXPECT_FALSE(t.is_timeout());
720 CASE_EXPECT_FALSE(t.is_exiting());
721 CASE_EXPECT_FALSE(t.is_completed());
722
723 CASE_EXPECT_TRUE(t.start());
724 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(t.get_status()));
725 CASE_EXPECT_FALSE(t.is_canceled());
726 CASE_EXPECT_FALSE(t.is_faulted());
727 CASE_EXPECT_FALSE(t.is_timeout());
728 CASE_EXPECT_FALSE(t.is_exiting());
729 CASE_EXPECT_FALSE(t.is_completed());
730
731 CASE_EXPECT_TRUE(t.kill(task_future_int_type::task_status_type::kTimeout));
732 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kTimeout), static_cast<int>(t.get_status()));
733 CASE_EXPECT_FALSE(t.is_canceled());
734 CASE_EXPECT_TRUE(t.is_faulted());
735 CASE_EXPECT_TRUE(t.is_timeout());
736 CASE_EXPECT_TRUE(t.is_exiting());
737 CASE_EXPECT_TRUE(t.is_completed());
738 CASE_EXPECT_EQ(-static_cast<int>(copp::promise_status::kTimeout), *t.get_context()->data());
739
740 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
741 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
742
743 resume_pending_contexts({100});
744 CASE_EXPECT_EQ(-static_cast<int>(copp::promise_status::kTimeout), *t.get_context()->data());
745 CASE_EXPECT_FALSE(t.is_canceled());
746 CASE_EXPECT_TRUE(t.is_faulted());
747 CASE_EXPECT_TRUE(t.is_timeout());
748 CASE_EXPECT_TRUE(t.is_exiting());
749 CASE_EXPECT_TRUE(t.is_completed());
750
751 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
752 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
753}
754
755CASE_TEST(task_promise, timeout_by_callee) {
756 size_t old_resume_generator_count = g_task_future_resume_generator_count;
757 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
758
759 task_future_int_type t = task_func_await_and_be_killed_by_callee(copp::promise_status::kTimeout);
760 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kCreated), static_cast<int>(t.get_status()));
761 CASE_EXPECT_FALSE(t.is_canceled());
762 CASE_EXPECT_FALSE(t.is_faulted());
763 CASE_EXPECT_FALSE(t.is_timeout());
764 CASE_EXPECT_FALSE(t.is_exiting());
765 CASE_EXPECT_FALSE(t.is_completed());
766
767 g_task_promise_killed_by_callee = std::make_shared<task_future_int_type>(t);
768 CASE_EXPECT_TRUE(t.start());
769 g_task_promise_killed_by_callee.reset();
770
771 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kTimeout), static_cast<int>(t.get_status()));
772 CASE_EXPECT_FALSE(t.is_canceled());
773 CASE_EXPECT_TRUE(t.is_faulted());
774 CASE_EXPECT_TRUE(t.is_timeout());
775 CASE_EXPECT_TRUE(t.is_exiting());
776 CASE_EXPECT_TRUE(t.is_completed());
777 CASE_EXPECT_EQ(-static_cast<int>(copp::promise_status::kTimeout), *t.get_context()->data());
778
779 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
780 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
781
782 resume_pending_contexts({100});
783 CASE_EXPECT_EQ(-static_cast<int>(copp::promise_status::kTimeout), *t.get_context()->data());
784 CASE_EXPECT_FALSE(t.is_canceled());
785 CASE_EXPECT_TRUE(t.is_faulted());
786 CASE_EXPECT_TRUE(t.is_timeout());
787 CASE_EXPECT_TRUE(t.is_exiting());
788 CASE_EXPECT_TRUE(t.is_completed());
789
790 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
791 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
792}
793
794namespace {
795static task_future_int_type task_func_await_child_task_child() {
796 auto u = task_future_func_int_l2(53);
797 int x = co_await u;
798 co_return x;
799}
800
801static task_future_int_type task_func_await_child_task_parent(task_future_int_type &out) {
802 out = task_func_await_child_task_child();
803 int x = co_await out;
804 co_return x;
805}
806
807static task_future_int_type task_func_await_empty() {
808 task_future_int_type empty;
809 int x = co_await empty;
810 CASE_EXPECT_EQ(-1, x);
811 co_return x;
812}
813} // namespace
814
815// kill parent task and the child task will not be effected
816CASE_TEST(task_promise, kill_parent_only) {
817 size_t old_resume_generator_count = g_task_future_resume_generator_count;
818 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
819
820 task_future_int_type child;
821 task_future_int_type parent = task_func_await_child_task_parent(child);
822 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kCreated), static_cast<int>(parent.get_status()));
823 CASE_EXPECT_FALSE(parent.is_canceled());
824 CASE_EXPECT_FALSE(parent.is_faulted());
825 CASE_EXPECT_FALSE(parent.is_timeout());
826 CASE_EXPECT_FALSE(parent.is_exiting());
827 CASE_EXPECT_FALSE(parent.is_completed());
828
829 CASE_EXPECT_TRUE(parent.start());
830 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(parent.get_status()));
831 CASE_EXPECT_FALSE(parent.is_canceled());
832 CASE_EXPECT_FALSE(parent.is_faulted());
833 CASE_EXPECT_FALSE(parent.is_timeout());
834 CASE_EXPECT_FALSE(parent.is_exiting());
835 CASE_EXPECT_FALSE(parent.is_completed());
836
837 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kCreated), static_cast<int>(child.get_status()));
838 CASE_EXPECT_EQ(old_resume_generator_count, g_task_future_resume_generator_count);
839 CASE_EXPECT_EQ(old_suspend_generator_count, g_task_future_suspend_generator_count);
840 child.start();
841 CASE_EXPECT_EQ(old_resume_generator_count, g_task_future_resume_generator_count);
842 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
843
844 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(child.get_status()));
845 CASE_EXPECT_FALSE(child.is_canceled());
846 CASE_EXPECT_FALSE(child.is_faulted());
847 CASE_EXPECT_FALSE(child.is_timeout());
848 CASE_EXPECT_FALSE(child.is_exiting());
849 CASE_EXPECT_FALSE(child.is_completed());
850
851 CASE_EXPECT_TRUE(parent.kill(task_future_int_type::task_status_type::kTimeout));
852 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kTimeout), static_cast<int>(parent.get_status()));
853 CASE_EXPECT_FALSE(parent.is_canceled());
854 CASE_EXPECT_TRUE(parent.is_faulted());
855 CASE_EXPECT_TRUE(parent.is_timeout());
856 CASE_EXPECT_TRUE(parent.is_exiting());
857 CASE_EXPECT_TRUE(parent.is_completed());
858 CASE_EXPECT_EQ(-static_cast<int>(copp::promise_status::kTimeout), *parent.get_context()->data());
859
860 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kRunning), static_cast<int>(child.get_status()));
861 CASE_EXPECT_FALSE(child.is_canceled());
862 CASE_EXPECT_FALSE(child.is_faulted());
863 CASE_EXPECT_FALSE(child.is_timeout());
864 CASE_EXPECT_FALSE(child.is_exiting());
865 CASE_EXPECT_FALSE(child.is_completed());
866
867 resume_pending_contexts({1000});
868 CASE_EXPECT_EQ(-static_cast<int>(copp::promise_status::kTimeout), *parent.get_context()->data());
869 CASE_EXPECT_FALSE(parent.is_canceled());
870 CASE_EXPECT_TRUE(parent.is_faulted());
871 CASE_EXPECT_TRUE(parent.is_timeout());
872 CASE_EXPECT_TRUE(parent.is_exiting());
873 CASE_EXPECT_TRUE(parent.is_completed());
874
875 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kDone), static_cast<int>(child.get_status()));
876 CASE_EXPECT_FALSE(child.is_canceled());
877 CASE_EXPECT_FALSE(child.is_faulted());
878 CASE_EXPECT_FALSE(child.is_timeout());
879 CASE_EXPECT_TRUE(child.is_exiting());
880 CASE_EXPECT_TRUE(child.is_completed());
881 CASE_EXPECT_EQ(1053, *child.get_context()->data());
882
883 CASE_EXPECT_EQ(old_resume_generator_count + 1, g_task_future_resume_generator_count);
884 CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_task_future_suspend_generator_count);
885}
886
887CASE_TEST(task_promise, empty_task) {
888 task_future_int_type t = task_func_await_empty();
889 t.start();
890
891 task_future_int_type empty;
892 CASE_EXPECT_FALSE(empty.start());
893 CASE_EXPECT_FALSE(empty.kill(task_future_int_type::task_status_type::kKilled));
894
895 CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kInvalid), static_cast<int>(empty.get_status()));
896 CASE_EXPECT_EQ(nullptr, empty.get_private_data());
897 CASE_EXPECT_EQ(0, empty.get_id());
898 CASE_EXPECT_EQ(0, empty.get_ref_future_count());
899 CASE_EXPECT_EQ(nullptr, empty.get_context().get());
900}
901
902// task destroy and auto resume
903CASE_TEST(task_promise, task_destroy_and_auto_resume) {
904 task_future_int_type parent;
905 {
906 task_future_int_type child;
907 parent = task_func_await_child_task_parent(child);
908 CASE_EXPECT_TRUE(parent.start());
909 child.start();
910
911 CASE_EXPECT_EQ(1, parent.get_ref_future_count());
912 CASE_EXPECT_EQ(1, child.get_ref_future_count());
913
914 CASE_EXPECT_TRUE(child.valid());
915 CASE_EXPECT_TRUE(child);
916
917 task_future_int_type move_child_assign = std::move(child);
918 CASE_EXPECT_EQ(0, child.get_ref_future_count());
919 CASE_EXPECT_EQ(1, move_child_assign.get_ref_future_count());
920 CASE_EXPECT_FALSE(child.valid());
921 CASE_EXPECT_FALSE(child);
922 CASE_EXPECT_TRUE(move_child_assign.valid());
923 CASE_EXPECT_TRUE(move_child_assign);
924
925 task_future_int_type move_child_ctor{std::move(move_child_assign)};
926 CASE_EXPECT_EQ(0, move_child_assign.get_ref_future_count());
927 CASE_EXPECT_EQ(1, move_child_ctor.get_ref_future_count());
928
929 task_future_int_type copy_child_assign = move_child_ctor;
930 task_future_int_type copy_child_ctor{move_child_ctor};
931
932 CASE_EXPECT_EQ(3, copy_child_ctor.get_ref_future_count());
933 CASE_EXPECT_EQ(3, copy_child_assign.get_ref_future_count());
934 CASE_EXPECT_EQ(3, move_child_ctor.get_ref_future_count());
935
936 CASE_EXPECT_EQ(copy_child_assign.get_context(), copy_child_ctor.get_context());
937 CASE_EXPECT_EQ(copy_child_assign.get_context(), move_child_ctor.get_context());
938
939 CASE_EXPECT_EQ(copy_child_assign.get_id(), copy_child_ctor.get_id());
940 CASE_EXPECT_EQ(copy_child_assign.get_id(), move_child_ctor.get_id());
941
942 CASE_EXPECT_FALSE(parent.is_exiting());
943 CASE_EXPECT_FALSE(parent.is_completed());
944 }
945
946 CASE_EXPECT_TRUE(parent.is_exiting());
947 CASE_EXPECT_TRUE(parent.is_completed());
948 CASE_EXPECT_EQ(-static_cast<int>(copp::promise_status::kKilled), *parent.get_context()->data());
949
950 resume_pending_contexts({});
951}
952
953namespace {
954static task_future_int_type task_func_await_int_simple() {
955 auto u = task_future_func_int_l2(91);
956 int x = co_await u;
957 co_return x;
958}
959
960static task_future_void_type task_func_await_void_simple() {
961 auto u = task_future_func_void_l2();
962 co_await u;
963 co_return;
964}
965
966static callable_future_int_type task_func_callable_await_task_int_simple() {
967 auto u = task_func_await_int_simple();
968 // forget to start here
969 int x = co_await u;
970 co_return x;
971}
972
973} // namespace
974
975CASE_TEST(task_promise, forget_to_start) {
976 // This should be safe here
977 {
978 auto f = task_func_callable_await_task_int_simple();
979 }
980
981 resume_pending_contexts({});
982}
983
984CASE_TEST(task_promise, callable_then_12_1_task_return_int_and_thenable_return_normal_int) {
985 auto t = task_func_await_int_simple();
986 auto f = t.then([](task_future_int_type::context_pointer_type, task_future_int_type::value_type value) {
987 CASE_EXPECT_EQ(2091, value);
988 CASE_MSG_INFO() << "thenable return int" << std::endl;
989 return value;
990 });
991
992 CASE_EXPECT_FALSE(f.is_ready());
993 t.start();
994 CASE_EXPECT_FALSE(f.is_ready());
995
996 resume_pending_contexts({2000});
997 CASE_EXPECT_TRUE(f.is_ready());
998
999 CASE_EXPECT_EQ(2091, f.get_internal_promise().data());
1000}
1001
1002CASE_TEST(task_promise, callable_then_12_2_task_return_int_and_thenable_return_normal_void) {
1003 auto t = task_func_await_int_simple();
1004 auto f = t.then([](const task_future_int_type::context_pointer_type &, task_future_int_type::value_type value) {
1005 CASE_EXPECT_EQ(2091, value);
1006 CASE_MSG_INFO() << "thenable return void" << std::endl;
1007 });
1008
1009 CASE_EXPECT_FALSE(f.is_ready());
1010 t.start();
1011 CASE_EXPECT_FALSE(f.is_ready());
1012
1013 resume_pending_contexts({2000});
1014 CASE_EXPECT_TRUE(f.is_ready());
1015}
1016
1017CASE_TEST(task_promise, callable_then_12_3_task_return_int_and_thenable_return_callable_int) {
1018 auto t = task_func_await_int_simple();
1019 auto f = t.then([](task_future_int_type::context_pointer_type &&,
1020 task_future_int_type::value_type value) -> copp::callable_future<int> {
1021 CASE_EXPECT_EQ(2091, value);
1022 CASE_MSG_INFO() << "thenable return callable_future<int>" << std::endl;
1023 co_return value;
1024 });
1025
1026 CASE_EXPECT_FALSE(f.is_ready());
1027 t.start();
1028 CASE_EXPECT_FALSE(f.is_ready());
1029
1030 resume_pending_contexts({2000});
1031 CASE_EXPECT_TRUE(f.is_ready());
1032
1033 CASE_EXPECT_EQ(2091, f.get_internal_promise().data());
1034}
1035
1036CASE_TEST(task_promise, callable_then_12_4_task_return_int_and_thenable_return_callable_void) {
1037 auto t = task_func_await_int_simple();
1038 auto f = t.then([](const task_future_int_type::context_pointer_type &,
1039 task_future_int_type::value_type value) -> copp::callable_future<void> {
1040 CASE_EXPECT_EQ(2091, value);
1041 CASE_MSG_INFO() << "thenable return callable_future<void>" << std::endl;
1042 co_return;
1043 });
1044
1045 CASE_EXPECT_FALSE(f.is_ready());
1046 t.start();
1047 CASE_EXPECT_FALSE(f.is_ready());
1048
1049 resume_pending_contexts({2000});
1050 CASE_EXPECT_TRUE(f.is_ready());
1051}
1052
1053CASE_TEST(task_promise, callable_then_12_5_task_return_int_and_thenable_return_callable_int) {
1054 auto t = task_func_await_int_simple();
1055 auto f = t.then([](task_future_int_type::context_pointer_type,
1056 task_future_int_type::value_type value) -> cotask::task_future<int, void> {
1057 CASE_EXPECT_EQ(2091, value);
1058 CASE_MSG_INFO() << "thenable return task_future<int>" << std::endl;
1059 co_return value;
1060 });
1061
1062 CASE_EXPECT_FALSE(f.is_ready());
1063 t.start();
1064 CASE_EXPECT_FALSE(f.is_ready());
1065
1066 resume_pending_contexts({2000});
1067 CASE_EXPECT_TRUE(f.is_ready());
1068
1069 CASE_EXPECT_EQ(2091, f.get_internal_promise().data());
1070}
1071
1072CASE_TEST(task_promise, callable_then_12_6_task_return_int_and_thenable_return_callable_void) {
1073 auto t = task_func_await_int_simple();
1074 auto f = t.then([](task_future_int_type::context_pointer_type &&,
1075 task_future_int_type::value_type value) -> cotask::task_future<void, void> {
1076 CASE_EXPECT_EQ(2091, value);
1077 CASE_MSG_INFO() << "thenable return task_future<void>" << std::endl;
1078 co_return;
1079 });
1080
1081 CASE_EXPECT_FALSE(f.is_ready());
1082 t.start();
1083 CASE_EXPECT_FALSE(f.is_ready());
1084
1085 resume_pending_contexts({2000});
1086 CASE_EXPECT_TRUE(f.is_ready());
1087}
1088
1089CASE_TEST(task_promise, callable_then_12_7_task_return_void_and_thenable_return_normal_int) {
1090 auto t = task_func_await_void_simple();
1091 auto f = t.then([](task_future_void_type::context_pointer_type) {
1092 CASE_MSG_INFO() << "thenable return int" << std::endl;
1093 return 2111;
1094 });
1095
1096 CASE_EXPECT_FALSE(f.is_ready());
1097 t.start();
1098 CASE_EXPECT_FALSE(f.is_ready());
1099
1100 resume_pending_contexts({});
1101 CASE_EXPECT_TRUE(f.is_ready());
1102
1103 CASE_EXPECT_EQ(2111, f.get_internal_promise().data());
1104}
1105
1106CASE_TEST(task_promise, callable_then_12_8_task_return_void_and_thenable_return_normal_void) {
1107 auto t = task_func_await_void_simple();
1108 auto f = t.then([](const task_future_void_type::context_pointer_type &) {
1109 CASE_MSG_INFO() << "thenable return void" << std::endl;
1110 });
1111
1112 CASE_EXPECT_FALSE(f.is_ready());
1113 t.start();
1114 CASE_EXPECT_FALSE(f.is_ready());
1115
1116 resume_pending_contexts({});
1117 CASE_EXPECT_TRUE(f.is_ready());
1118}
1119
1120CASE_TEST(task_promise, callable_then_12_9_task_return_void_and_thenable_return_callable_int) {
1121 auto t = task_func_await_void_simple();
1122 auto f = t.then([](task_future_void_type::context_pointer_type) -> copp::callable_future<int> {
1123 CASE_MSG_INFO() << "thenable return callable_future<int>" << std::endl;
1124 co_return 2111;
1125 });
1126
1127 CASE_EXPECT_FALSE(f.is_ready());
1128 t.start();
1129 CASE_EXPECT_FALSE(f.is_ready());
1130
1131 resume_pending_contexts({});
1132 CASE_EXPECT_TRUE(f.is_ready());
1133
1134 CASE_EXPECT_EQ(2111, f.get_internal_promise().data());
1135}
1136
1137CASE_TEST(task_promise, callable_then_12_10_task_return_void_and_thenable_return_callable_void) {
1138 auto t = task_func_await_void_simple();
1139 auto f = t.then([](const task_future_void_type::context_pointer_type &) -> copp::callable_future<void> {
1140 CASE_MSG_INFO() << "thenable return callable_future<void>" << std::endl;
1141 co_return;
1142 });
1143
1144 CASE_EXPECT_FALSE(f.is_ready());
1145 t.start();
1146 CASE_EXPECT_FALSE(f.is_ready());
1147
1148 resume_pending_contexts({});
1149 CASE_EXPECT_TRUE(f.is_ready());
1150}
1151
1152CASE_TEST(task_promise, callable_then_12_11_task_return_void_and_thenable_return_callable_int) {
1153 auto t = task_func_await_void_simple();
1154 auto f = t.then([](task_future_void_type::context_pointer_type) -> cotask::task_future<int, void> {
1155 CASE_MSG_INFO() << "thenable return task_future<int>" << std::endl;
1156 co_return 2111;
1157 });
1158
1159 CASE_EXPECT_FALSE(f.is_ready());
1160 t.start();
1161 CASE_EXPECT_FALSE(f.is_ready());
1162
1163 resume_pending_contexts({});
1164 CASE_EXPECT_TRUE(f.is_ready());
1165
1166 CASE_EXPECT_EQ(2111, f.get_internal_promise().data());
1167}
1168
1169CASE_TEST(task_promise, callable_then_12_12_task_return_void_and_thenable_return_callable_void) {
1170 auto t = task_func_await_void_simple();
1171 auto f = t.then([](const task_future_void_type::context_pointer_type &) -> cotask::task_future<void, void> {
1172 CASE_MSG_INFO() << "thenable return task_future<void>" << std::endl;
1173 co_return;
1174 });
1175
1176 CASE_EXPECT_FALSE(f.is_ready());
1177 t.start();
1178 CASE_EXPECT_FALSE(f.is_ready());
1179
1180 resume_pending_contexts({});
1181 CASE_EXPECT_TRUE(f.is_ready());
1182}
1183
1184CASE_TEST(task_promise, then_kill_task) {
1185 auto t = task_func_await_int_simple();
1186 auto f = t.then([](task_future_int_type::context_pointer_type ctx, task_future_int_type::value_type value) {
1187 CASE_EXPECT_EQ(static_cast<int>(ctx->get_status()),
1188 static_cast<int>(task_future_int_type::task_status_type::kTimeout));
1189 CASE_EXPECT_EQ(-static_cast<int>(task_future_int_type::task_status_type::kTimeout), value);
1190 CASE_MSG_INFO() << "thenable of timeout task return int" << std::endl;
1191 return value;
1192 });
1193
1194 CASE_EXPECT_FALSE(f.is_ready());
1195 t.start();
1196 CASE_EXPECT_FALSE(f.is_ready());
1197
1198 t.kill(task_future_int_type::task_status_type::kTimeout);
1199 CASE_EXPECT_TRUE(f.is_ready());
1200
1201 CASE_EXPECT_EQ(-static_cast<int>(task_future_int_type::task_status_type::kTimeout), f.get_internal_promise().data());
1202
1203 resume_pending_contexts({});
1204}
1205
1206CASE_TEST(task_promise, then_empty_task) {
1207 task_future_int_type t;
1208 auto f = t.then([](task_future_int_type::context_pointer_type ctx, task_future_int_type::value_type value) {
1209 CASE_EXPECT_TRUE(!ctx);
1210 CASE_EXPECT_EQ(-1, value);
1211 CASE_MSG_INFO() << "thenable of empty task return int" << std::endl;
1212 return value;
1213 });
1214
1215 CASE_EXPECT_TRUE(f.is_ready());
1216
1217 CASE_EXPECT_EQ(-1, f.get_internal_promise().data());
1218
1219 resume_pending_contexts({});
1220}
1221
1222CASE_TEST(task_promise, then_exiting_task) {
1223 auto t = task_func_await_int_simple();
1224 t.start();
1225
1226 resume_pending_contexts({3000});
1227
1228 auto f = t.then([](task_future_int_type::context_pointer_type ctx, task_future_int_type::value_type value) {
1229 CASE_EXPECT_EQ(static_cast<int>(ctx->get_status()),
1230 static_cast<int>(task_future_int_type::task_status_type::kDone));
1231 CASE_EXPECT_EQ(3091, value);
1232 CASE_MSG_INFO() << "thenable of exiting task return int" << std::endl;
1233 return value;
1234 });
1235
1236 CASE_EXPECT_TRUE(f.is_ready());
1237
1238 CASE_EXPECT_EQ(3091, f.get_internal_promise().data());
1239}
1240
1241CASE_TEST(task_promise, task_then_12_1_task_return_int_and_thenable_return_normal_int) {
1242 auto t = task_func_await_int_simple();
1243 auto f = t.then(
1244 [](task_future_int_type::context_pointer_type, task_future_int_type::value_type value) {
1245 CASE_EXPECT_EQ(2091, value);
1246 CASE_MSG_INFO() << "first thenable return int" << std::endl;
1247 return value;
1248 },
1249 3000)
1250 .then(
1251 [](cotask::task_future<int, int>::context_pointer_type ctx, task_future_int_type::value_type value) {
1252 CASE_EXPECT_EQ(2091, value);
1253 CASE_MSG_INFO() << "second thenable return int" << std::endl;
1254 return value + ctx->get_private_data();
1255 },
1256 nullptr);
1257
1258 CASE_EXPECT_FALSE(f.is_exiting());
1259 t.start();
1260 CASE_EXPECT_FALSE(f.is_exiting());
1261
1262 resume_pending_contexts({2000});
1263 CASE_EXPECT_TRUE(f.is_exiting());
1264
1265 CASE_EXPECT_EQ(5091, *f.get_context()->data());
1266}
1267
1268CASE_TEST(task_promise, task_then_12_2_task_return_int_and_thenable_return_normal_void) {
1269 auto t = task_func_await_int_simple();
1270 auto f = t.then(
1271 [](const task_future_int_type::context_pointer_type &, task_future_int_type::value_type value) {
1272 CASE_EXPECT_EQ(2091, value);
1273 CASE_MSG_INFO() << "first thenable return void" << std::endl;
1274 },
1275 3000)
1276 .then(
1277 [](cotask::task_future<void, int>::context_pointer_type ctx) {
1278 CASE_EXPECT_EQ(3000, ctx->get_private_data());
1279 CASE_MSG_INFO() << "second thenable return void" << std::endl;
1280 },
1281 nullptr);
1282
1283 CASE_EXPECT_FALSE(f.is_exiting());
1284 t.start();
1285 CASE_EXPECT_FALSE(f.is_exiting());
1286
1287 resume_pending_contexts({2000});
1288 CASE_EXPECT_TRUE(f.is_exiting());
1289}
1290
1291CASE_TEST(task_promise, task_then_12_3_task_return_int_and_thenable_return_callable_int) {
1292 auto t = task_func_await_int_simple();
1293 auto f = t.then(
1294 [](task_future_int_type::context_pointer_type &&,
1295 task_future_int_type::value_type value) -> copp::callable_future<int> {
1296 CASE_EXPECT_EQ(2091, value);
1297 CASE_MSG_INFO() << "first thenable return callable_future<int>" << std::endl;
1298 co_return value;
1299 },
1300 3000)
1301 .then(
1302 [](cotask::task_future<int, int>::context_pointer_type ctx, task_future_int_type::value_type value) {
1303 CASE_EXPECT_EQ(2091, value);
1304 CASE_MSG_INFO() << "second thenable return int" << std::endl;
1305 return value + ctx->get_private_data();
1306 },
1307 nullptr);
1308
1309 CASE_EXPECT_FALSE(f.is_exiting());
1310 t.start();
1311 CASE_EXPECT_FALSE(f.is_exiting());
1312
1313 resume_pending_contexts({2000});
1314 CASE_EXPECT_TRUE(f.is_exiting());
1315
1316 CASE_EXPECT_EQ(5091, *f.get_context()->data());
1317}
1318
1319CASE_TEST(task_promise, task_then_12_4_task_return_int_and_thenable_return_callable_void) {
1320 auto t = task_func_await_int_simple();
1321 auto f = t.then(
1322 [](const task_future_int_type::context_pointer_type &,
1323 task_future_int_type::value_type value) -> copp::callable_future<void> {
1324 CASE_EXPECT_EQ(2091, value);
1325 CASE_MSG_INFO() << "first thenable return callable_future<void>" << std::endl;
1326 co_return;
1327 },
1328 3000)
1329 .then(
1330 [](cotask::task_future<void, int>::context_pointer_type ctx) {
1331 CASE_EXPECT_EQ(3000, ctx->get_private_data());
1332 CASE_MSG_INFO() << "second thenable return void" << std::endl;
1333 },
1334 nullptr);
1335
1336 CASE_EXPECT_FALSE(f.is_exiting());
1337 t.start();
1338 CASE_EXPECT_FALSE(f.is_exiting());
1339
1340 resume_pending_contexts({2000});
1341 CASE_EXPECT_TRUE(f.is_exiting());
1342}
1343
1344CASE_TEST(task_promise, task_then_12_5_task_return_int_and_thenable_return_callable_int) {
1345 auto t = task_func_await_int_simple();
1346 auto f = t.then(
1347 [](task_future_int_type::context_pointer_type,
1348 task_future_int_type::value_type value) -> cotask::task_future<int, void> {
1349 CASE_EXPECT_EQ(2091, value);
1350 CASE_MSG_INFO() << "first thenable return task_future<int>" << std::endl;
1351 co_return value;
1352 },
1353 3000)
1354 .then(
1355 [](cotask::task_future<int, int>::context_pointer_type ctx, task_future_int_type::value_type value) {
1356 CASE_EXPECT_EQ(2091, value);
1357 CASE_MSG_INFO() << "second thenable return int" << std::endl;
1358 return value + ctx->get_private_data();
1359 },
1360 nullptr);
1361
1362 CASE_EXPECT_FALSE(f.is_exiting());
1363 t.start();
1364 CASE_EXPECT_FALSE(f.is_exiting());
1365
1366 resume_pending_contexts({2000});
1367 CASE_EXPECT_TRUE(f.is_exiting());
1368
1369 CASE_EXPECT_EQ(5091, *f.get_context()->data());
1370}
1371
1372CASE_TEST(task_promise, task_then_12_6_task_return_int_and_thenable_return_callable_void) {
1373 auto t = task_func_await_int_simple();
1374 auto f = t.then(
1375 [](task_future_int_type::context_pointer_type &&,
1376 task_future_int_type::value_type value) -> cotask::task_future<void, void> {
1377 CASE_EXPECT_EQ(2091, value);
1378 CASE_MSG_INFO() << "first thenable return task_future<void>" << std::endl;
1379 co_return;
1380 },
1381 3000)
1382 .then(
1383 [](cotask::task_future<void, int>::context_pointer_type ctx) {
1384 CASE_EXPECT_EQ(3000, ctx->get_private_data());
1385 CASE_MSG_INFO() << "second thenable return void" << std::endl;
1386 },
1387 nullptr);
1388
1389 CASE_EXPECT_FALSE(f.is_exiting());
1390 t.start();
1391 CASE_EXPECT_FALSE(f.is_exiting());
1392
1393 resume_pending_contexts({2000});
1394 CASE_EXPECT_TRUE(f.is_exiting());
1395}
1396
1397CASE_TEST(task_promise, task_then_12_7_task_return_void_and_thenable_return_normal_int) {
1398 auto t = task_func_await_void_simple();
1399 auto f = t.then(
1400 [](task_future_void_type::context_pointer_type) {
1401 CASE_MSG_INFO() << "first thenable return int" << std::endl;
1402 return 2111;
1403 },
1404 3000)
1405 .then(
1406 [](cotask::task_future<int, int>::context_pointer_type ctx, task_future_int_type::value_type value) {
1407 CASE_EXPECT_EQ(2111, value);
1408 CASE_MSG_INFO() << "second thenable return int" << std::endl;
1409 return value + ctx->get_private_data();
1410 },
1411 nullptr);
1412
1413 CASE_EXPECT_FALSE(f.is_exiting());
1414 t.start();
1415 CASE_EXPECT_FALSE(f.is_exiting());
1416
1417 resume_pending_contexts({});
1418 CASE_EXPECT_TRUE(f.is_exiting());
1419
1420 CASE_EXPECT_EQ(5111, *f.get_context()->data());
1421}
1422
1423CASE_TEST(task_promise, task_then_12_8_task_return_void_and_thenable_return_normal_void) {
1424 auto t = task_func_await_void_simple();
1425 auto f = t.then(
1426 [](const task_future_void_type::context_pointer_type &) {
1427 CASE_MSG_INFO() << "first thenable return void" << std::endl;
1428 },
1429 3000)
1430 .then(
1431 [](cotask::task_future<void, int>::context_pointer_type ctx) {
1432 CASE_EXPECT_EQ(3000, ctx->get_private_data());
1433 CASE_MSG_INFO() << "second thenable return void" << std::endl;
1434 },
1435 nullptr);
1436
1437 CASE_EXPECT_FALSE(f.is_exiting());
1438 t.start();
1439 CASE_EXPECT_FALSE(f.is_exiting());
1440
1441 resume_pending_contexts({});
1442 CASE_EXPECT_TRUE(f.is_exiting());
1443}
1444
1445CASE_TEST(task_promise, task_then_12_9_task_return_void_and_thenable_return_callable_int) {
1446 auto t = task_func_await_void_simple();
1447 auto f = t.then(
1448 [](task_future_void_type::context_pointer_type) -> copp::callable_future<int> {
1449 CASE_MSG_INFO() << "first thenable return callable_future<int>" << std::endl;
1450 co_return 2111;
1451 },
1452 3000)
1453 .then(
1454 [](cotask::task_future<int, int>::context_pointer_type ctx, task_future_int_type::value_type value) {
1455 CASE_EXPECT_EQ(2111, value);
1456 CASE_MSG_INFO() << "second thenable return int" << std::endl;
1457 return value + ctx->get_private_data();
1458 },
1459 nullptr);
1460
1461 CASE_EXPECT_FALSE(f.is_exiting());
1462 t.start();
1463 CASE_EXPECT_FALSE(f.is_exiting());
1464
1465 resume_pending_contexts({});
1466 CASE_EXPECT_TRUE(f.is_exiting());
1467
1468 CASE_EXPECT_EQ(5111, *f.get_context()->data());
1469}
1470
1471CASE_TEST(task_promise, task_then_12_10_task_return_void_and_thenable_return_callable_void) {
1472 auto t = task_func_await_void_simple();
1473 auto f = t.then(
1474 [](const task_future_void_type::context_pointer_type &) -> copp::callable_future<void> {
1475 CASE_MSG_INFO() << "first thenable return callable_future<void>" << std::endl;
1476 co_return;
1477 },
1478 3000)
1479 .then(
1480 [](cotask::task_future<void, int>::context_pointer_type ctx) {
1481 CASE_EXPECT_EQ(3000, ctx->get_private_data());
1482 CASE_MSG_INFO() << "second thenable return void" << std::endl;
1483 },
1484 nullptr);
1485
1486 CASE_EXPECT_FALSE(f.is_exiting());
1487 t.start();
1488 CASE_EXPECT_FALSE(f.is_exiting());
1489
1490 resume_pending_contexts({});
1491 CASE_EXPECT_TRUE(f.is_exiting());
1492}
1493
1494CASE_TEST(task_promise, task_then_12_11_task_return_void_and_thenable_return_callable_int) {
1495 auto t = task_func_await_void_simple();
1496 auto f = t.then(
1497 [](task_future_void_type::context_pointer_type) -> cotask::task_future<int, void> {
1498 CASE_MSG_INFO() << "first thenable return task_future<int>" << std::endl;
1499 co_return 2111;
1500 },
1501 3000)
1502 .then(
1503 [](cotask::task_future<int, int>::context_pointer_type ctx, task_future_int_type::value_type value) {
1504 CASE_EXPECT_EQ(2111, value);
1505 CASE_MSG_INFO() << "second thenable return int" << std::endl;
1506 return value + ctx->get_private_data();
1507 },
1508 nullptr);
1509
1510 CASE_EXPECT_FALSE(f.is_exiting());
1511 t.start();
1512 CASE_EXPECT_FALSE(f.is_exiting());
1513
1514 resume_pending_contexts({});
1515 CASE_EXPECT_TRUE(f.is_exiting());
1516
1517 CASE_EXPECT_EQ(5111, *f.get_context()->data());
1518}
1519
1520CASE_TEST(task_promise, task_then_12_12_task_return_void_and_thenable_return_callable_void) {
1521 auto t = task_func_await_void_simple();
1522 auto f = t.then(
1523 [](const task_future_void_type::context_pointer_type &) -> cotask::task_future<void, void> {
1524 CASE_MSG_INFO() << "first thenable return task_future<void>" << std::endl;
1525 co_return;
1526 },
1527 3000)
1528 .then(
1529 [](cotask::task_future<void, int>::context_pointer_type ctx) {
1530 CASE_EXPECT_EQ(3000, ctx->get_private_data());
1531 CASE_MSG_INFO() << "second thenable return void" << std::endl;
1532 },
1533 nullptr);
1534
1535 CASE_EXPECT_FALSE(f.is_exiting());
1536 t.start();
1537 CASE_EXPECT_FALSE(f.is_exiting());
1538
1539 resume_pending_contexts({});
1540 CASE_EXPECT_TRUE(f.is_exiting());
1541}
1542
1543namespace {
1544static cotask::task_future<int, void> task_func_some_any_all_callable_suspend() {
1545 auto suspend_callback = [](generator_future_int_type::context_pointer_type ctx) {
1546 ++g_task_future_suspend_generator_count;
1547 g_task_future_pending_int_contexts.push_back(ctx);
1548 };
1549 auto resume_callback = [](const generator_future_int_type::context_type &) {
1550 ++g_task_future_resume_generator_count;
1551 };
1552
1553 auto value = co_await generator_future_int_type(suspend_callback, resume_callback);
1554 co_return value;
1555}
1556
1557static copp::callable_future<int> task_future_func_some_callable_in_container(size_t expect_ready_count,
1558 copp::promise_status expect_status) {
1559 size_t old_resume_generator_count = g_task_future_resume_generator_count;
1560 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
1561
1562 size_t resume_ready_count = 0;
1563
1564 std::vector<cotask::task_future<int, void>> tasks;
1565 tasks.emplace_back(task_func_some_any_all_callable_suspend());
1566 tasks.emplace_back(task_func_some_any_all_callable_suspend());
1567 tasks.emplace_back(task_func_some_any_all_callable_suspend());
1568 for (auto &task_object : tasks) {
1569 task_object.start();
1570 }
1571
1572 copp::some_ready<cotask::task_future<int, void>>::type readys;
1573 auto some_result = co_await copp::some(readys, 2, tasks);
1574 CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(some_result));
1575
1576 int result = 1;
1577 for (auto &ready_task : readys) {
1578 if (ready_task->is_exiting()) {
1579 result += *ready_task->get_context()->data();
1580 ++resume_ready_count;
1581 }
1582 }
1583
1584 CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
1585
1586 // Nothing happend here if we await the tasks again.
1587 some_result = co_await copp::some(readys, 2, tasks);
1588 CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(some_result));
1589
1590 // If it's killed, await will trigger suspend and resume again, or it will return directly.
1591 CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
1592
1593 CASE_EXPECT_EQ(old_resume_generator_count + expect_ready_count, g_task_future_resume_generator_count);
1594 CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_task_future_suspend_generator_count);
1595 CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
1596
1597 co_return result;
1598}
1599} // namespace
1600
1601CASE_TEST(task_promise, finish_some_in_container) {
1602 auto f = task_future_func_some_callable_in_container(2, copp::promise_status::kDone);
1603
1604 CASE_EXPECT_FALSE(f.is_ready());
1605
1606 // partly resume
1607 resume_pending_contexts({471}, 1);
1608 CASE_EXPECT_FALSE(f.is_ready());
1609 resume_pending_contexts({473}, 1);
1610
1611 CASE_EXPECT_TRUE(f.is_ready());
1612 CASE_EXPECT_EQ(945, f.get_internal_promise().data());
1613
1614 resume_pending_contexts({});
1615}
1616
1617CASE_TEST(task_promise, kill_some_in_container) {
1618 auto f = task_future_func_some_callable_in_container(0, copp::promise_status::kKilled);
1619
1620 CASE_EXPECT_FALSE(f.is_ready());
1621
1622 // partly resume
1623 f.kill();
1624
1625 CASE_EXPECT_TRUE(f.is_ready());
1626 CASE_EXPECT_EQ(1, f.get_internal_promise().data());
1627
1628 resume_pending_contexts({});
1629}
1630
1631static copp::callable_future<int> task_future_func_some_callable_in_initialize_list(
1632 size_t expect_ready_count, copp::promise_status expect_status) {
1633 size_t old_resume_generator_count = g_task_future_resume_generator_count;
1634 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
1635
1636 size_t resume_ready_count = 0;
1637
1638 cotask::task_future<int, void> task1 = task_func_some_any_all_callable_suspend();
1639 cotask::task_future<int, void> task2 = task_func_some_any_all_callable_suspend();
1640 cotask::task_future<int, void> task3 = task_func_some_any_all_callable_suspend();
1641 task1.start();
1642 task2.start();
1643 task3.start();
1644
1645 copp::some_ready<cotask::task_future<int, void>>::type readys;
1646 std::reference_wrapper<cotask::task_future<int, void>> pending[] = {task1, task2, task3};
1647 auto some_result = co_await copp::some(readys, 2, pending);
1648 CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(some_result));
1649
1650 int result = 1;
1651 for (auto &ready_task : readys) {
1652 if (ready_task->is_exiting()) {
1653 result += *ready_task->get_context()->data();
1654 ++resume_ready_count;
1655 }
1656 }
1657
1658 CASE_EXPECT_EQ(old_resume_generator_count + expect_ready_count, g_task_future_resume_generator_count);
1659 CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_task_future_suspend_generator_count);
1660 CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
1661
1662 co_return result;
1663}
1664
1665CASE_TEST(task_promise, finish_some_in_initialize_list) {
1666 auto f = task_future_func_some_callable_in_initialize_list(2, copp::promise_status::kDone);
1667
1668 CASE_EXPECT_FALSE(f.is_ready());
1669
1670 // partly resume
1671 resume_pending_contexts({471}, 1);
1672 CASE_EXPECT_FALSE(f.is_ready());
1673 resume_pending_contexts({473}, 1);
1674
1675 CASE_EXPECT_TRUE(f.is_ready());
1676 CASE_EXPECT_EQ(945, f.get_internal_promise().data());
1677
1678 resume_pending_contexts({});
1679}
1680
1681namespace {
1682static copp::callable_future<int> task_future_func_any_callable_in_container(size_t expect_ready_count,
1683 copp::promise_status expect_status) {
1684 size_t old_resume_generator_count = g_task_future_resume_generator_count;
1685 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
1686
1687 size_t resume_ready_count = 0;
1688
1689 std::vector<cotask::task_future<int, void>> tasks;
1690 tasks.emplace_back(task_func_some_any_all_callable_suspend());
1691 tasks.emplace_back(task_func_some_any_all_callable_suspend());
1692 tasks.emplace_back(task_func_some_any_all_callable_suspend());
1693 for (auto &task_object : tasks) {
1694 task_object.start();
1695 }
1696
1697 copp::any_ready<cotask::task_future<int, void>>::type readys;
1698 auto any_result = co_await copp::any(readys, tasks);
1699 CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(any_result));
1700
1701 int result = 1;
1702 for (auto &ready_task : readys) {
1703 if (ready_task->is_exiting()) {
1704 result += *ready_task->get_context()->data();
1705 ++resume_ready_count;
1706 }
1707 }
1708
1709 CASE_EXPECT_EQ(old_resume_generator_count + expect_ready_count, g_task_future_resume_generator_count);
1710 CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_task_future_suspend_generator_count);
1711 CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
1712
1713 // Nothing happend here if we await the tasks again.
1714 any_result = co_await copp::any(readys, tasks);
1715 CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(any_result));
1716
1717 // If it's killed, await will trigger suspend and resume again, or it will return directly.
1718 CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
1719
1720 CASE_EXPECT_EQ(old_resume_generator_count + expect_ready_count, g_task_future_resume_generator_count);
1721 CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_task_future_suspend_generator_count);
1722 CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
1723
1724 co_return result;
1725}
1726} // namespace
1727
1728CASE_TEST(task_promise, finish_any_in_container) {
1729 auto f = task_future_func_any_callable_in_container(1, copp::promise_status::kDone);
1730
1731 CASE_EXPECT_FALSE(f.is_ready());
1732
1733 // partly resume
1734 resume_pending_contexts({671}, 1);
1735
1736 CASE_EXPECT_TRUE(f.is_ready());
1737 CASE_EXPECT_EQ(672, f.get_internal_promise().data());
1738
1739 resume_pending_contexts({});
1740}
1741
1742namespace {
1743static copp::callable_future<int> task_future_func_all_callable_in_container(size_t expect_ready_count,
1744 copp::promise_status expect_status) {
1745 size_t old_resume_generator_count = g_task_future_resume_generator_count;
1746 size_t old_suspend_generator_count = g_task_future_suspend_generator_count;
1747
1748 size_t resume_ready_count = 0;
1749
1750 std::vector<cotask::task_future<int, void>> tasks;
1751 tasks.emplace_back(task_func_some_any_all_callable_suspend());
1752 tasks.emplace_back(task_func_some_any_all_callable_suspend());
1753 tasks.emplace_back(task_func_some_any_all_callable_suspend());
1754 for (auto &task_object : tasks) {
1755 task_object.start();
1756 }
1757
1758 copp::all_ready<cotask::task_future<int, void>>::type readys;
1759 auto all_result = co_await copp::all(readys, tasks);
1760 CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(all_result));
1761
1762 int result = 1;
1763 for (auto &ready_task : readys) {
1764 if (ready_task->is_exiting()) {
1765 result += *ready_task->get_context()->data();
1766 ++resume_ready_count;
1767 }
1768 }
1769
1770 CASE_EXPECT_EQ(old_resume_generator_count + 3, g_task_future_resume_generator_count);
1771 CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_task_future_suspend_generator_count);
1772 CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
1773
1774 // Nothing happend here if we await the tasks again.
1775 all_result = co_await copp::all(readys, tasks);
1776 CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(all_result));
1777
1778 // If it's killed, await will trigger suspend and resume again, or it will return directly.
1779 CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
1780
1781 CASE_EXPECT_EQ(old_resume_generator_count + expect_ready_count, g_task_future_resume_generator_count);
1782 CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_task_future_suspend_generator_count);
1783 CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
1784
1785 co_return result;
1786}
1787} // namespace
1788
1789CASE_TEST(task_promise, finish_all_in_container) {
1790 auto f = task_future_func_all_callable_in_container(3, copp::promise_status::kDone);
1791
1792 CASE_EXPECT_FALSE(f.is_ready());
1793
1794 // partly resume
1795 resume_pending_contexts({671}, 1);
1796 CASE_EXPECT_FALSE(f.is_ready());
1797
1798 resume_pending_contexts({791, 793}, 2);
1799
1800 CASE_EXPECT_TRUE(f.is_ready());
1801 CASE_EXPECT_EQ(2256, f.get_internal_promise().data());
1802
1803 resume_pending_contexts({});
1804}
1805
1806#else
1807CASE_TEST(task_promise, disabled) {}
1808#endif
constexpr auto data(TCONTAINER &&container) -> decltype(container.data())
Definition span.h:54
#define CASE_MSG_INFO()
#define CASE_EXPECT_FALSE(c)
Definition test_macros.h:98
#define CASE_EXPECT_EQ(l, r)
Definition test_macros.h:99
#define CASE_EXPECT_NE(l, r)
#define CASE_TEST(test_name, case_name)
Definition test_macros.h:47
#define CASE_EXPECT_TRUE(c)
Definition test_macros.h:97