libcopp  2.2.0
generator_promise_test.cpp
Go to the documentation of this file.
1 // Copyright 2023 owent
2 
6 
7 #include <array>
8 #include <cstdio>
9 #include <cstring>
10 #include <iostream>
11 #include <list>
12 #include <string>
13 
14 #include "frame/test_macros.h"
15 
16 #if defined(LIBCOPP_MACRO_ENABLE_STD_COROUTINE) && LIBCOPP_MACRO_ENABLE_STD_COROUTINE
17 
18 using generator_future_int_type = copp::generator_future<int>;
19 using generator_future_void_type = copp::generator_future<void>;
20 
21 namespace {
22 std::list<generator_future_int_type::context_pointer_type> g_pending_int_contexts;
23 std::list<generator_future_void_type::context_pointer_type> g_pending_void_contexts;
24 size_t g_resume_generator_count = 0;
25 size_t g_suspend_generator_count = 0;
26 
27 size_t resume_pending_contexts(std::list<int> values, int max_count = 32767) {
28  size_t ret = 0;
29  while (max_count > 0 && (!g_pending_int_contexts.empty() || !g_pending_void_contexts.empty())) {
30  --max_count;
31  if (!g_pending_int_contexts.empty()) {
32  auto ctx = *g_pending_int_contexts.begin();
33  g_pending_int_contexts.pop_front();
34 
35  if (!values.empty()) {
36  int val = values.front();
37  values.pop_front();
38  ctx->set_value(val);
39  } else {
40  ctx->set_value(0);
41  }
42 
43  ++ret;
44  } else if (!g_pending_void_contexts.empty()) {
45  auto ctx = *g_pending_void_contexts.begin();
46  g_pending_void_contexts.pop_front();
47  ctx->set_value();
48 
49  ++ret;
50  }
51  }
52 
53  return ret;
54 }
55 
56 } // namespace
57 
58 static copp::callable_future<int> callable_func_await_int() {
59  generator_future_int_type gen_left_value{
60  [](generator_future_int_type::context_pointer_type ctx) {
61  ++g_suspend_generator_count;
62  g_pending_int_contexts.push_back(ctx);
63  },
64  [](const generator_future_int_type::context_type &) { ++g_resume_generator_count; }};
65 
66  // await left value
67  CASE_EXPECT_FALSE(gen_left_value.is_ready());
68  CASE_EXPECT_TRUE(gen_left_value.is_pending());
69  CASE_EXPECT_TRUE(gen_left_value.get_status() == copp::promise_status::kRunning);
70  int x1 = co_await gen_left_value;
71  CASE_EXPECT_TRUE(gen_left_value.is_ready());
72  CASE_EXPECT_FALSE(gen_left_value.is_pending());
73  CASE_EXPECT_TRUE(gen_left_value.get_status() == copp::promise_status::kDone);
74 
75  // Await a ready generator will be ignored and will not incease suspend count
76  CASE_EXPECT_EQ(x1, co_await gen_left_value);
77 
78  // await right value
79  int x2 = co_await generator_future_int_type{
80  [](generator_future_int_type::context_pointer_type ctx) {
81  ++g_suspend_generator_count;
82  g_pending_int_contexts.push_back(ctx);
83  },
84  [](const generator_future_int_type::context_type &) { ++g_resume_generator_count; }};
85 
86  generator_future_void_type gen_left_void{
87  [](generator_future_void_type::context_pointer_type ctx) {
88  ++g_suspend_generator_count;
89  g_pending_void_contexts.push_back(ctx);
90  },
91  [](const generator_future_void_type::context_type &) { ++g_resume_generator_count; }};
92 
93  // await left value
94  CASE_EXPECT_FALSE(gen_left_void.is_ready());
95  CASE_EXPECT_TRUE(gen_left_void.is_pending());
96  CASE_EXPECT_TRUE(gen_left_void.get_status() == copp::promise_status::kRunning);
97  co_await gen_left_void;
98  CASE_EXPECT_TRUE(gen_left_void.is_ready());
99  CASE_EXPECT_FALSE(gen_left_void.is_pending());
100  CASE_EXPECT_TRUE(gen_left_void.get_status() == copp::promise_status::kDone);
101 
102  // Await a ready generator will be ignored and will not incease suspend count
103  co_await gen_left_void;
104 
105  // await right value
106  co_await generator_future_void_type{
107  [](generator_future_void_type::context_pointer_type ctx) {
108  ++g_suspend_generator_count;
109  g_pending_void_contexts.push_back(ctx);
110  },
111  [](const generator_future_void_type::context_type &) { ++g_resume_generator_count; }};
112 
113  co_return x1 + x2;
114 }
115 
116 CASE_TEST(generator_promise, basic_int_generator) {
117  size_t old_resume_generator_count = g_resume_generator_count;
118  size_t old_suspend_generator_count = g_suspend_generator_count;
119 
120  copp::callable_future<int> f = callable_func_await_int();
121 
122  CASE_EXPECT_NE(static_cast<int>(copp::promise_status::kDone), static_cast<int>(f.get_status()));
123  CASE_EXPECT_FALSE(f.is_ready());
124 
125  resume_pending_contexts({13100, 13});
126 
127  CASE_EXPECT_TRUE(f.is_ready());
128  CASE_EXPECT_EQ(13113, f.get_internal_promise().data());
129 
130  CASE_EXPECT_EQ(old_resume_generator_count + 4, g_resume_generator_count);
131  CASE_EXPECT_EQ(old_suspend_generator_count + 4, g_suspend_generator_count);
132 }
133 
134 static copp::callable_future<int> callable_func_await_int_killed() {
135  generator_future_int_type gen_left_value{[](generator_future_int_type::context_pointer_type ctx) {
136  ++g_suspend_generator_count;
137  g_pending_int_contexts.push_back(ctx);
138  },
139  [](const generator_future_int_type::context_type &ctx) {
140  CASE_EXPECT_FALSE(ctx.is_ready());
141  CASE_EXPECT_TRUE(ctx.is_pending());
142  ++g_resume_generator_count;
143  }};
144 
145  // await left value
146  CASE_EXPECT_FALSE(gen_left_value.is_ready());
147  CASE_EXPECT_TRUE(gen_left_value.is_pending());
148  CASE_EXPECT_TRUE(gen_left_value.get_status() == copp::promise_status::kRunning);
149  int x1 = co_await gen_left_value;
150  CASE_EXPECT_FALSE(gen_left_value.is_ready());
151  CASE_EXPECT_TRUE(gen_left_value.is_pending());
152  CASE_EXPECT_TRUE(gen_left_value.get_status() == copp::promise_status::kRunning);
153 
154  auto current_callable_status = co_yield copp::callable_future<int>::yield_status();
155  CASE_EXPECT_TRUE(current_callable_status == copp::promise_status::kKilled);
156 
157  // All co_await will be ignored after caller is killed
158  co_await gen_left_value;
159 
160  generator_future_void_type gen_left_void{[](generator_future_void_type::context_pointer_type ctx) {
161  ++g_suspend_generator_count;
162  g_pending_void_contexts.push_back(ctx);
163  },
164  [](const generator_future_void_type::context_type &ctx) {
165  CASE_EXPECT_FALSE(ctx.is_ready());
166  CASE_EXPECT_TRUE(ctx.is_pending());
167  ++g_resume_generator_count;
168  }};
169 
170  // All co_await will be ignored after caller is killed
171  CASE_EXPECT_FALSE(gen_left_void.is_ready());
172  CASE_EXPECT_TRUE(gen_left_void.is_pending());
173  CASE_EXPECT_TRUE(gen_left_void.get_status() == copp::promise_status::kRunning);
174  co_await gen_left_void;
175  CASE_EXPECT_FALSE(gen_left_void.is_ready());
176  CASE_EXPECT_TRUE(gen_left_void.is_pending());
177  CASE_EXPECT_TRUE(gen_left_void.get_status() == copp::promise_status::kRunning);
178 
179  co_return x1;
180 }
181 
182 static copp::callable_future<void> callable_func_await_void_killed() {
183  generator_future_void_type gen_left_void{[](generator_future_void_type::context_pointer_type ctx) {
184  ++g_suspend_generator_count;
185  g_pending_void_contexts.push_back(ctx);
186  },
187  [](const generator_future_void_type::context_type &ctx) {
188  CASE_EXPECT_FALSE(ctx.is_ready());
189  CASE_EXPECT_TRUE(ctx.is_pending());
190  ++g_resume_generator_count;
191  }};
192 
193  // await left value
194  CASE_EXPECT_FALSE(gen_left_void.is_ready());
195  CASE_EXPECT_TRUE(gen_left_void.is_pending());
196  CASE_EXPECT_TRUE(gen_left_void.get_status() == copp::promise_status::kRunning);
197  co_await gen_left_void;
198  CASE_EXPECT_FALSE(gen_left_void.is_ready());
199  CASE_EXPECT_TRUE(gen_left_void.is_pending());
200  CASE_EXPECT_TRUE(gen_left_void.get_status() == copp::promise_status::kRunning);
201 
202  // All co_await will be ignored after caller is killed
203  co_await gen_left_void;
204 
205  generator_future_int_type gen_left_value{[](generator_future_int_type::context_pointer_type ctx) {
206  ++g_suspend_generator_count;
207  g_pending_int_contexts.push_back(ctx);
208  },
209  [](const generator_future_int_type::context_type &ctx) {
210  CASE_EXPECT_FALSE(ctx.is_ready());
211  CASE_EXPECT_TRUE(ctx.is_pending());
212  ++g_resume_generator_count;
213  }};
214 
215  // All co_await will be ignored after caller is killed
216  CASE_EXPECT_FALSE(gen_left_value.is_ready());
217  CASE_EXPECT_TRUE(gen_left_value.is_pending());
218  CASE_EXPECT_TRUE(gen_left_value.get_status() == copp::promise_status::kRunning);
219  co_await gen_left_value;
220  CASE_EXPECT_FALSE(gen_left_value.is_ready());
221  CASE_EXPECT_TRUE(gen_left_value.is_pending());
222  CASE_EXPECT_TRUE(gen_left_value.get_status() == copp::promise_status::kRunning);
223 
224  auto current_callable_status = co_yield copp::callable_future<int>::yield_status();
225  CASE_EXPECT_TRUE(current_callable_status == copp::promise_status::kKilled);
226 
227  co_return;
228 }
229 
230 CASE_TEST(generator_promise, caller_killed) {
231  {
232  size_t old_resume_generator_count = g_resume_generator_count;
233  size_t old_suspend_generator_count = g_suspend_generator_count;
234 
235  copp::callable_future<int> f = callable_func_await_int_killed();
236 
237  // Mock to kill by caller
238  f.kill(copp::promise_status::kKilled, true);
239  CASE_EXPECT_TRUE(f.is_ready());
240 
241  CASE_EXPECT_EQ(old_resume_generator_count + 1, g_resume_generator_count);
242  CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_suspend_generator_count);
243  }
244 
245  {
246  size_t old_resume_generator_count = g_resume_generator_count;
247  size_t old_suspend_generator_count = g_suspend_generator_count;
248 
249  copp::callable_future<void> f = callable_func_await_void_killed();
250 
251  // Mock to kill by caller
252  f.kill(copp::promise_status::kKilled, true);
253  CASE_EXPECT_TRUE(f.is_ready());
254 
255  CASE_EXPECT_EQ(old_resume_generator_count + 1, g_resume_generator_count);
256  CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_suspend_generator_count);
257  }
258 
259  resume_pending_contexts({});
260 }
261 
262 static copp::callable_future<int> callable_func_await_int_killed_by_destroy_generator(
263  std::unique_ptr<generator_future_int_type> &gen_left_value) {
264  gen_left_value.reset(new generator_future_int_type(
265  [](generator_future_int_type::context_pointer_type) {
266  ++g_suspend_generator_count;
267  // No reference to ctx, so it will be destroyed when last generator is
268  // destroyed
269  },
270  [](const generator_future_int_type::context_type &ctx) {
271  CASE_EXPECT_TRUE(ctx.is_ready());
272  CASE_EXPECT_EQ(*ctx.data(), -static_cast<int>(copp::promise_status::kKilled));
273  ++g_resume_generator_count;
274  }));
275 
276  // await left value
277  CASE_EXPECT_FALSE(gen_left_value->is_ready());
278  CASE_EXPECT_TRUE(gen_left_value->is_pending());
279  CASE_EXPECT_TRUE(gen_left_value->get_status() == copp::promise_status::kRunning);
280  int x1 = co_await *gen_left_value;
281  CASE_EXPECT_TRUE(nullptr == gen_left_value);
282 
283  CASE_EXPECT_EQ(x1, -static_cast<int>(copp::promise_status::kKilled));
284 
285  co_return x1;
286 }
287 
288 CASE_TEST(generator_promise, caller_killed_by_destroy_generator) {
289  std::unique_ptr<generator_future_int_type> gen_left_value;
290 
291  size_t old_resume_generator_count = g_resume_generator_count;
292  size_t old_suspend_generator_count = g_suspend_generator_count;
293 
294  copp::callable_future<int> f = callable_func_await_int_killed_by_destroy_generator(gen_left_value);
295 
296  // Mock to kill by caller
297  gen_left_value.reset();
298  CASE_EXPECT_TRUE(f.is_ready());
299 
300  CASE_EXPECT_EQ(old_resume_generator_count + 1, g_resume_generator_count);
301  CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_suspend_generator_count);
302 }
303 
304 static copp::callable_future<int> callable_func_await_int_killed_by_destroy_generator_in_callback(
305  std::unique_ptr<generator_future_int_type> &gen_left_value) {
306  gen_left_value.reset(new generator_future_int_type(
307  [&gen_left_value](generator_future_int_type::context_pointer_type) {
308  ++g_suspend_generator_count;
309  // No reference to ctx, so it will be destroyed when last generator is
310  // destroyed
311 
312  gen_left_value.reset();
313  },
314  [](const generator_future_int_type::context_type &ctx) {
315  CASE_EXPECT_TRUE(ctx.is_ready());
316  CASE_EXPECT_EQ(*ctx.data(), -static_cast<int>(copp::promise_status::kKilled));
317  ++g_resume_generator_count;
318  }));
319 
320  // await left value
321  CASE_EXPECT_FALSE(gen_left_value->is_ready());
322  CASE_EXPECT_TRUE(gen_left_value->is_pending());
323  CASE_EXPECT_TRUE(gen_left_value->get_status() == copp::promise_status::kRunning);
324  int x1 = co_await *gen_left_value;
325  CASE_EXPECT_TRUE(nullptr == gen_left_value);
326 
327  CASE_EXPECT_EQ(x1, -static_cast<int>(copp::promise_status::kKilled));
328 
329  co_return x1;
330 }
331 
332 CASE_TEST(generator_promise, caller_killed_by_destroy_generator_in_callback) {
333  std::unique_ptr<generator_future_int_type> gen_left_value;
334 
335  size_t old_resume_generator_count = g_resume_generator_count;
336  size_t old_suspend_generator_count = g_suspend_generator_count;
337 
338  copp::callable_future<int> f = callable_func_await_int_killed_by_destroy_generator_in_callback(gen_left_value);
339 
340  // Mock to kill by caller
341  CASE_EXPECT_TRUE(f.is_ready());
342 
343  CASE_EXPECT_EQ(old_resume_generator_count + 1, g_resume_generator_count);
344  CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_suspend_generator_count);
345 }
346 
347 class test_context_transform_error_code_type {
348  public:
349  int code;
350 
351  test_context_transform_error_code_type() : code(0) {}
352  test_context_transform_error_code_type(int c) : code(c) {}
353  test_context_transform_error_code_type(const test_context_transform_error_code_type &) = default;
354  test_context_transform_error_code_type &operator=(const test_context_transform_error_code_type &) = default;
355  test_context_transform_error_code_type(test_context_transform_error_code_type &&) = default;
356  test_context_transform_error_code_type &operator=(test_context_transform_error_code_type &&) = default;
357  ~test_context_transform_error_code_type() {}
358 };
359 
360 LIBCOPP_COPP_NAMESPACE_BEGIN
361 template <>
362 struct promise_error_transform<test_context_transform_error_code_type> {
363  using type = test_context_transform_error_code_type;
364  type operator()(promise_status in) const {
365  if (in == promise_status::kTimeout) {
366  return test_context_transform_error_code_type{-500};
367  }
368  return test_context_transform_error_code_type{static_cast<int>(in)};
369  }
370 };
371 LIBCOPP_COPP_NAMESPACE_END
372 
373 namespace {
374 using test_context_transform_error_code_generator = copp::generator_future<test_context_transform_error_code_type>;
375 std::list<test_context_transform_error_code_generator::context_pointer_type>
376  g_test_context_transform_error_code_generator_executor;
377 
378 static copp::callable_future<int> test_context_transform_error_code_generator_l2() {
379  auto result = co_await test_context_transform_error_code_generator{
380  [](test_context_transform_error_code_generator::context_pointer_type ctx) {
381  g_test_context_transform_error_code_generator_executor.emplace_back(std::move(ctx));
382  }};
383  co_return result.code;
384 }
385 
386 static copp::callable_future<void> test_context_transform_error_code_generator_l1() {
387  auto result = co_await test_context_transform_error_code_generator_l2();
388  CASE_EXPECT_EQ(result, -500);
389  co_return;
390 }
391 } // namespace
392 
393 CASE_TEST(generator_promise, transform_error_code) {
394  auto f2 = test_context_transform_error_code_generator_l1();
395  f2.kill(copp::promise_status::kTimeout, true);
396 
397  g_test_context_transform_error_code_generator_executor.clear();
398 }
399 
400 static copp::callable_future<int> callable_func_multiple_await_int(generator_future_int_type &shared_generator) {
401  auto result = co_await shared_generator;
402  co_return result;
403 }
404 
405 CASE_TEST(generator_promise, miltiple_wait_int_generator) {
406  size_t old_resume_generator_count = g_resume_generator_count;
407  size_t old_suspend_generator_count = g_suspend_generator_count;
408 
409  generator_future_int_type int_generator{
410  [](generator_future_int_type::context_pointer_type ctx) {
411  ++g_suspend_generator_count;
412  if (g_pending_int_contexts.end() ==
413  std::find(g_pending_int_contexts.begin(), g_pending_int_contexts.end(), ctx)) {
414  g_pending_int_contexts.push_back(ctx);
415  }
416  },
417  [](const generator_future_int_type::context_type &) { ++g_resume_generator_count; }};
418 
419  copp::callable_future<int> f1 = callable_func_multiple_await_int(int_generator);
420  copp::callable_future<int> f2 = callable_func_multiple_await_int(int_generator);
421 
422  CASE_EXPECT_NE(static_cast<int>(copp::promise_status::kDone), static_cast<int>(f1.get_status()));
423  CASE_EXPECT_FALSE(f1.is_ready());
424  CASE_EXPECT_NE(static_cast<int>(copp::promise_status::kDone), static_cast<int>(f2.get_status()));
425  CASE_EXPECT_FALSE(f2.is_ready());
426 
427  CASE_EXPECT_EQ(1, resume_pending_contexts({143}));
428 
429  CASE_EXPECT_TRUE(f1.is_ready());
430  CASE_EXPECT_EQ(143, f1.get_internal_promise().data());
431  CASE_EXPECT_TRUE(f2.is_ready());
432  CASE_EXPECT_EQ(143, f2.get_internal_promise().data());
433 
434  CASE_EXPECT_EQ(old_resume_generator_count + 2, g_resume_generator_count);
435  CASE_EXPECT_EQ(old_suspend_generator_count + 2, g_suspend_generator_count);
436 }
437 
438 static copp::callable_future<int> callable_func_resume_when_suspend() {
439  auto result = co_await generator_future_int_type{
440  [](generator_future_int_type::context_pointer_type ctx) {
441  ++g_suspend_generator_count;
442  ctx->set_value(369);
443  },
444  [](const generator_future_int_type::context_type &) { ++g_resume_generator_count; }};
445  co_return result;
446 }
447 
448 CASE_TEST(generator_promise, resume_when_suspend) {
449  size_t old_resume_generator_count = g_resume_generator_count;
450  size_t old_suspend_generator_count = g_suspend_generator_count;
451 
452  copp::callable_future<int> f1 = callable_func_resume_when_suspend();
453 
454  CASE_EXPECT_EQ(static_cast<int>(copp::promise_status::kDone), static_cast<int>(f1.get_status()));
455  CASE_EXPECT_TRUE(f1.is_ready());
456  CASE_EXPECT_EQ(369, f1.get_internal_promise().data());
457 
458  CASE_EXPECT_EQ(old_resume_generator_count + 1, g_resume_generator_count);
459  CASE_EXPECT_EQ(old_suspend_generator_count + 1, g_suspend_generator_count);
460 }
461 
462 static copp::callable_future<int> callable_func_some_generator_in_container(size_t expect_ready_count,
463  copp::promise_status expect_status) {
464  size_t old_resume_generator_count = g_resume_generator_count;
465  size_t old_suspend_generator_count = g_suspend_generator_count;
466 
467  size_t resume_ready_count = 0;
468  auto suspend_callback = [](generator_future_int_type::context_pointer_type ctx) {
469  ++g_suspend_generator_count;
470  g_pending_int_contexts.push_back(ctx);
471  };
472  auto resume_callback = [&resume_ready_count](const generator_future_int_type::context_type &ctx) {
473  ++g_resume_generator_count;
474  if (ctx.is_ready()) {
475  ++resume_ready_count;
476  }
477  };
478 
479  std::vector<generator_future_int_type> generators;
480  generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
481  generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
482  generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
483 
484  copp::some_ready<generator_future_int_type>::type readys;
485  auto some_result = co_await copp::some(readys, 2, generators);
486  CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(some_result));
487 
488  int result = 1;
489  for (auto &ready_generator : readys) {
490  result += *ready_generator->get_context()->data();
491  }
492 
493  CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
494  CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
495  CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
496 
497  // Nothing happend here if we await the generators again.
498  some_result = co_await copp::some(readys, 2, generators);
499  CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(some_result));
500 
501  // If it's killed, await will trigger suspend and resume again, or it will return directly.
502  if (expect_status > copp::promise_status::kDone) {
503  CASE_EXPECT_EQ(old_resume_generator_count + 6 - resume_ready_count, g_resume_generator_count);
504  CASE_EXPECT_EQ(old_suspend_generator_count + 6 - resume_ready_count, g_suspend_generator_count);
505  CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
506  } else {
507  CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
508  CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
509  CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
510  }
511 
512  co_return result;
513 }
514 
515 CASE_TEST(generator_promise, finish_some_in_container) {
516  auto f = callable_func_some_generator_in_container(2, copp::promise_status::kDone);
517 
518  CASE_EXPECT_FALSE(f.is_ready());
519 
520  // partly resume
521  resume_pending_contexts({471}, 1);
522  CASE_EXPECT_FALSE(f.is_ready());
523  resume_pending_contexts({473}, 1);
524 
525  CASE_EXPECT_TRUE(f.is_ready());
526  CASE_EXPECT_EQ(945, f.get_internal_promise().data());
527 
528  resume_pending_contexts({});
529 }
530 
531 CASE_TEST(generator_promise, kill_some_in_container) {
532  auto f = callable_func_some_generator_in_container(0, copp::promise_status::kKilled);
533 
534  CASE_EXPECT_FALSE(f.is_ready());
535 
536  // partly resume
537  f.kill();
538 
539  CASE_EXPECT_TRUE(f.is_ready());
540  CASE_EXPECT_EQ(1, f.get_internal_promise().data());
541 
542  resume_pending_contexts({});
543 }
544 
545 static copp::callable_future<int> callable_func_some_generator_in_initialize_list(size_t expect_ready_count,
546  copp::promise_status expect_status) {
547  size_t old_resume_generator_count = g_resume_generator_count;
548  size_t old_suspend_generator_count = g_suspend_generator_count;
549 
550  size_t resume_ready_count = 0;
551  auto suspend_callback = [](generator_future_int_type::context_pointer_type ctx) {
552  ++g_suspend_generator_count;
553  g_pending_int_contexts.push_back(ctx);
554  };
555  auto resume_callback = [&resume_ready_count](const generator_future_int_type::context_type &ctx) {
556  ++g_resume_generator_count;
557  if (ctx.is_ready()) {
558  ++resume_ready_count;
559  }
560  };
561 
562  generator_future_int_type gen1{suspend_callback, resume_callback};
563  generator_future_int_type gen2{suspend_callback, resume_callback};
564  generator_future_int_type gen3{suspend_callback, resume_callback};
565 
566  copp::some_ready<generator_future_int_type>::type readys;
567  std::array<std::reference_wrapper<generator_future_int_type>, 3> pending = {gen1, gen2, gen3};
568  auto some_result = co_await copp::some(readys, 2, copp::gsl::make_span(pending));
569  CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(some_result));
570 
571  int result = 1;
572  for (auto &ready_generator : readys) {
573  result += *ready_generator->get_context()->data();
574  }
575 
576  CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
577  CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
578  CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
579 
580  co_return result;
581 }
582 
583 CASE_TEST(generator_promise, finish_some_in_initialize_list) {
584  auto f = callable_func_some_generator_in_initialize_list(2, copp::promise_status::kDone);
585 
586  CASE_EXPECT_FALSE(f.is_ready());
587 
588  // partly resume
589  resume_pending_contexts({471}, 1);
590  CASE_EXPECT_FALSE(f.is_ready());
591  resume_pending_contexts({473}, 1);
592 
593  CASE_EXPECT_TRUE(f.is_ready());
594  CASE_EXPECT_EQ(945, f.get_internal_promise().data());
595 
596  resume_pending_contexts({});
597 }
598 
599 static copp::callable_future<int> callable_func_any_generator_in_container(size_t expect_ready_count,
600  copp::promise_status expect_status) {
601  size_t old_resume_generator_count = g_resume_generator_count;
602  size_t old_suspend_generator_count = g_suspend_generator_count;
603 
604  size_t resume_ready_count = 0;
605  auto suspend_callback = [](generator_future_int_type::context_pointer_type ctx) {
606  ++g_suspend_generator_count;
607  g_pending_int_contexts.push_back(ctx);
608  };
609  auto resume_callback = [&resume_ready_count](const generator_future_int_type::context_type &ctx) {
610  ++g_resume_generator_count;
611  if (ctx.is_ready()) {
612  ++resume_ready_count;
613  }
614  };
615 
616  std::vector<generator_future_int_type> generators;
617  generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
618  generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
619  generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
620 
621  copp::any_ready<generator_future_int_type>::type readys;
622  auto any_result = co_await copp::any(readys, generators);
623  CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(any_result));
624 
625  int result = 1;
626  for (auto &ready_generator : readys) {
627  result += *ready_generator->get_context()->data();
628  }
629 
630  CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
631  CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
632  CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
633 
634  // Nothing happend here if we await the generators again.
635  std::vector<copp::gsl::not_null<generator_future_int_type *>> generators_not_null_type;
636  for (auto &generator : generators) {
637  generators_not_null_type.push_back(copp::gsl::make_not_null(&generator));
638  }
639  any_result = co_await copp::any(readys, generators_not_null_type);
640  CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(any_result));
641 
642  // If it's killed, await will trigger suspend and resume again, or it will return directly.
643  if (expect_status > copp::promise_status::kDone) {
644  CASE_EXPECT_EQ(old_resume_generator_count + 6 - resume_ready_count, g_resume_generator_count);
645  CASE_EXPECT_EQ(old_suspend_generator_count + 6 - resume_ready_count, g_suspend_generator_count);
646  CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
647  } else {
648  CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
649  CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
650  CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
651  }
652 
653  co_return result;
654 }
655 
656 CASE_TEST(generator_promise, finish_any_in_container) {
657  auto f = callable_func_any_generator_in_container(1, copp::promise_status::kDone);
658 
659  CASE_EXPECT_FALSE(f.is_ready());
660 
661  // partly resume
662  resume_pending_contexts({671}, 1);
663 
664  CASE_EXPECT_TRUE(f.is_ready());
665  CASE_EXPECT_EQ(672, f.get_internal_promise().data());
666 
667  resume_pending_contexts({});
668 }
669 
670 static copp::callable_future<int> callable_func_all_generator_in_container(size_t expect_ready_count,
671  copp::promise_status expect_status) {
672  size_t old_resume_generator_count = g_resume_generator_count;
673  size_t old_suspend_generator_count = g_suspend_generator_count;
674 
675  size_t resume_ready_count = 0;
676  auto suspend_callback = [](generator_future_int_type::context_pointer_type ctx) {
677  ++g_suspend_generator_count;
678  g_pending_int_contexts.push_back(ctx);
679  };
680  auto resume_callback = [&resume_ready_count](const generator_future_int_type::context_type &ctx) {
681  ++g_resume_generator_count;
682  if (ctx.is_ready()) {
683  ++resume_ready_count;
684  }
685  };
686 
687  std::vector<generator_future_int_type> generators;
688  generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
689  generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
690  generators.push_back(generator_future_int_type(suspend_callback, resume_callback));
691 
692  copp::all_ready<generator_future_int_type>::type readys;
693  auto all_result = co_await copp::all(readys, generators);
694  CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(all_result));
695 
696  int result = 1;
697  for (auto &ready_generator : readys) {
698  result += *ready_generator->get_context()->data();
699  }
700 
701  CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
702  CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
703  CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
704 
705  // Nothing happend here if we await the generators again.
706  all_result = co_await copp::all(readys, generators);
707  CASE_EXPECT_EQ(static_cast<int>(expect_status), static_cast<int>(all_result));
708 
709  // If it's killed, await will trigger suspend and resume again, or it will return directly.
710  if (expect_status > copp::promise_status::kDone) {
711  CASE_EXPECT_EQ(old_resume_generator_count + 6 - resume_ready_count, g_resume_generator_count);
712  CASE_EXPECT_EQ(old_suspend_generator_count + 6 - resume_ready_count, g_suspend_generator_count);
713  CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
714  } else {
715  CASE_EXPECT_EQ(old_resume_generator_count + 3, g_resume_generator_count);
716  CASE_EXPECT_EQ(old_suspend_generator_count + 3, g_suspend_generator_count);
717  CASE_EXPECT_EQ(expect_ready_count, resume_ready_count);
718  }
719 
720  co_return result;
721 }
722 
723 CASE_TEST(generator_promise, finish_all_in_container) {
724  auto f = callable_func_all_generator_in_container(3, copp::promise_status::kDone);
725 
726  CASE_EXPECT_FALSE(f.is_ready());
727 
728  // partly resume
729  resume_pending_contexts({671}, 1);
730  CASE_EXPECT_FALSE(f.is_ready());
731 
732  resume_pending_contexts({791, 793}, 2);
733 
734  CASE_EXPECT_TRUE(f.is_ready());
735  CASE_EXPECT_EQ(2256, f.get_internal_promise().data());
736 
737  resume_pending_contexts({});
738 }
739 
740 #else
741 CASE_TEST(generator_promise, disabled) {}
742 #endif
CASE_TEST(generator_promise, disabled)
auto make_not_null(T &&t) noexcept
Definition: not_null.h:111
constexpr span< TELEMENT > make_span(TELEMENT *ptr, typename span< TELEMENT >::size_type count)
Definition: span.h:255
#define CASE_EXPECT_FALSE(c)
Definition: test_macros.h:95
#define CASE_EXPECT_EQ(l, r)
Definition: test_macros.h:96
#define CASE_EXPECT_NE(l, r)
Definition: test_macros.h:97
#define CASE_EXPECT_TRUE(c)
Definition: test_macros.h:94