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/race.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
20
21static cobalt::promise<std::chrono::milliseconds::rep> dummy(
22 asio::any_io_executor exec,
23 std::chrono::milliseconds ms = std::chrono::milliseconds(50))
24{
25 asio::steady_timer tim{exec, ms};
26 co_await tim.async_wait(token: cobalt::use_op);
27 co_return ms.count();
28}
29
30static cobalt::generator<int> gen(asio::any_io_executor exec)
31{
32 asio::steady_timer tim{exec, std::chrono::milliseconds(50000)};
33 co_await tim.async_wait(token: cobalt::use_op);
34 co_return 123;
35}
36
37BOOST_AUTO_TEST_SUITE(left_race_);
38#if !defined(BOOST_COBALT_NO_SELF_DELETE)
39
40CO_TEST_CASE(variadic)
41{
42 auto exec = co_await asio::this_coro::executor;
43 auto d1 = dummy(exec, ms: std::chrono::milliseconds(100));
44 auto d2 = dummy(exec, ms: std::chrono::milliseconds( 50));
45 auto g = gen(exec);
46 auto c = co_await left_race(p&: d1, p&: d2, p: dummy(exec, ms: std::chrono::milliseconds(100000)), p&: g);
47 BOOST_CHECK(c.index() == 1u);
48 BOOST_CHECK(boost::variant2::get<1>(c) == 50);
49 BOOST_CHECK(d1);
50 BOOST_CHECK(!d1.ready());
51 BOOST_CHECK( d2.ready());
52 BOOST_CHECK(100 == co_await d1);
53 BOOST_CHECK(!d1);
54 BOOST_CHECK( d1.ready());
55 co_await d2;
56
57 g.cancel();
58 BOOST_CHECK_THROW(co_await g, boost::system::system_error);
59}
60#endif
61
62CO_TEST_CASE(list)
63{
64 auto exec = co_await asio::this_coro::executor;
65 std::vector<cobalt::promise<std::chrono::milliseconds::rep>> vec;
66 vec.push_back(x: dummy(exec, ms: std::chrono::milliseconds(100)));
67 vec.push_back(x: dummy(exec, ms: std::chrono::milliseconds( 50)));
68 vec.push_back(x: dummy(exec, ms: std::chrono::milliseconds(100000)));
69
70 auto c = co_await left_race(p&: vec);
71 BOOST_CHECK(c.first == 1u);
72 BOOST_CHECK(c.second == 50);
73 BOOST_CHECK(!vec[0].ready());
74 BOOST_CHECK( vec[1].ready());
75 BOOST_CHECK(co_await vec[0]);
76 BOOST_CHECK( vec[0].ready());
77 BOOST_CHECK( vec[1].ready());
78 vec[2].cancel();
79 BOOST_CHECK( vec[2]);
80 BOOST_CHECK_THROW(co_await vec[2], boost::system::system_error);
81 BOOST_CHECK_THROW(co_await vec[2], boost::system::system_error);
82 BOOST_CHECK(!vec[2]);
83}
84
85CO_TEST_CASE(empty_list)
86{
87 auto exec = co_await asio::this_coro::executor;
88 std::vector<cobalt::promise<std::size_t>> vec;
89 try {
90 BOOST_CHECK_THROW(co_await left_race(vec), boost::system::system_error);
91 }
92 catch(...) {}
93}
94
95
96CO_TEST_CASE(stop_)
97{
98 auto d = dummy(exec: co_await asio::this_coro::executor,
99 ms: std::chrono::milliseconds(10));
100 BOOST_CHECK((co_await left_race(d, stop())).index() == 0);
101}
102
103CO_TEST_CASE(compliance)
104{
105 auto exec = co_await asio::this_coro::executor;
106 auto d = dummy(exec, ms: std::chrono::milliseconds(100000));
107
108 {
109 immediate i;
110 BOOST_CHECK((co_await left_race(d, i)).index() == 1);
111 }
112
113 {
114 immediate_bool i;
115 BOOST_CHECK((co_await left_race(d, i)).index() == 1);
116 }
117
118 {
119 immediate_handle i;
120 BOOST_CHECK((co_await left_race(d, i)).index() == 1);
121 }
122
123 {
124 posted p;
125 BOOST_CHECK((co_await left_race(d, p)).index() == 1);
126 }
127
128 {
129 posted_bool p;
130 BOOST_CHECK((co_await left_race(d, p)).index() == 1);
131 }
132
133 {
134 posted_handle p;
135 BOOST_CHECK((co_await left_race(d, p)).index() == 1);
136 }
137 d.cancel();
138 BOOST_CHECK_THROW(co_await d, boost::system::system_error);
139}
140CO_TEST_CASE(immediate_timer)
141{
142 immediate i;
143 asio::steady_timer tim{co_await cobalt::this_coro::executor, std::chrono::steady_clock::time_point::max()};
144 BOOST_CHECK((co_await left_race(tim.async_wait(cobalt::use_op), i)) == 1);
145
146}
147
148CO_TEST_CASE(compliance_ranged)
149{
150 BOOST_CHECK(co_await cobalt::left_race(std::vector<immediate>(3u)) == 0);
151 BOOST_CHECK(co_await cobalt::left_race(std::vector<immediate_bool>(1u)) == 0);
152 BOOST_CHECK(co_await cobalt::left_race(std::vector<immediate_handle>(1u)) == 0);
153 BOOST_CHECK(co_await cobalt::left_race(std::vector<posted>(3u)) == 0);
154 BOOST_CHECK(co_await cobalt::left_race(std::vector<posted_bool>(1u)) == 0);
155 BOOST_CHECK(co_await cobalt::left_race(std::vector<posted_handle>(1u)) == 0);
156}
157
158BOOST_AUTO_TEST_SUITE_END();
159

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