1// Copyright (c) 2022 Klemens D. Morgenstern
2//
3// Distributed under the Boost Software License, Version 1.0. (See accompanying
4// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
5
6#include <boost/cobalt/detail/handler.hpp>
7
8#include <boost/test/unit_test.hpp>
9#include "test.hpp"
10#include <boost/asio/any_io_executor.hpp>
11#include <boost/asio/post.hpp>
12
13using namespace boost;
14
15struct dummy_promise
16{
17 using executor_type = boost::asio::any_io_executor;
18 executor_type get_executor() const;
19
20};
21
22static_assert(boost::asio::detail::has_executor_type<dummy_promise>::value);
23
24
25void test(boost::cobalt::completion_handler<> ch)
26{
27 boost::asio::post(token: std::move(ch));
28}
29
30BOOST_AUTO_TEST_SUITE(handler);
31
32struct immediate_aw
33{
34 bool await_ready() {return false;}
35
36 std::optional<std::tuple<>> result;
37 cobalt::detail::completed_immediately_t completed_immediately;
38
39 template<typename T>
40 bool await_suspend(std::coroutine_handle<T> h)
41 {
42 cobalt::completion_handler<> ch{h, result,
43#if !defined(BOOST_COBALT_NO_PMR)
44 cobalt::this_thread::get_default_resource(),
45#endif
46 &completed_immediately};
47
48 auto exec = asio::get_associated_immediate_executor(ch, h.promise().get_executor());
49 completed_immediately = cobalt::detail::completed_immediately_t::initiating;
50 asio::dispatch(exec, std::move(ch));
51
52 BOOST_CHECK(result);
53 BOOST_CHECK(completed_immediately == cobalt::detail::completed_immediately_t::yes);
54
55 return completed_immediately != cobalt::detail::completed_immediately_t::yes;
56 }
57
58 void await_resume()
59 {
60 BOOST_CHECK(completed_immediately != cobalt::detail::completed_immediately_t::no);
61 BOOST_CHECK(result);
62 }
63};
64
65#if !defined(BOOST_COBALT_USE_IO_CONTEXT)
66
67struct non_immediate_aw
68{
69 bool await_ready() {return false;}
70
71 std::optional<std::tuple<>> result;
72 cobalt::detail::completed_immediately_t completed_immediately;
73 cobalt::detail::sbo_resource res;
74
75 template<typename T>
76 bool await_suspend(std::coroutine_handle<T> h)
77 {
78 cobalt::completion_handler<> ch{h, result, &res, &completed_immediately};
79
80 auto exec = asio::get_associated_immediate_executor(ch, h.promise().get_executor());
81 asio::dispatch(exec,
82 asio::deferred(
83 [exec = h.promise().get_executor()]()
84 {
85 return asio::post(exec, asio::deferred);
86 }))(std::move(ch));
87
88 BOOST_CHECK(!result);
89 BOOST_CHECK(completed_immediately != cobalt::detail::completed_immediately_t::yes);
90
91 return completed_immediately != cobalt::detail::completed_immediately_t::yes;
92 }
93
94 void await_resume()
95 {
96 BOOST_CHECK(completed_immediately != cobalt::detail::completed_immediately_t::yes);
97 BOOST_CHECK(result);
98 }
99};
100
101
102
103
104CO_TEST_CASE(immediate_completion)
105{
106 co_await immediate_aw{};
107 co_await non_immediate_aw{};
108}
109
110#endif
111
112BOOST_AUTO_TEST_CASE(immediate_executor_initiating)
113{
114 asio::io_context ctx;
115 cobalt::detail::completed_immediately_t completed_immediately = cobalt::detail::completed_immediately_t::initiating;
116 cobalt::detail::completion_handler_noop_executor chh{ctx.get_executor(), &completed_immediately};
117 bool called = false;
118
119 asio::dispatch(ex: chh, token: [&] { called = true; });
120 BOOST_CHECK(called);
121 BOOST_CHECK(completed_immediately == cobalt::detail::completed_immediately_t::initiating);
122}
123
124BOOST_AUTO_TEST_CASE(immediate_executor_maybe)
125{
126 asio::io_context ctx;
127 cobalt::detail::completed_immediately_t completed_immediately = cobalt::detail::completed_immediately_t::initiating;
128 cobalt::detail::completion_handler_noop_executor chh{ctx.get_executor(), &completed_immediately};
129 bool called = false;
130
131 completed_immediately = cobalt::detail::completed_immediately_t::maybe;
132 asio::dispatch(ex: chh, token: [&] { called = true; completed_immediately = cobalt::detail::completed_immediately_t::yes; });
133 BOOST_CHECK(called);
134 BOOST_CHECK(completed_immediately == cobalt::detail::completed_immediately_t::yes);
135}
136
137
138BOOST_AUTO_TEST_CASE(immediate_executor_maybe_not)
139{
140 asio::io_context ctx;
141 cobalt::detail::completed_immediately_t completed_immediately = cobalt::detail::completed_immediately_t::initiating;
142 cobalt::detail::completion_handler_noop_executor chh{ctx.get_executor(), &completed_immediately};
143 bool called = false;
144
145 completed_immediately = cobalt::detail::completed_immediately_t::maybe;
146 asio::dispatch(ex: chh, token: [&] { called = true; });
147 BOOST_CHECK(called);
148 BOOST_CHECK(completed_immediately == cobalt::detail::completed_immediately_t::initiating);
149}
150
151BOOST_AUTO_TEST_CASE(immediate_executor_no)
152{
153 asio::io_context ctx;
154 cobalt::detail::completed_immediately_t completed_immediately = cobalt::detail::completed_immediately_t::initiating;
155 cobalt::detail::completion_handler_noop_executor chh{ctx.get_executor(), &completed_immediately};
156 bool called = false;
157
158 completed_immediately = cobalt::detail::completed_immediately_t::no;
159 asio::dispatch(ex: chh, token: [&] { called = true; });
160 BOOST_CHECK(!called);
161 BOOST_CHECK(completed_immediately == cobalt::detail::completed_immediately_t::no);
162 BOOST_CHECK(ctx.run() == 1u);
163 BOOST_CHECK(called);
164}
165
166BOOST_AUTO_TEST_SUITE_END();
167

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