1 // (C) Copyright 2008-10 Anthony Williams
2 //
3 // Distributed under the Boost Software License, Version 1.0. (See
4 // accompanying file LICENSE_1_0.txt or copy at
5 // http://www.boost.org/LICENSE_1_0.txt)
6
7 #include <utility>
8 #include <memory>
9 #include <stdexcept>
10 #include <string>
11
12 #include <boost/test/unit_test.hpp>
13
14 #include <boost/fiber/all.hpp>
15
16 int gi = 7;
17
18 struct my_exception : public std::runtime_error {
my_exceptionmy_exception19 my_exception() :
20 std::runtime_error("my_exception") {
21 }
22 };
23
24 struct A {
25 A() = default;
26
27 A( A const&) = delete;
28 A( A &&) = default;
29
30 A & operator=( A const&) = delete;
31 A & operator=( A &&) = default;
32
33 int value{ 0 };
34 };
35
fn1(boost::fibers::promise<int> * p,int i)36 void fn1( boost::fibers::promise< int > * p, int i) {
37 boost::this_fiber::yield();
38 p->set_value( i);
39 }
40
fn2()41 void fn2() {
42 boost::fibers::promise< int > p;
43 boost::fibers::future< int > f( p.get_future() );
44 boost::this_fiber::yield();
45 boost::fibers::fiber( boost::fibers::launch::post, fn1, & p, 7).detach();
46 boost::this_fiber::yield();
47 BOOST_CHECK( 7 == f.get() );
48 }
49
fn3()50 int fn3() {
51 return 3;
52 }
53
fn4()54 void fn4() {
55 }
56
fn5()57 int fn5() {
58 boost::throw_exception( my_exception() );
59 return 3;
60 }
61
fn6()62 void fn6() {
63 boost::throw_exception( my_exception() );
64 }
65
fn7()66 int & fn7() {
67 return gi;
68 }
69
fn8(int i)70 int fn8( int i) {
71 return i;
72 }
73
fn9()74 A fn9() {
75 A a;
76 a.value = 3;
77 return a;
78 }
79
fn10()80 A fn10() {
81 boost::throw_exception( my_exception() );
82 return A();
83 }
84
85 // promise
test_promise_create()86 void test_promise_create() {
87 // use std::allocator<> as default
88 boost::fibers::promise< int > p1;
89
90 // use std::allocator<> as user defined
91 std::allocator< boost::fibers::promise< int > > alloc;
92 boost::fibers::promise< int > p2( std::allocator_arg, alloc);
93 }
94
test_promise_create_ref()95 void test_promise_create_ref() {
96 // use std::allocator<> as default
97 boost::fibers::promise< int& > p1;
98
99 // use std::allocator<> as user defined
100 std::allocator< boost::fibers::promise< int& > > alloc;
101 boost::fibers::promise< int& > p2( std::allocator_arg, alloc);
102 }
103
test_promise_create_void()104 void test_promise_create_void() {
105 // use std::allocator<> as default
106 boost::fibers::promise< void > p1;
107
108 // use std::allocator<> as user defined
109 std::allocator< boost::fibers::promise< void > > alloc;
110 boost::fibers::promise< void > p2( std::allocator_arg, alloc);
111 }
112
test_promise_move()113 void test_promise_move() {
114 boost::fibers::promise< int > p1;
115
116 // move construction
117 boost::fibers::promise< int > p2( std::move( p1) );
118
119 // move assigment
120 p1 = std::move( p2);
121 }
122
test_promise_move_ref()123 void test_promise_move_ref() {
124 boost::fibers::promise< int& > p1;
125
126 // move construction
127 boost::fibers::promise< int& > p2( std::move( p1) );
128
129 // move assigment
130 p1 = std::move( p2);
131 }
132
test_promise_move_void()133 void test_promise_move_void() {
134 boost::fibers::promise< void > p1;
135
136 // move construction
137 boost::fibers::promise< void > p2( std::move( p1) );
138
139 // move assigment
140 p1 = std::move( p2);
141 }
142
test_promise_swap()143 void test_promise_swap() {
144 boost::fibers::promise< int > p1;
145
146 // move construction
147 boost::fibers::promise< int > p2( std::move( p1) );
148
149 // swap
150 p1.swap( p2);
151 }
152
test_promise_swap_ref()153 void test_promise_swap_ref() {
154 boost::fibers::promise< int& > p1;
155
156 // move construction
157 boost::fibers::promise< int& > p2( std::move( p1) );
158
159 // swap
160 p1.swap( p2);
161 }
162
test_promise_swap_void()163 void test_promise_swap_void() {
164 boost::fibers::promise< void > p1;
165
166 // move construction
167 boost::fibers::promise< void > p2( std::move( p1) );
168
169 // swap
170 p1.swap( p2);
171 }
172
test_promise_get_future()173 void test_promise_get_future() {
174 boost::fibers::promise< int > p1;
175
176 // retrieve future
177 boost::fibers::future< int > f1 = p1.get_future();
178 BOOST_CHECK( f1.valid() );
179
180 // retrieve future a second time
181 bool thrown = false;
182 try {
183 f1 = p1.get_future();
184 } catch ( boost::fibers::future_already_retrieved const&) {
185 thrown = true;
186 }
187 BOOST_CHECK( thrown);
188
189 // move construction
190 boost::fibers::promise< int > p2( std::move( p1) );
191
192 // retrieve future from uninitialized
193 thrown = false;
194 try {
195 f1 = p1.get_future();
196 } catch ( boost::fibers::promise_uninitialized const&) {
197 thrown = true;
198 }
199 BOOST_CHECK( thrown);
200 }
201
test_promise_get_future_ref()202 void test_promise_get_future_ref() {
203 boost::fibers::promise< int& > p1;
204
205 // retrieve future
206 boost::fibers::future< int& > f1 = p1.get_future();
207 BOOST_CHECK( f1.valid() );
208
209 // retrieve future a second time
210 bool thrown = false;
211 try {
212 f1 = p1.get_future();
213 } catch ( boost::fibers::future_already_retrieved const&) {
214 thrown = true;
215 }
216 BOOST_CHECK( thrown);
217
218 // move construction
219 boost::fibers::promise< int& > p2( std::move( p1) );
220
221 // retrieve future from uninitialized
222 thrown = false;
223 try {
224 f1 = p1.get_future();
225 } catch ( boost::fibers::promise_uninitialized const&) {
226 thrown = true;
227 }
228 BOOST_CHECK( thrown);
229 }
230
test_promise_get_future_void()231 void test_promise_get_future_void() {
232 boost::fibers::promise< void > p1;
233
234 // retrieve future
235 boost::fibers::future< void > f1 = p1.get_future();
236 BOOST_CHECK( f1.valid() );
237
238 // retrieve future a second time
239 bool thrown = false;
240 try {
241 f1 = p1.get_future();
242 } catch ( boost::fibers::future_already_retrieved const&) {
243 thrown = true;
244 }
245 BOOST_CHECK( thrown);
246
247 // move construction
248 boost::fibers::promise< void > p2( std::move( p1) );
249
250 // retrieve future from uninitialized
251 thrown = false;
252 try {
253 f1 = p1.get_future();
254 } catch ( boost::fibers::promise_uninitialized const&) {
255 thrown = true;
256 }
257 BOOST_CHECK( thrown);
258 }
259
test_promise_set_value()260 void test_promise_set_value() {
261 // promise takes a copyable as return type
262 boost::fibers::promise< int > p1;
263 boost::fibers::future< int > f1 = p1.get_future();
264 BOOST_CHECK( f1.valid() );
265
266 // copy value
267 p1.set_value( 7);
268 BOOST_CHECK( 7 == f1.get() );
269
270 // set value a second time
271 bool thrown = false;
272 try {
273 p1.set_value( 11);
274 } catch ( boost::fibers::promise_already_satisfied const&) {
275 thrown = true;
276 }
277 BOOST_CHECK( thrown);
278 }
279
test_promise_set_value_move()280 void test_promise_set_value_move() {
281 // promise takes a copyable as return type
282 boost::fibers::promise< A > p1;
283 boost::fibers::future< A > f1 = p1.get_future();
284 BOOST_CHECK( f1.valid() );
285
286 // move value
287 A a1; a1.value = 7;
288 p1.set_value( std::move( a1) );
289 A a2 = f1.get();
290 BOOST_CHECK( 7 == a2.value);
291
292 // set value a second time
293 bool thrown = false;
294 try {
295 A a;
296 p1.set_value( std::move( a) );
297 } catch ( boost::fibers::promise_already_satisfied const&) {
298 thrown = true;
299 }
300 BOOST_CHECK( thrown);
301 }
302
test_promise_set_value_ref()303 void test_promise_set_value_ref() {
304 // promise takes a reference as return type
305 boost::fibers::promise< int& > p1;
306 boost::fibers::future< int& > f1 = p1.get_future();
307 BOOST_CHECK( f1.valid() );
308
309 // copy value
310 int i = 7;
311 p1.set_value( i);
312 int & j = f1.get();
313 BOOST_CHECK( &i == &j);
314
315 // set value a second time
316 bool thrown = false;
317 try {
318 p1.set_value( i);
319 } catch ( boost::fibers::promise_already_satisfied const&) {
320 thrown = true;
321 }
322 BOOST_CHECK( thrown);
323 }
324
test_promise_set_value_void()325 void test_promise_set_value_void() {
326 // promise takes a copyable as return type
327 boost::fibers::promise< void > p1;
328 boost::fibers::future< void > f1 = p1.get_future();
329 BOOST_CHECK( f1.valid() );
330
331 // set void
332 p1.set_value();
333 f1.get();
334
335 // set value a second time
336 bool thrown = false;
337 try {
338 p1.set_value();
339 } catch ( boost::fibers::promise_already_satisfied const&) {
340 thrown = true;
341 }
342 BOOST_CHECK( thrown);
343 }
344
test_promise_set_exception()345 void test_promise_set_exception() {
346 boost::fibers::promise< int > p1;
347 boost::fibers::future< int > f1 = p1.get_future();
348 BOOST_CHECK( f1.valid() );
349 p1.set_exception( std::make_exception_ptr( my_exception() ) );
350
351 // set exception a second time
352 bool thrown = false;
353 try {
354 p1.set_exception( std::make_exception_ptr( my_exception() ) );
355 } catch ( boost::fibers::promise_already_satisfied const&) {
356 thrown = true;
357 }
358 BOOST_CHECK( thrown);
359
360 // set value
361 thrown = false;
362 try
363 { p1.set_value( 11); }
364 catch ( boost::fibers::promise_already_satisfied const&)
365 { thrown = true; }
366 BOOST_CHECK( thrown);
367 }
368
test_promise_set_exception_ref()369 void test_promise_set_exception_ref() {
370 boost::fibers::promise< int& > p1;
371 boost::fibers::future< int& > f1 = p1.get_future();
372 BOOST_CHECK( f1.valid() );
373 p1.set_exception( std::make_exception_ptr( my_exception() ) );
374
375 // set exception a second time
376 bool thrown = false;
377 try {
378 p1.set_exception( std::make_exception_ptr( my_exception() ) );
379 } catch ( boost::fibers::promise_already_satisfied const&) {
380 thrown = true;
381 }
382 BOOST_CHECK( thrown);
383
384 // set value
385 thrown = false;
386 int i = 11;
387 try {
388 p1.set_value( i);
389 } catch ( boost::fibers::promise_already_satisfied const&) {
390 thrown = true;
391 }
392 BOOST_CHECK( thrown);
393 }
394
test_promise_set_exception_void()395 void test_promise_set_exception_void() {
396 boost::fibers::promise< void > p1;
397 boost::fibers::future< void > f1 = p1.get_future();
398 BOOST_CHECK( f1.valid() );
399 p1.set_exception( std::make_exception_ptr( my_exception() ) );
400
401 // set exception a second time
402 bool thrown = false;
403 try {
404 p1.set_exception( std::make_exception_ptr( my_exception() ) );
405 } catch ( boost::fibers::promise_already_satisfied const&) {
406 thrown = true;
407 }
408 BOOST_CHECK( thrown);
409
410 // set value
411 thrown = false;
412 try {
413 p1.set_value();
414 } catch ( boost::fibers::promise_already_satisfied const&) {
415 thrown = true;
416 }
417 BOOST_CHECK( thrown);
418 }
419
init_unit_test_suite(int,char * [])420 boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) {
421 boost::unit_test_framework::test_suite* test =
422 BOOST_TEST_SUITE("Boost.Fiber: promise test suite");
423
424 test->add(BOOST_TEST_CASE(test_promise_create));
425 test->add(BOOST_TEST_CASE(test_promise_create_ref));
426 test->add(BOOST_TEST_CASE(test_promise_create_void));
427 test->add(BOOST_TEST_CASE(test_promise_move));
428 test->add(BOOST_TEST_CASE(test_promise_move_ref));
429 test->add(BOOST_TEST_CASE(test_promise_move_void));
430 test->add(BOOST_TEST_CASE(test_promise_swap));
431 test->add(BOOST_TEST_CASE(test_promise_swap_ref));
432 test->add(BOOST_TEST_CASE(test_promise_swap_void));
433 test->add(BOOST_TEST_CASE(test_promise_get_future));
434 test->add(BOOST_TEST_CASE(test_promise_get_future_ref));
435 test->add(BOOST_TEST_CASE(test_promise_get_future_void));
436 test->add(BOOST_TEST_CASE(test_promise_set_value));
437 test->add(BOOST_TEST_CASE(test_promise_set_value_move));
438 test->add(BOOST_TEST_CASE(test_promise_set_value_ref));
439 test->add(BOOST_TEST_CASE(test_promise_set_value_void));
440 test->add(BOOST_TEST_CASE(test_promise_set_exception));
441 test->add(BOOST_TEST_CASE(test_promise_set_exception_ref));
442 test->add(BOOST_TEST_CASE(test_promise_set_exception_void));
443
444 return test;
445 }
446