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
16int gi = 7;
17
18struct my_exception : public std::runtime_error {
19 my_exception() :
20 std::runtime_error("my_exception") {
21 }
22};
23
24struct 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
36void fn1( boost::fibers::promise< int > * p, int i) {
37 boost::this_fiber::yield();
38 p->set_value( i);
39}
40
41void 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::dispatch, fn1, & p, 7).detach();
46 boost::this_fiber::yield();
47 BOOST_CHECK( 7 == f.get() );
48}
49
50int fn3() {
51 return 3;
52}
53
54void fn4() {
55}
56
57int fn5() {
58 boost::throw_exception( e: my_exception() );
59 return 3;
60}
61
62void fn6() {
63 boost::throw_exception( e: my_exception() );
64}
65
66int & fn7() {
67 return gi;
68}
69
70int fn8( int i) {
71 return i;
72}
73
74A fn9() {
75 A a;
76 a.value = 3;
77 return a;
78}
79
80A fn10() {
81 boost::throw_exception( e: my_exception() );
82 return A();
83}
84
85// promise
86void 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
95void 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
104void 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
113void 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
123void 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
133void 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
143void 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( other&: p2);
151}
152
153void 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( other&: p2);
161}
162
163void 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( other&: p2);
171}
172
173void 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
202void 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
231void 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
260void 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
280void 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
303void 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
325void 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
345void 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( ex: my_exception() ) );
350
351 // set exception a second time
352 bool thrown = false;
353 try {
354 p1.set_exception( std::make_exception_ptr( ex: 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
369void 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( ex: my_exception() ) );
374
375 // set exception a second time
376 bool thrown = false;
377 try {
378 p1.set_exception( std::make_exception_ptr( ex: 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
395void 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( ex: my_exception() ) );
400
401 // set exception a second time
402 bool thrown = false;
403 try {
404 p1.set_exception( std::make_exception_ptr( ex: 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
420boost::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

source code of boost/libs/fiber/test/test_promise_dispatch.cpp