]>
Commit | Line | Data |
---|---|---|
1e59de90 TL |
1 | // |
2 | // experimental/coro/simple_test.cpp | |
3 | // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
4 | // | |
5 | // Copyright (c) 2021-2022 Klemens D. Morgenstern | |
6 | // (klemens dot morgenstern at gmx dot net) | |
7 | // | |
8 | // Distributed under the Boost Software License, Version 1.0. (See accompanying | |
9 | // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) | |
10 | // | |
11 | ||
12 | // Disable autolinking for unit tests. | |
13 | #if !defined(BOOST_ALL_NO_LIB) | |
14 | #define BOOST_ALL_NO_LIB 1 | |
15 | #endif // !defined(BOOST_ALL_NO_LIB) | |
16 | ||
17 | // Test that header file is self-contained. | |
18 | #include <boost/asio/experimental/coro.hpp> | |
19 | ||
20 | #include <boost/asio/co_spawn.hpp> | |
21 | #include <boost/asio/detached.hpp> | |
22 | #include <boost/asio/io_context.hpp> | |
23 | #include <boost/asio/use_awaitable.hpp> | |
24 | #include <iostream> | |
25 | #include <vector> | |
26 | #include "../../unit_test.hpp" | |
27 | ||
28 | using namespace boost::asio::experimental; | |
29 | ||
30 | namespace boost { | |
31 | namespace asio { | |
32 | namespace experimental { | |
33 | ||
34 | template struct coro<void(), void, any_io_executor>; | |
35 | template struct coro<int(), void, any_io_executor>; | |
36 | template struct coro<void(), int, any_io_executor>; | |
37 | template struct coro<int(int), void, any_io_executor>; | |
38 | template struct coro<int(), int, any_io_executor>; | |
39 | template struct coro<int(int), int, any_io_executor>; | |
40 | ||
41 | template struct coro<void() noexcept, void, any_io_executor>; | |
42 | template struct coro<int() noexcept, void, any_io_executor>; | |
43 | template struct coro<void() noexcept, int, any_io_executor>; | |
44 | template struct coro<int(int) noexcept, void, any_io_executor>; | |
45 | template struct coro<int() noexcept, int, any_io_executor>; | |
46 | template struct coro<int(int) noexcept, int, any_io_executor>; | |
47 | ||
48 | } // namespace experimental | |
49 | } // namespace asio | |
50 | } // namespace boost | |
51 | ||
52 | namespace coro { | |
53 | ||
54 | template <typename Func> | |
55 | struct on_scope_exit | |
56 | { | |
57 | Func func; | |
58 | ||
59 | static_assert(noexcept(func())); | |
60 | ||
61 | on_scope_exit(const Func &f) | |
62 | : func(static_cast< Func && >(f)) | |
63 | { | |
64 | } | |
65 | ||
66 | on_scope_exit(Func &&f) | |
67 | : func(f) | |
68 | { | |
69 | } | |
70 | ||
71 | on_scope_exit(const on_scope_exit &) = delete; | |
72 | ||
73 | ~on_scope_exit() | |
74 | { | |
75 | func(); | |
76 | } | |
77 | }; | |
78 | ||
79 | boost::asio::experimental::coro<int> generator_impl( | |
80 | boost::asio::any_io_executor, int& last, bool& destroyed) | |
81 | { | |
82 | on_scope_exit x = [&]() noexcept { destroyed = true; }; | |
83 | (void)x; | |
84 | ||
85 | int i = 0; | |
86 | while (true) | |
87 | co_yield last = ++i; | |
88 | } | |
89 | ||
90 | boost::asio::awaitable<void> generator_test() | |
91 | { | |
92 | int val = 0; | |
93 | bool destr = false; | |
94 | { | |
95 | auto gi = generator_impl( | |
96 | co_await boost::asio::this_coro::executor, val, destr); | |
97 | ||
98 | for (int i = 0; i < 10; i++) | |
99 | { | |
100 | BOOST_ASIO_CHECK(val == i); | |
101 | const auto next = co_await gi.async_resume(boost::asio::use_awaitable); | |
102 | BOOST_ASIO_CHECK(next); | |
103 | BOOST_ASIO_CHECK(val == *next); | |
104 | BOOST_ASIO_CHECK(val == i + 1); | |
105 | } | |
106 | ||
107 | BOOST_ASIO_CHECK(!destr); | |
108 | } | |
109 | BOOST_ASIO_CHECK(destr); | |
110 | }; | |
111 | ||
112 | void run_generator_test() | |
113 | { | |
114 | boost::asio::io_context ctx; | |
115 | boost::asio::co_spawn(ctx, generator_test, boost::asio::detached); | |
116 | ctx.run(); | |
117 | } | |
118 | ||
119 | boost::asio::experimental::coro<void, int> task_test(boost::asio::io_context&) | |
120 | { | |
121 | co_return 42; | |
122 | } | |
123 | ||
124 | boost::asio::experimental::coro<void, int> task_throw(boost::asio::io_context&) | |
125 | { | |
126 | throw std::logic_error(__func__); | |
127 | co_return 42; | |
128 | } | |
129 | ||
130 | void run_task_test() | |
131 | { | |
132 | boost::asio::io_context ctx; | |
133 | ||
134 | bool tt1 = false; | |
135 | bool tt2 = false; | |
136 | bool tt3 = false; | |
137 | bool tt4 = false; | |
138 | auto tt = task_test(ctx); | |
139 | tt.async_resume( | |
140 | [&](std::exception_ptr pt, int i) | |
141 | { | |
142 | tt1 = true; | |
143 | BOOST_ASIO_CHECK(!pt); | |
144 | BOOST_ASIO_CHECK(i == 42); | |
145 | tt.async_resume( | |
146 | [&](std::exception_ptr pt, int) | |
147 | { | |
148 | tt2 = true; | |
149 | BOOST_ASIO_CHECK(pt); | |
150 | }); | |
151 | }); | |
152 | ||
153 | auto tt_2 = task_throw(ctx); | |
154 | ||
155 | tt_2.async_resume( | |
156 | [&](std::exception_ptr pt, int) | |
157 | { | |
158 | tt3 = true; | |
159 | BOOST_ASIO_CHECK(pt); | |
160 | tt.async_resume( | |
161 | [&](std::exception_ptr pt, int) | |
162 | { | |
163 | tt4 = true; | |
164 | BOOST_ASIO_CHECK(pt); | |
165 | }); | |
166 | }); | |
167 | ||
168 | ctx.run(); | |
169 | ||
170 | BOOST_ASIO_CHECK(tt1); | |
171 | BOOST_ASIO_CHECK(tt2); | |
172 | BOOST_ASIO_CHECK(tt3); | |
173 | BOOST_ASIO_CHECK(tt4); | |
174 | } | |
175 | ||
176 | boost::asio::experimental::coro<char> completion_generator_test_impl( | |
177 | boost::asio::any_io_executor, int limit) | |
178 | { | |
179 | for (int i = 0; i < limit; i++) | |
180 | co_yield i; | |
181 | } | |
182 | ||
183 | boost::asio::awaitable<void> completion_generator_test() | |
184 | { | |
185 | std::vector<int> res; | |
186 | auto g = completion_generator_test_impl( | |
187 | co_await boost::asio::this_coro::executor, 10); | |
188 | ||
189 | BOOST_ASIO_CHECK(g.is_open()); | |
190 | while (auto val = co_await g.async_resume(boost::asio::use_awaitable)) | |
191 | res.push_back(*val); | |
192 | ||
193 | BOOST_ASIO_CHECK(!g.is_open()); | |
194 | BOOST_ASIO_CHECK((res == std::vector{0,1,2,3,4,5,6,7,8,9})); | |
195 | }; | |
196 | ||
197 | ||
198 | void run_completion_generator_test() | |
199 | { | |
200 | boost::asio::io_context ctx; | |
201 | boost::asio::co_spawn(ctx, completion_generator_test, boost::asio::detached); | |
202 | ctx.run(); | |
203 | } | |
204 | ||
205 | boost::asio::experimental::coro<int(int)> | |
206 | symmetrical_test_impl(boost::asio::any_io_executor) | |
207 | { | |
208 | int i = 0; | |
209 | while (true) | |
210 | i = (co_yield i) + i; | |
211 | } | |
212 | ||
213 | boost::asio::awaitable<void> symmetrical_test() | |
214 | { | |
215 | auto g = symmetrical_test_impl(co_await boost::asio::this_coro::executor); | |
216 | ||
217 | BOOST_ASIO_CHECK(g.is_open()); | |
218 | ||
219 | BOOST_ASIO_CHECK(0 == (co_await g.async_resume(0, | |
220 | boost::asio::use_awaitable)).value_or(-1)); | |
221 | ||
222 | BOOST_ASIO_CHECK(1 == (co_await g.async_resume(1, | |
223 | boost::asio::use_awaitable)).value_or(-1)); | |
224 | ||
225 | BOOST_ASIO_CHECK(3 == (co_await g.async_resume(2, | |
226 | boost::asio::use_awaitable)).value_or(-1)); | |
227 | ||
228 | BOOST_ASIO_CHECK(6 == (co_await g.async_resume(3, | |
229 | boost::asio::use_awaitable)).value_or(-1)); | |
230 | ||
231 | BOOST_ASIO_CHECK(10 == (co_await g.async_resume(4, | |
232 | boost::asio::use_awaitable)).value_or(-1)); | |
233 | ||
234 | BOOST_ASIO_CHECK(15 == (co_await g.async_resume(5, | |
235 | boost::asio::use_awaitable)).value_or(-1)); | |
236 | ||
237 | BOOST_ASIO_CHECK(21 == (co_await g.async_resume(6, | |
238 | boost::asio::use_awaitable)).value_or(-1)); | |
239 | ||
240 | BOOST_ASIO_CHECK(28 == (co_await g.async_resume(7, | |
241 | boost::asio::use_awaitable)).value_or(-1)); | |
242 | ||
243 | BOOST_ASIO_CHECK(36 == (co_await g.async_resume(8, | |
244 | boost::asio::use_awaitable)).value_or(-1)); | |
245 | ||
246 | BOOST_ASIO_CHECK(45 == (co_await g.async_resume(9, | |
247 | boost::asio::use_awaitable)).value_or(-1)); | |
248 | }; | |
249 | ||
250 | void run_symmetrical_test() | |
251 | { | |
252 | boost::asio::io_context ctx; | |
253 | boost::asio::co_spawn(ctx, symmetrical_test, boost::asio::detached); | |
254 | ctx.run(); | |
255 | } | |
256 | ||
257 | } // namespace coro | |
258 | ||
259 | BOOST_ASIO_TEST_SUITE | |
260 | ( | |
261 | "coro/simple_test", | |
262 | BOOST_ASIO_TEST_CASE(::coro::run_generator_test) | |
263 | BOOST_ASIO_TEST_CASE(::coro::run_task_test) | |
264 | BOOST_ASIO_TEST_CASE(::coro::run_symmetrical_test) | |
265 | BOOST_ASIO_TEST_CASE(::coro::run_completion_generator_test) | |
266 | ) |