]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // (C) Copyright 2008-10 Anthony Williams |
2 | // 2015 Oliver Kowalke | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0. (See | |
5 | // accompanying file LICENSE_1_0.txt or copy at | |
6 | // http://www.boost.org/LICENSE_1_0.txt) | |
7 | ||
8 | #include <chrono> | |
9 | #include <memory> | |
10 | #include <stdexcept> | |
11 | #include <string> | |
12 | #include <utility> | |
13 | ||
14 | #include <boost/test/unit_test.hpp> | |
15 | ||
16 | #include <boost/fiber/all.hpp> | |
17 | ||
18 | typedef std::chrono::milliseconds ms; | |
19 | typedef std::chrono::high_resolution_clock Clock; | |
20 | ||
21 | int gi = 7; | |
22 | ||
23 | struct my_exception : public std::runtime_error { | |
24 | my_exception() : | |
25 | std::runtime_error("my_exception") { | |
26 | } | |
27 | }; | |
28 | ||
29 | struct A { | |
30 | A() = default; | |
31 | ||
32 | A( A const&) = delete; | |
33 | A( A &&) = default; | |
34 | ||
35 | A & operator=( A const&) = delete; | |
36 | A & operator=( A &&) = default; | |
37 | ||
38 | int value; | |
39 | }; | |
40 | ||
41 | void fn1( boost::fibers::promise< int > * p, int i) { | |
42 | boost::this_fiber::yield(); | |
43 | p->set_value( i); | |
44 | } | |
45 | ||
46 | void fn2() { | |
47 | boost::fibers::promise< int > p; | |
48 | boost::fibers::future< int > f( p.get_future() ); | |
49 | boost::this_fiber::yield(); | |
50 | boost::fibers::fiber( boost::fibers::launch::dispatch, fn1, & p, 7).detach(); | |
51 | boost::this_fiber::yield(); | |
52 | BOOST_CHECK( 7 == f.get() ); | |
53 | } | |
54 | ||
55 | int fn3() { | |
56 | return 3; | |
57 | } | |
58 | ||
59 | void fn4() { | |
60 | } | |
61 | ||
62 | int fn5() { | |
63 | boost::throw_exception( my_exception() ); | |
64 | return 3; | |
65 | } | |
66 | ||
67 | void fn6() { | |
68 | boost::throw_exception( my_exception() ); | |
69 | } | |
70 | ||
71 | int & fn7() { | |
72 | return gi; | |
73 | } | |
74 | ||
75 | int fn8( int i) { | |
76 | return i; | |
77 | } | |
78 | ||
79 | A fn9() { | |
80 | A a; | |
81 | a.value = 3; | |
b32b8144 | 82 | return a; |
7c673cae FG |
83 | } |
84 | ||
85 | A fn10() { | |
86 | boost::throw_exception( my_exception() ); | |
87 | return A(); | |
88 | } | |
89 | ||
90 | void fn11( boost::fibers::promise< int > p) { | |
91 | boost::this_fiber::sleep_for( ms(500) ); | |
92 | p.set_value(3); | |
93 | } | |
94 | ||
95 | void fn12( boost::fibers::promise< int& > p) { | |
96 | boost::this_fiber::sleep_for( ms(500) ); | |
97 | gi = 5; | |
98 | p.set_value( gi); | |
99 | } | |
100 | ||
101 | void fn13( boost::fibers::promise< void > p) { | |
b32b8144 | 102 | boost::this_fiber::sleep_for( ms(400) ); |
7c673cae FG |
103 | p.set_value(); |
104 | } | |
105 | ||
106 | // future | |
107 | void test_future_create() { | |
108 | // default constructed future is not valid | |
109 | boost::fibers::future< int > f1; | |
110 | BOOST_CHECK( ! f1.valid() ); | |
111 | ||
112 | // future retrieved from promise is valid (if it is the first) | |
113 | boost::fibers::promise< int > p2; | |
114 | boost::fibers::future< int > f2 = p2.get_future(); | |
115 | BOOST_CHECK( f2.valid() ); | |
116 | } | |
117 | ||
118 | void test_future_create_ref() { | |
119 | // default constructed future is not valid | |
120 | boost::fibers::future< int& > f1; | |
121 | BOOST_CHECK( ! f1.valid() ); | |
122 | ||
123 | // future retrieved from promise is valid (if it is the first) | |
124 | boost::fibers::promise< int& > p2; | |
125 | boost::fibers::future< int& > f2 = p2.get_future(); | |
126 | BOOST_CHECK( f2.valid() ); | |
127 | } | |
128 | ||
129 | void test_future_create_void() { | |
130 | // default constructed future is not valid | |
131 | boost::fibers::future< void > f1; | |
132 | BOOST_CHECK( ! f1.valid() ); | |
133 | ||
134 | // future retrieved from promise is valid (if it is the first) | |
135 | boost::fibers::promise< void > p2; | |
136 | boost::fibers::future< void > f2 = p2.get_future(); | |
137 | BOOST_CHECK( f2.valid() ); | |
138 | } | |
139 | ||
140 | void test_future_move() { | |
141 | // future retrieved from promise is valid (if it is the first) | |
142 | boost::fibers::promise< int > p1; | |
143 | boost::fibers::future< int > f1 = p1.get_future(); | |
144 | BOOST_CHECK( f1.valid() ); | |
145 | ||
146 | // move construction | |
147 | boost::fibers::future< int > f2( std::move( f1) ); | |
148 | BOOST_CHECK( ! f1.valid() ); | |
149 | BOOST_CHECK( f2.valid() ); | |
150 | ||
151 | // move assignment | |
152 | f1 = std::move( f2); | |
153 | BOOST_CHECK( f1.valid() ); | |
154 | BOOST_CHECK( ! f2.valid() ); | |
155 | } | |
156 | ||
157 | void test_future_move_ref() { | |
158 | // future retrieved from promise is valid (if it is the first) | |
159 | boost::fibers::promise< int& > p1; | |
160 | boost::fibers::future< int& > f1 = p1.get_future(); | |
161 | BOOST_CHECK( f1.valid() ); | |
162 | ||
163 | // move construction | |
164 | boost::fibers::future< int& > f2( std::move( f1) ); | |
165 | BOOST_CHECK( ! f1.valid() ); | |
166 | BOOST_CHECK( f2.valid() ); | |
167 | ||
168 | // move assignment | |
169 | f1 = std::move( f2); | |
170 | BOOST_CHECK( f1.valid() ); | |
171 | BOOST_CHECK( ! f2.valid() ); | |
172 | } | |
173 | ||
174 | void test_future_move_void() { | |
175 | // future retrieved from promise is valid (if it is the first) | |
176 | boost::fibers::promise< void > p1; | |
177 | boost::fibers::future< void > f1 = p1.get_future(); | |
178 | BOOST_CHECK( f1.valid() ); | |
179 | ||
180 | // move construction | |
181 | boost::fibers::future< void > f2( std::move( f1) ); | |
182 | BOOST_CHECK( ! f1.valid() ); | |
183 | BOOST_CHECK( f2.valid() ); | |
184 | ||
185 | // move assignment | |
186 | f1 = std::move( f2); | |
187 | BOOST_CHECK( f1.valid() ); | |
188 | BOOST_CHECK( ! f2.valid() ); | |
189 | } | |
190 | ||
191 | void test_future_get() { | |
192 | // future retrieved from promise is valid (if it is the first) | |
193 | boost::fibers::promise< int > p1; | |
194 | p1.set_value( 7); | |
195 | ||
196 | boost::fibers::future< int > f1 = p1.get_future(); | |
197 | BOOST_CHECK( f1.valid() ); | |
198 | ||
199 | // get | |
200 | BOOST_CHECK( ! f1.get_exception_ptr() ); | |
201 | BOOST_CHECK( 7 == f1.get() ); | |
202 | BOOST_CHECK( ! f1.valid() ); | |
203 | ||
204 | // throw broken_promise if promise is destroyed without set | |
205 | { | |
206 | boost::fibers::promise< int > p2; | |
207 | f1 = p2.get_future(); | |
208 | } | |
209 | bool thrown = false; | |
210 | try { | |
211 | f1.get(); | |
212 | } catch ( boost::fibers::broken_promise const&) { | |
213 | thrown = true; | |
214 | } | |
215 | BOOST_CHECK( ! f1.valid() ); | |
216 | BOOST_CHECK( thrown); | |
217 | } | |
218 | ||
219 | void test_future_get_move() { | |
220 | // future retrieved from promise is valid (if it is the first) | |
221 | boost::fibers::promise< A > p1; | |
222 | A a; a.value = 7; | |
223 | p1.set_value( std::move( a) ); | |
224 | ||
225 | boost::fibers::future< A > f1 = p1.get_future(); | |
226 | BOOST_CHECK( f1.valid() ); | |
227 | ||
228 | // get | |
229 | BOOST_CHECK( ! f1.get_exception_ptr() ); | |
230 | BOOST_CHECK( 7 == f1.get().value); | |
231 | BOOST_CHECK( ! f1.valid() ); | |
232 | ||
233 | // throw broken_promise if promise is destroyed without set | |
234 | { | |
235 | boost::fibers::promise< A > p2; | |
236 | f1 = p2.get_future(); | |
237 | } | |
238 | bool thrown = false; | |
239 | try { | |
240 | f1.get(); | |
241 | } catch ( boost::fibers::broken_promise const&) { | |
242 | thrown = true; | |
243 | } | |
244 | BOOST_CHECK( ! f1.valid() ); | |
245 | BOOST_CHECK( thrown); | |
246 | } | |
247 | ||
248 | void test_future_get_ref() { | |
249 | // future retrieved from promise is valid (if it is the first) | |
250 | boost::fibers::promise< int& > p1; | |
251 | int i = 7; | |
252 | p1.set_value( i); | |
253 | ||
254 | boost::fibers::future< int& > f1 = p1.get_future(); | |
255 | BOOST_CHECK( f1.valid() ); | |
256 | ||
257 | // get | |
258 | BOOST_CHECK( ! f1.get_exception_ptr() ); | |
259 | int & j = f1.get(); | |
260 | BOOST_CHECK( &i == &j); | |
261 | BOOST_CHECK( ! f1.valid() ); | |
262 | ||
263 | // throw broken_promise if promise is destroyed without set | |
264 | { | |
265 | boost::fibers::promise< int& > p2; | |
266 | f1 = p2.get_future(); | |
267 | } | |
268 | bool thrown = false; | |
269 | try { | |
270 | f1.get(); | |
271 | } catch ( boost::fibers::broken_promise const&) { | |
272 | thrown = true; | |
273 | } | |
274 | BOOST_CHECK( ! f1.valid() ); | |
275 | BOOST_CHECK( thrown); | |
276 | } | |
277 | ||
278 | ||
279 | void test_future_get_void() { | |
280 | // future retrieved from promise is valid (if it is the first) | |
281 | boost::fibers::promise< void > p1; | |
282 | p1.set_value(); | |
283 | ||
284 | boost::fibers::future< void > f1 = p1.get_future(); | |
285 | BOOST_CHECK( f1.valid() ); | |
286 | ||
287 | // get | |
288 | BOOST_CHECK( ! f1.get_exception_ptr() ); | |
289 | f1.get(); | |
290 | BOOST_CHECK( ! f1.valid() ); | |
291 | ||
292 | // throw broken_promise if promise is destroyed without set | |
293 | { | |
294 | boost::fibers::promise< void > p2; | |
295 | f1 = p2.get_future(); | |
296 | } | |
297 | bool thrown = false; | |
298 | try { | |
299 | f1.get(); | |
300 | } catch ( boost::fibers::broken_promise const&) { | |
301 | thrown = true; | |
302 | } | |
303 | BOOST_CHECK( ! f1.valid() ); | |
304 | BOOST_CHECK( thrown); | |
305 | } | |
306 | ||
307 | void test_future_share() { | |
308 | // future retrieved from promise is valid (if it is the first) | |
309 | boost::fibers::promise< int > p1; | |
310 | int i = 7; | |
311 | p1.set_value( i); | |
312 | ||
313 | boost::fibers::future< int > f1 = p1.get_future(); | |
314 | BOOST_CHECK( f1.valid() ); | |
315 | ||
316 | // share | |
317 | boost::fibers::shared_future< int > sf1 = f1.share(); | |
318 | BOOST_CHECK( sf1.valid() ); | |
319 | BOOST_CHECK( ! f1.valid() ); | |
320 | ||
321 | // get | |
322 | BOOST_CHECK( ! sf1.get_exception_ptr() ); | |
323 | int j = sf1.get(); | |
324 | BOOST_CHECK_EQUAL( i, j); | |
325 | BOOST_CHECK( sf1.valid() ); | |
326 | } | |
327 | ||
328 | void test_future_share_ref() { | |
329 | // future retrieved from promise is valid (if it is the first) | |
330 | boost::fibers::promise< int& > p1; | |
331 | int i = 7; | |
332 | p1.set_value( i); | |
333 | ||
334 | boost::fibers::future< int& > f1 = p1.get_future(); | |
335 | BOOST_CHECK( f1.valid() ); | |
336 | ||
337 | // share | |
338 | boost::fibers::shared_future< int& > sf1 = f1.share(); | |
339 | BOOST_CHECK( sf1.valid() ); | |
340 | BOOST_CHECK( ! f1.valid() ); | |
341 | ||
342 | // get | |
343 | BOOST_CHECK( ! sf1.get_exception_ptr() ); | |
344 | int & j = sf1.get(); | |
345 | BOOST_CHECK( &i == &j); | |
346 | BOOST_CHECK( sf1.valid() ); | |
347 | } | |
348 | ||
349 | void test_future_share_void() { | |
350 | // future retrieved from promise is valid (if it is the first) | |
351 | boost::fibers::promise< void > p1; | |
352 | p1.set_value(); | |
353 | ||
354 | boost::fibers::future< void > f1 = p1.get_future(); | |
355 | BOOST_CHECK( f1.valid() ); | |
356 | ||
357 | // share | |
358 | boost::fibers::shared_future< void > sf1 = f1.share(); | |
359 | BOOST_CHECK( sf1.valid() ); | |
360 | BOOST_CHECK( ! f1.valid() ); | |
361 | ||
362 | // get | |
363 | BOOST_CHECK( ! sf1.get_exception_ptr() ); | |
364 | sf1.get(); | |
365 | BOOST_CHECK( sf1.valid() ); | |
366 | } | |
367 | ||
368 | void test_future_wait() { | |
369 | // future retrieved from promise is valid (if it is the first) | |
370 | boost::fibers::promise< int > p1; | |
371 | boost::fibers::future< int > f1 = p1.get_future(); | |
372 | ||
373 | // wait on future | |
374 | p1.set_value( 7); | |
375 | f1.wait(); | |
376 | BOOST_CHECK( 7 == f1.get() ); | |
377 | } | |
378 | ||
379 | void test_future_wait_ref() { | |
380 | // future retrieved from promise is valid (if it is the first) | |
381 | boost::fibers::promise< int& > p1; | |
382 | boost::fibers::future< int& > f1 = p1.get_future(); | |
383 | ||
384 | // wait on future | |
385 | int i = 7; | |
386 | p1.set_value( i); | |
387 | f1.wait(); | |
388 | int & j = f1.get(); | |
389 | BOOST_CHECK( &i == &j); | |
390 | } | |
391 | ||
392 | void test_future_wait_void() { | |
393 | // future retrieved from promise is valid (if it is the first) | |
394 | boost::fibers::promise< void > p1; | |
395 | boost::fibers::future< void > f1 = p1.get_future(); | |
396 | ||
397 | // wait on future | |
398 | p1.set_value(); | |
399 | f1.wait(); | |
400 | f1.get(); | |
401 | BOOST_CHECK( ! f1.valid() ); | |
402 | } | |
403 | ||
404 | void test_future_wait_for() { | |
405 | // future retrieved from promise is valid (if it is the first) | |
406 | boost::fibers::promise< int > p1; | |
407 | boost::fibers::future< int > f1 = p1.get_future(); | |
408 | ||
409 | boost::fibers::fiber( boost::fibers::launch::dispatch, fn11, std::move( p1) ).detach(); | |
410 | ||
411 | // wait on future | |
412 | BOOST_CHECK( f1.valid() ); | |
413 | boost::fibers::future_status status = f1.wait_for( ms(300) ); | |
414 | BOOST_CHECK( boost::fibers::future_status::timeout == status); | |
415 | ||
416 | BOOST_CHECK( f1.valid() ); | |
b32b8144 | 417 | status = f1.wait_for( ms(400) ); |
7c673cae FG |
418 | BOOST_CHECK( boost::fibers::future_status::ready == status); |
419 | ||
420 | BOOST_CHECK( f1.valid() ); | |
421 | f1.wait(); | |
422 | } | |
423 | ||
424 | void test_future_wait_for_ref() { | |
425 | // future retrieved from promise is valid (if it is the first) | |
426 | boost::fibers::promise< int& > p1; | |
427 | boost::fibers::future< int& > f1 = p1.get_future(); | |
428 | ||
429 | boost::fibers::fiber( boost::fibers::launch::dispatch, fn12, std::move( p1) ).detach(); | |
430 | ||
431 | // wait on future | |
432 | BOOST_CHECK( f1.valid() ); | |
433 | boost::fibers::future_status status = f1.wait_for( ms(300) ); | |
434 | BOOST_CHECK( boost::fibers::future_status::timeout == status); | |
435 | ||
436 | BOOST_CHECK( f1.valid() ); | |
b32b8144 | 437 | status = f1.wait_for( ms(400) ); |
7c673cae FG |
438 | BOOST_CHECK( boost::fibers::future_status::ready == status); |
439 | ||
440 | BOOST_CHECK( f1.valid() ); | |
441 | f1.wait(); | |
442 | } | |
443 | ||
444 | void test_future_wait_for_void() { | |
445 | // future retrieved from promise is valid (if it is the first) | |
446 | boost::fibers::promise< void > p1; | |
447 | boost::fibers::future< void > f1 = p1.get_future(); | |
448 | ||
449 | boost::fibers::fiber( boost::fibers::launch::dispatch, fn13, std::move( p1) ).detach(); | |
450 | ||
451 | // wait on future | |
452 | BOOST_CHECK( f1.valid() ); | |
453 | boost::fibers::future_status status = f1.wait_for( ms(300) ); | |
454 | BOOST_CHECK( boost::fibers::future_status::timeout == status); | |
455 | ||
456 | BOOST_CHECK( f1.valid() ); | |
b32b8144 | 457 | status = f1.wait_for( ms(400) ); |
7c673cae FG |
458 | BOOST_CHECK( boost::fibers::future_status::ready == status); |
459 | ||
460 | BOOST_CHECK( f1.valid() ); | |
461 | f1.wait(); | |
462 | } | |
463 | ||
464 | void test_future_wait_until() { | |
465 | // future retrieved from promise is valid (if it is the first) | |
466 | boost::fibers::promise< int > p1; | |
467 | boost::fibers::future< int > f1 = p1.get_future(); | |
468 | ||
469 | boost::fibers::fiber( boost::fibers::launch::dispatch, fn11, std::move( p1) ).detach(); | |
470 | ||
471 | // wait on future | |
472 | BOOST_CHECK( f1.valid() ); | |
473 | boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); | |
474 | BOOST_CHECK( boost::fibers::future_status::timeout == status); | |
475 | ||
476 | BOOST_CHECK( f1.valid() ); | |
b32b8144 | 477 | status = f1.wait_until( Clock::now() + ms(400) ); |
7c673cae FG |
478 | BOOST_CHECK( boost::fibers::future_status::ready == status); |
479 | ||
480 | BOOST_CHECK( f1.valid() ); | |
481 | f1.wait(); | |
482 | } | |
483 | ||
484 | void test_future_wait_until_ref() { | |
485 | // future retrieved from promise is valid (if it is the first) | |
486 | boost::fibers::promise< int& > p1; | |
487 | boost::fibers::future< int& > f1 = p1.get_future(); | |
488 | ||
489 | boost::fibers::fiber( boost::fibers::launch::dispatch, fn12, std::move( p1) ).detach(); | |
490 | ||
491 | // wait on future | |
492 | BOOST_CHECK( f1.valid() ); | |
493 | boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); | |
494 | BOOST_CHECK( boost::fibers::future_status::timeout == status); | |
495 | ||
496 | BOOST_CHECK( f1.valid() ); | |
b32b8144 | 497 | status = f1.wait_until( Clock::now() + ms(400) ); |
7c673cae FG |
498 | BOOST_CHECK( boost::fibers::future_status::ready == status); |
499 | ||
500 | BOOST_CHECK( f1.valid() ); | |
501 | f1.wait(); | |
502 | } | |
503 | ||
504 | void test_future_wait_until_void() { | |
505 | // future retrieved from promise is valid (if it is the first) | |
506 | boost::fibers::promise< void > p1; | |
507 | boost::fibers::future< void > f1 = p1.get_future(); | |
508 | ||
509 | boost::fibers::fiber( boost::fibers::launch::dispatch, fn13, std::move( p1) ).detach(); | |
510 | ||
511 | // wait on future | |
512 | BOOST_CHECK( f1.valid() ); | |
513 | boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); | |
514 | BOOST_CHECK( boost::fibers::future_status::timeout == status); | |
515 | ||
516 | BOOST_CHECK( f1.valid() ); | |
b32b8144 | 517 | status = f1.wait_until( Clock::now() + ms(400) ); |
7c673cae FG |
518 | BOOST_CHECK( boost::fibers::future_status::ready == status); |
519 | ||
520 | BOOST_CHECK( f1.valid() ); | |
521 | f1.wait(); | |
522 | } | |
523 | ||
524 | void test_future_wait_with_fiber_1() { | |
525 | boost::fibers::promise< int > p1; | |
526 | boost::fibers::fiber( boost::fibers::launch::dispatch, fn1, & p1, 7).detach(); | |
527 | ||
528 | boost::fibers::future< int > f1 = p1.get_future(); | |
529 | ||
530 | // wait on future | |
531 | BOOST_CHECK( 7 == f1.get() ); | |
532 | } | |
533 | ||
534 | void test_future_wait_with_fiber_2() { | |
535 | boost::fibers::fiber( boost::fibers::launch::dispatch, fn2).join(); | |
536 | } | |
537 | ||
538 | ||
539 | boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { | |
540 | boost::unit_test_framework::test_suite* test = | |
541 | BOOST_TEST_SUITE("Boost.Fiber: future test suite"); | |
542 | ||
543 | test->add(BOOST_TEST_CASE(test_future_create)); | |
544 | test->add(BOOST_TEST_CASE(test_future_create_ref)); | |
545 | test->add(BOOST_TEST_CASE(test_future_create_void)); | |
546 | test->add(BOOST_TEST_CASE(test_future_move)); | |
547 | test->add(BOOST_TEST_CASE(test_future_move_ref)); | |
548 | test->add(BOOST_TEST_CASE(test_future_move_void)); | |
549 | test->add(BOOST_TEST_CASE(test_future_get)); | |
550 | test->add(BOOST_TEST_CASE(test_future_get_move)); | |
551 | test->add(BOOST_TEST_CASE(test_future_get_ref)); | |
552 | test->add(BOOST_TEST_CASE(test_future_get_void)); | |
553 | test->add(BOOST_TEST_CASE(test_future_share)); | |
554 | test->add(BOOST_TEST_CASE(test_future_share_ref)); | |
555 | test->add(BOOST_TEST_CASE(test_future_share_void)); | |
556 | test->add(BOOST_TEST_CASE(test_future_wait)); | |
557 | test->add(BOOST_TEST_CASE(test_future_wait_ref)); | |
558 | test->add(BOOST_TEST_CASE(test_future_wait_void)); | |
559 | test->add(BOOST_TEST_CASE(test_future_wait_for)); | |
560 | test->add(BOOST_TEST_CASE(test_future_wait_for_ref)); | |
561 | test->add(BOOST_TEST_CASE(test_future_wait_for_void)); | |
562 | test->add(BOOST_TEST_CASE(test_future_wait_until)); | |
563 | test->add(BOOST_TEST_CASE(test_future_wait_until_ref)); | |
564 | test->add(BOOST_TEST_CASE(test_future_wait_until_void)); | |
565 | test->add(BOOST_TEST_CASE(test_future_wait_with_fiber_1)); | |
566 | test->add(BOOST_TEST_CASE(test_future_wait_with_fiber_2)); | |
567 | ||
568 | return test; | |
569 | } |