1//
2// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7
8#include <boost/cobalt/join.hpp>
9#include <boost/cobalt/generator.hpp>
10#include <boost/cobalt/promise.hpp>
11#include <boost/cobalt/op.hpp>
12
13#include <boost/asio/steady_timer.hpp>
14
15#include <boost/test/unit_test.hpp>
16#include "test.hpp"
17
18using namespace boost;
19
20static cobalt::promise<std::chrono::milliseconds::rep> wdummy(
21 asio::any_io_executor exec,
22 std::chrono::milliseconds ms = std::chrono::milliseconds(25))
23{
24 if (ms == std::chrono::milliseconds ::max())
25 throw std::runtime_error("wdummy_throw");
26
27 asio::steady_timer tim{exec, ms};
28 co_await tim.async_wait(token: cobalt::use_op);
29 co_return ms.count();
30}
31
32static cobalt::generator<int> wgen(asio::any_io_executor exec)
33{
34 asio::steady_timer tim{exec, std::chrono::milliseconds(25)};
35 co_await tim.async_wait(token: cobalt::use_op);
36 co_return 123;
37}
38
39static cobalt::promise<void> wthrow(bool throw_ = false)
40{
41 if (throw_)
42 co_await asio::post(ex: co_await cobalt::this_coro::executor, token: cobalt::use_op);
43 throw std::runtime_error("wthrow");
44 co_return;
45}
46
47static cobalt::promise<void> wnever()
48{
49 asio::steady_timer tim{cobalt::this_thread::get_executor(),
50 std::chrono::steady_clock::time_point::max()};
51 co_await tim.async_wait(token: cobalt::use_op);
52 co_return;
53}
54
55
56BOOST_AUTO_TEST_SUITE(join_);
57
58CO_TEST_CASE(variadic)
59{
60 auto exec = co_await asio::this_coro::executor;
61 auto d1 = wdummy(exec, ms: std::chrono::milliseconds(100));
62 auto d2 = wdummy(exec, ms: std::chrono::milliseconds( 50));
63 asio::steady_timer tim{co_await asio::this_coro::executor};
64 auto g = wgen(exec);
65 auto c = co_await join(p&: d1, p&: d2, p: wdummy(exec, ms: std::chrono::milliseconds(150)),
66 p&: g);
67
68 BOOST_CHECK(std::get<0>(c) == 100);
69 BOOST_CHECK(std::get<1>(c) == 50);
70 BOOST_CHECK(std::get<2>(c) == 150);
71 BOOST_CHECK(std::get<3>(c) == 123);
72}
73
74CO_TEST_CASE(variadic_throw)
75{
76 auto exec = co_await asio::this_coro::executor;
77 auto d1 = wdummy(exec, ms: std::chrono::milliseconds(100));
78 auto d2 = wdummy(exec, ms: std::chrono::milliseconds( 50));
79 asio::steady_timer tim{co_await asio::this_coro::executor};
80 auto g = wgen(exec);
81 try {
82 BOOST_CHECK_THROW(co_await join(d1, d2, wdummy(exec, std::chrono::milliseconds(150)), g, wthrow()),
83 boost::system::system_error);
84 } catch(...) {}
85}
86
87CO_TEST_CASE(list)
88{
89 auto exec = co_await asio::this_coro::executor;
90 std::vector<cobalt::promise<std::chrono::milliseconds::rep>> vec;
91 vec.push_back(x: wdummy(exec, ms: std::chrono::milliseconds(100)));
92 vec.push_back(x: wdummy(exec, ms: std::chrono::milliseconds( 50)));
93 vec.push_back(x: wdummy(exec, ms: std::chrono::milliseconds(150)));
94
95 auto res = co_await join(p: std::move(vec));
96 BOOST_REQUIRE(res.size() == 3);
97 BOOST_CHECK(res[0] == 100);
98 BOOST_CHECK(res[1] == 50);
99 BOOST_CHECK(res[2] == 150);
100}
101
102CO_TEST_CASE(list_exception)
103{
104 auto exec = co_await asio::this_coro::executor;
105 std::vector<cobalt::promise<void>> vec;
106 vec.push_back(x: wthrow());
107 vec.push_back(x: wnever());
108
109 try {
110 BOOST_CHECK_THROW(co_await join(std::move(vec)), boost::system::system_error);
111 } catch(...) {}
112}
113
114CO_TEST_CASE(exception_after_post)
115try
116{
117 BOOST_CHECK_THROW(co_await cobalt::join(wthrow(true), wnever()), boost::system::system_error);
118 BOOST_CHECK_THROW(co_await cobalt::join(wnever(), wthrow(true)), boost::system::system_error);
119} catch(...) {}
120
121
122CO_TEST_CASE(exception_after_list)
123try
124{
125 std::vector<cobalt::promise<void>> vec;
126 vec.push_back(x: wthrow(throw_: true));
127 vec.push_back(x: wnever());
128 BOOST_CHECK_THROW(co_await cobalt::join(vec), boost::system::system_error);
129 vec.clear();
130 vec.push_back(x: wnever());
131 vec.push_back(x: wthrow(throw_: true));
132 BOOST_CHECK_THROW(co_await cobalt::join(vec), boost::system::system_error);
133}
134catch(...)
135{
136
137}
138
139CO_TEST_CASE(compliance)
140{
141 auto exec = co_await asio::this_coro::executor;
142 {
143 auto d = wdummy(exec, ms: std::chrono::milliseconds(1));
144 immediate i;
145 co_await join(p&: d, p&: i);
146 }
147
148 {
149 auto d = wdummy(exec, ms: std::chrono::milliseconds(1));
150 immediate_bool i;
151 co_await join(p&: d, p&: i);
152 }
153 {
154 auto d = wdummy(exec, ms: std::chrono::milliseconds(1));
155 immediate_handle i;
156 co_await join(p&: d, p&: i);
157 }
158 {
159 auto d = wdummy(exec, ms: std::chrono::milliseconds(1));
160 posted p;
161 co_await join(p&: d, p);
162 }
163 {
164 auto d = wdummy(exec, ms: std::chrono::milliseconds(1));
165 posted_bool p;
166 co_await join(p&: d, p);
167 }
168 {
169 auto d = wdummy(exec, ms: std::chrono::milliseconds(1));
170 posted_handle p;
171 co_await join(p&: d, p);
172 }
173}
174
175BOOST_AUTO_TEST_SUITE_END();

source code of boost/libs/cobalt/test/join.cpp