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
30
31static cobalt::promise<std::chrono::milliseconds::rep> nothrow_dummy(
32 asio::any_io_executor exec,
33 std::chrono::milliseconds ms = std::chrono::milliseconds(50))
34try {
35 asio::steady_timer tim{exec, ms};
36 co_await tim.async_wait(token: cobalt::use_op);
37 co_return ms.count();
38}
39catch(...)
40{
41 co_return std::numeric_limits<std::chrono::milliseconds::rep>::max();
42}
43
44static cobalt::generator<int> gen(asio::any_io_executor exec)
45{
46 asio::steady_timer tim{exec, std::chrono::milliseconds(50000)};
47 co_await tim.async_wait(token: cobalt::use_op);
48 co_return 123;
49}
50
51BOOST_AUTO_TEST_SUITE(race_);
52
53CO_TEST_CASE(variadic)
54{
55 auto exec = co_await asio::this_coro::executor;
56 auto d1 = dummy(exec, ms: std::chrono::milliseconds(100));
57 auto d2 = dummy(exec, ms: std::chrono::milliseconds( 50));
58 auto g = gen(exec);
59 std::mt19937 src{1u};
60 auto c = co_await race(g&: src, p&: d1, p&: d2, p: dummy(exec, ms: std::chrono::milliseconds(100000)), p&: g);
61 BOOST_CHECK(c.index() == 1u);
62 BOOST_CHECK(boost::variant2::get<1>(c) == 50);
63 BOOST_CHECK(d1);
64 //BOOST_CHECK(!d1.ready()); NOTE: Inderministic on msvc, due to the additional post!
65 BOOST_CHECK( d2.ready());
66 BOOST_CHECK(100 == co_await d1);
67 BOOST_CHECK(!d1);
68 BOOST_CHECK( d1.ready());
69 co_await d2;
70
71 g.cancel();
72 try { BOOST_CHECK_THROW(co_await g, boost::system::system_error); }
73 catch (boost::system::system_error &) {}
74}
75
76
77cobalt::promise<void> list_step(std::default_random_engine::result_type seed)
78{
79 std::mt19937 src{seed};
80
81 auto exec = co_await asio::this_coro::executor;
82 std::vector<cobalt::promise<std::chrono::milliseconds::rep>> vec;
83 vec.push_back(x: dummy(exec, ms: std::chrono::milliseconds(100)));
84 vec.push_back(x: dummy(exec, ms: std::chrono::milliseconds( 50)));
85 vec.push_back(x: dummy(exec, ms: std::chrono::milliseconds(100000)));
86
87 auto c = co_await race(g&: src, p&: vec);
88 BOOST_CHECK(c.first == 1u);
89 BOOST_CHECK(c.second == 50);
90 BOOST_CHECK(!vec[0].ready());
91 BOOST_CHECK( vec[1].ready());
92 BOOST_CHECK(co_await vec[0]);
93 BOOST_CHECK( vec[0].ready());
94 BOOST_CHECK( vec[1].ready());
95 vec[2].cancel();
96 BOOST_CHECK( vec[2]);
97 BOOST_CHECK_THROW(co_await vec[2], boost::system::system_error);
98 BOOST_CHECK_THROW(co_await vec[2], boost::system::system_error);
99 BOOST_CHECK(!vec[2]);
100}
101
102CO_TEST_CASE(list_1u) { co_await list_step(seed: 1u);}
103CO_TEST_CASE(list_2u) { co_await list_step(seed: 2u);}
104CO_TEST_CASE(list_3u) { co_await list_step(seed: 3u);}
105CO_TEST_CASE(list_4u) { co_await list_step(seed: 4u);}
106CO_TEST_CASE(list_5u) { co_await list_step(seed: 5u);}
107CO_TEST_CASE(list_6u) { co_await list_step(seed: 6u);}
108CO_TEST_CASE(list_7u) { co_await list_step(seed: 7u);}
109CO_TEST_CASE(list_8u) { co_await list_step(seed: 8u);}
110CO_TEST_CASE(list_9u) { co_await list_step(seed: 9u);}
111
112CO_TEST_CASE(empty_list)
113{
114 auto exec = co_await asio::this_coro::executor;
115 std::vector<cobalt::promise<std::size_t>> vec;
116 try
117 {
118 BOOST_CHECK_THROW(co_await race(vec), boost::system::system_error);
119 }
120 catch(...) {}
121}
122
123
124CO_TEST_CASE(stop_)
125{
126 auto d = nothrow_dummy(exec: co_await asio::this_coro::executor,
127 ms: std::chrono::milliseconds(10));
128 BOOST_CHECK((co_await left_race(d, stop())).index() == 0);
129}
130
131CO_TEST_CASE(compliance)
132{
133 auto exec = co_await asio::this_coro::executor;
134 auto d = dummy(exec, ms: std::chrono::milliseconds(100000));
135 {
136 immediate i;
137 BOOST_CHECK((co_await race(d, i)).index() == 1);
138 }
139
140 {
141 immediate_bool i;
142 BOOST_CHECK((co_await race(d, i)).index() == 1);
143 }
144
145 {
146 immediate_handle i;
147 BOOST_CHECK((co_await race(d, i)).index() == 1);
148 }
149 {
150 posted p;
151 BOOST_CHECK((co_await race(d, p)).index() == 1);
152 }
153 {
154 posted_bool p;
155 BOOST_CHECK((co_await race(d, p)).index() == 1);
156 }
157 {
158 posted_handle p;
159 BOOST_CHECK((co_await race(d, p)).index() == 1);
160 }
161 d.cancel();
162 BOOST_CHECK_THROW(co_await d, boost::system::system_error);
163}
164
165
166BOOST_AUTO_TEST_SUITE_END();
167

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