]>
Commit | Line | Data |
---|---|---|
1e59de90 | 1 | // Copyright 2018-2022 Emil Dotchevski and Reverge Studios, Inc. |
20effc67 TL |
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 | ||
1e59de90 TL |
6 | #include <boost/leaf/config.hpp> |
7 | ||
8 | #if defined(BOOST_LEAF_NO_EXCEPTIONS) || defined(BOOST_LEAF_NO_THREADS) || !BOOST_LEAF_CFG_CAPTURE | |
20effc67 TL |
9 | |
10 | #include <iostream> | |
11 | ||
12 | int main() | |
13 | { | |
14 | std::cout << "Unit test not applicable." << std::endl; | |
15 | return 0; | |
16 | } | |
17 | ||
18 | #else | |
19 | ||
1e59de90 TL |
20 | #ifdef BOOST_LEAF_TEST_SINGLE_HEADER |
21 | # include "leaf.hpp" | |
22 | #else | |
23 | # include <boost/leaf/capture.hpp> | |
24 | # include <boost/leaf/handle_errors.hpp> | |
25 | # include <boost/leaf/exception.hpp> | |
26 | # include <boost/leaf/on_error.hpp> | |
27 | #endif | |
28 | ||
20effc67 TL |
29 | #include "lightweight_test.hpp" |
30 | #include <vector> | |
31 | #include <future> | |
32 | #include <iterator> | |
33 | #include <algorithm> | |
34 | ||
35 | namespace leaf = boost::leaf; | |
36 | ||
37 | template <int> struct info { int value; }; | |
38 | ||
39 | struct fut_info | |
40 | { | |
41 | int a; | |
42 | int b; | |
43 | int result; | |
44 | std::future<int> fut; | |
45 | }; | |
46 | ||
47 | template <class H, class F> | |
48 | std::vector<fut_info> launch_tasks( int task_count, F f ) | |
49 | { | |
50 | BOOST_LEAF_ASSERT(task_count>0); | |
51 | std::vector<fut_info> fut; | |
52 | std::generate_n( std::back_inserter(fut), task_count, | |
53 | [=] | |
54 | { | |
55 | int const a = rand(); | |
56 | int const b = rand(); | |
57 | int const res = (rand()%10) - 5; | |
58 | return fut_info { a, b, res, std::async( std::launch::async, | |
59 | [=] | |
60 | { | |
61 | return leaf::capture(leaf::make_shared_context<H>(), f, a, b, res); | |
62 | } ) }; | |
63 | } ); | |
64 | return fut; | |
65 | } | |
66 | ||
67 | int main() | |
68 | { | |
69 | int received_a, received_b; | |
70 | auto error_handlers = std::make_tuple( | |
71 | [&received_a, &received_b]( info<1> const & x1, info<2> const & x2, info<4> const & ) | |
72 | { | |
73 | received_a = x1.value; | |
74 | received_b = x2.value; | |
75 | return -1; | |
76 | }, | |
77 | [] | |
78 | { | |
79 | return -2; | |
80 | } ); | |
81 | ||
82 | { | |
83 | std::vector<fut_info> fut = launch_tasks<decltype(error_handlers)>( | |
84 | 100, | |
85 | []( int a, int b, int res ) | |
86 | { | |
87 | if( res >= 0 ) | |
88 | return res; | |
89 | else | |
90 | throw leaf::exception(info<1>{a}, info<2>{b}, info<3>{}); | |
91 | } ); | |
92 | ||
93 | for( auto & f : fut ) | |
94 | { | |
95 | f.fut.wait(); | |
96 | received_a = received_b = 0; | |
97 | int r = leaf::try_catch( | |
98 | [&] | |
99 | { | |
100 | auto load = leaf::on_error( info<4>{} ); | |
101 | ||
102 | // Calling future_get is required in order to make the on_error (above) work. | |
103 | return leaf::future_get(f.fut); | |
104 | }, | |
105 | error_handlers ); | |
106 | if( f.result>=0 ) | |
107 | BOOST_TEST_EQ(r, f.result); | |
108 | else | |
109 | { | |
110 | BOOST_TEST_EQ(r, -1); | |
111 | BOOST_TEST_EQ(received_a, f.a); | |
112 | BOOST_TEST_EQ(received_b, f.b); | |
113 | } | |
114 | } | |
115 | } | |
116 | ||
117 | { | |
118 | std::vector<fut_info> fut = launch_tasks<decltype(error_handlers)>( | |
119 | 100, | |
120 | []( int a, int b, int res ) | |
121 | { | |
122 | if( res >= 0 ) | |
123 | return res; | |
124 | else | |
125 | throw leaf::exception(info<1>{a}, info<2>{b}, info<3>{}); | |
126 | } ); | |
127 | ||
128 | for( auto & f : fut ) | |
129 | { | |
130 | f.fut.wait(); | |
131 | received_a = received_b = 0; | |
132 | int r = leaf::try_catch( | |
133 | [&] | |
134 | { | |
135 | auto load = leaf::on_error( info<4>{} ); | |
136 | ||
137 | return leaf::try_catch( | |
138 | [&] | |
139 | { | |
140 | // Not calling future_get, a on_error in this scope won't work correctly. | |
141 | // This is to verify that the on_error in the outer scope (above) works. | |
142 | return f.fut.get(); | |
143 | }, | |
144 | []() -> int | |
145 | { | |
146 | throw; | |
147 | } ); | |
148 | }, | |
149 | error_handlers ); | |
150 | if( f.result>=0 ) | |
151 | BOOST_TEST_EQ(r, f.result); | |
152 | else | |
153 | { | |
154 | BOOST_TEST_EQ(r, -1); | |
155 | BOOST_TEST_EQ(received_a, f.a); | |
156 | BOOST_TEST_EQ(received_b, f.b); | |
157 | } | |
158 | } | |
159 | } | |
160 | ||
161 | return boost::report_errors(); | |
162 | } | |
163 | ||
164 | #endif |