• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
my_exceptionmy_exception24     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 
fn1(boost::fibers::promise<int> * p,int i)41 void fn1( boost::fibers::promise< int > * p, int i) {
42     boost::this_fiber::yield();
43     p->set_value( i);
44 }
45 
fn2()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 
fn3()55 int fn3() {
56     return 3;
57 }
58 
fn4()59 void fn4() {
60 }
61 
fn5()62 int fn5() {
63     boost::throw_exception( my_exception() );
64     return 3;
65 }
66 
fn6()67 void fn6() {
68     boost::throw_exception( my_exception() );
69 }
70 
fn7()71 int & fn7() {
72     return gi;
73 }
74 
fn8(int i)75 int fn8( int i) {
76     return i;
77 }
78 
fn9()79 A fn9() {
80      A a;
81      a.value = 3;
82      return a;
83 }
84 
fn10()85 A fn10() {
86     boost::throw_exception( my_exception() );
87     return A();
88 }
89 
fn11(boost::fibers::promise<int> p)90 void fn11( boost::fibers::promise< int > p) {
91   boost::this_fiber::sleep_for( ms(500) );
92   p.set_value(3);
93 }
94 
fn12(boost::fibers::promise<int &> p)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 
fn13(boost::fibers::promise<void> p)101 void fn13( boost::fibers::promise< void > p) {
102   boost::this_fiber::sleep_for( ms(400) );
103   p.set_value();
104 }
105 
106 // future
test_future_create()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 
test_future_create_ref()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 
test_future_create_void()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 
test_future_move()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 
test_future_move_ref()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 
test_future_move_void()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 
test_future_get()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 
test_future_get_move()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 
test_future_get_ref()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 
test_future_get_void()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 
test_future_share()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 
test_future_share_ref()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 
test_future_share_void()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 
test_future_wait()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 
test_future_wait_ref()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 
test_future_wait_void()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 
test_future_wait_for()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() );
417     status = f1.wait_for( ms(400) );
418     BOOST_CHECK( boost::fibers::future_status::ready == status);
419 
420     BOOST_CHECK( f1.valid() );
421     f1.wait();
422 }
423 
test_future_wait_for_ref()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() );
437     status = f1.wait_for( ms(400) );
438     BOOST_CHECK( boost::fibers::future_status::ready == status);
439 
440     BOOST_CHECK( f1.valid() );
441     f1.wait();
442 }
443 
test_future_wait_for_void()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() );
457     status = f1.wait_for( ms(400) );
458     BOOST_CHECK( boost::fibers::future_status::ready == status);
459 
460     BOOST_CHECK( f1.valid() );
461     f1.wait();
462 }
463 
test_future_wait_until()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() );
477     status = f1.wait_until( Clock::now() + ms(400) );
478     BOOST_CHECK( boost::fibers::future_status::ready == status);
479 
480     BOOST_CHECK( f1.valid() );
481     f1.wait();
482 }
483 
test_future_wait_until_ref()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() );
497     status = f1.wait_until( Clock::now() + ms(400) );
498     BOOST_CHECK( boost::fibers::future_status::ready == status);
499 
500     BOOST_CHECK( f1.valid() );
501     f1.wait();
502 }
503 
test_future_wait_until_void()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() );
517     status = f1.wait_until( Clock::now() + ms(400) );
518     BOOST_CHECK( boost::fibers::future_status::ready == status);
519 
520     BOOST_CHECK( f1.valid() );
521     f1.wait();
522 }
523 
test_future_wait_with_fiber_1()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 
test_future_wait_with_fiber_2()534 void test_future_wait_with_fiber_2() {
535     boost::fibers::fiber( boost::fibers::launch::dispatch, fn2).join();
536 }
537 
538 
init_unit_test_suite(int,char * [])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 }
570