• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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;
34 };
35 
36 struct B {
37     bool    bset{ false };
38 
39     B() = default;
40 
BB41     B( bool set) :
42         bset{ set } {
43         gi = 3;
44     }
45 
~BB46     ~B() {
47         if ( bset) {
48             gi = -1;
49         }
50     }
51 
BB52     B( B && other) :
53         bset{ other.bset } {
54         other.bset = false;
55     }
56 
operator =B57     B & operator=( B && other) {
58         if ( this == & other) return * this;
59         bset = other.bset;
60         other.bset = false;
61         return * this;
62     }
63 
64     B( B const&) = delete;
65     B & operator=( B const&) = delete;
66 };
67 
fn1(boost::fibers::promise<int> * p,int i)68 void fn1( boost::fibers::promise< int > * p, int i) {
69     boost::this_fiber::yield();
70     p->set_value( i);
71 }
72 
fn2()73 void fn2() {
74     boost::fibers::promise< int > p;
75     boost::fibers::future< int > f( p.get_future() );
76     boost::this_fiber::yield();
77     boost::fibers::fiber( boost::fibers::launch::dispatch, fn1, & p, 7).detach();
78     boost::this_fiber::yield();
79     BOOST_CHECK( 7 == f.get() );
80 }
81 
fn3()82 int fn3() {
83     return 3;
84 }
85 
fn4()86 void fn4() {
87 }
88 
fn5()89 int fn5() {
90     boost::throw_exception( my_exception() );
91     return 3;
92 }
93 
fn6()94 void fn6() {
95     boost::throw_exception( my_exception() );
96 }
97 
fn7()98 int & fn7() {
99     return gi;
100 }
101 
fn8(int i)102 int fn8( int i) {
103     return i;
104 }
105 
fn9()106 A fn9() {
107      A a;
108      a.value = 3;
109      return a;
110 }
111 
fn10()112 A fn10() {
113     boost::throw_exception( my_exception() );
114     return A();
115 }
116 
fn11(bool set)117 B fn11( bool set) {
118      B b( set);
119      return b;
120 }
121 
122 // packaged_task
test_packaged_task_create()123 void test_packaged_task_create() {
124     // default constructed packaged_task is not valid
125     boost::fibers::packaged_task< int() > t1;
126     BOOST_CHECK( ! t1.valid() );
127 
128     // packaged_task from function
129     boost::fibers::packaged_task< int() > t2( fn3);
130     BOOST_CHECK( t2.valid() );
131 }
132 
133 // packaged_task
test_packaged_task_create_move()134 void test_packaged_task_create_move() {
135     // default constructed packaged_task is not valid
136     boost::fibers::packaged_task< A() > t1;
137     BOOST_CHECK( ! t1.valid() );
138 
139     // packaged_task from function
140     boost::fibers::packaged_task< A() > t2( fn9);
141     BOOST_CHECK( t2.valid() );
142 }
143 
test_packaged_task_create_void()144 void test_packaged_task_create_void() {
145     // default constructed packaged_task is not valid
146     boost::fibers::packaged_task< void() > t1;
147     BOOST_CHECK( ! t1.valid() );
148 
149     // packaged_task from function
150     boost::fibers::packaged_task< void() > t2( fn4);
151     BOOST_CHECK( t2.valid() );
152 }
153 
test_packaged_task_move()154 void test_packaged_task_move() {
155     boost::fibers::packaged_task< int() > t1( fn3);
156     BOOST_CHECK( t1.valid() );
157 
158     // move construction
159     boost::fibers::packaged_task< int() > t2( std::move( t1) );
160     BOOST_CHECK( ! t1.valid() );
161     BOOST_CHECK( t2.valid() );
162 
163     // move assignment
164     t1 = std::move( t2);
165     BOOST_CHECK( t1.valid() );
166     BOOST_CHECK( ! t2.valid() );
167 }
168 
test_packaged_task_move_move()169 void test_packaged_task_move_move() {
170     boost::fibers::packaged_task< A() > t1( fn9);
171     BOOST_CHECK( t1.valid() );
172 
173     // move construction
174     boost::fibers::packaged_task< A() > t2( std::move( t1) );
175     BOOST_CHECK( ! t1.valid() );
176     BOOST_CHECK( t2.valid() );
177 
178     // move assignment
179     t1 = std::move( t2);
180     BOOST_CHECK( t1.valid() );
181     BOOST_CHECK( ! t2.valid() );
182 }
183 
test_packaged_task_move_void()184 void test_packaged_task_move_void() {
185     boost::fibers::packaged_task< void() > t1( fn4);
186     BOOST_CHECK( t1.valid() );
187 
188     // move construction
189     boost::fibers::packaged_task< void() > t2( std::move( t1) );
190     BOOST_CHECK( ! t1.valid() );
191     BOOST_CHECK( t2.valid() );
192 
193     // move assignment
194     t1 = std::move( t2);
195     BOOST_CHECK( t1.valid() );
196     BOOST_CHECK( ! t2.valid() );
197 }
198 
test_packaged_task_swap()199 void test_packaged_task_swap() {
200     boost::fibers::packaged_task< int() > t1( fn3);
201     BOOST_CHECK( t1.valid() );
202 
203     boost::fibers::packaged_task< int() > t2;
204     BOOST_CHECK( ! t2.valid() );
205 
206     // swap
207     t1.swap( t2);
208     BOOST_CHECK( ! t1.valid() );
209     BOOST_CHECK( t2.valid() );
210 }
211 
test_packaged_task_swap_move()212 void test_packaged_task_swap_move() {
213     boost::fibers::packaged_task< A() > t1( fn9);
214     BOOST_CHECK( t1.valid() );
215 
216     boost::fibers::packaged_task< A() > t2;
217     BOOST_CHECK( ! t2.valid() );
218 
219     // swap
220     t1.swap( t2);
221     BOOST_CHECK( ! t1.valid() );
222     BOOST_CHECK( t2.valid() );
223 }
224 
test_packaged_task_swap_void()225 void test_packaged_task_swap_void() {
226     boost::fibers::packaged_task< void() > t1( fn4);
227     BOOST_CHECK( t1.valid() );
228 
229     boost::fibers::packaged_task< void() > t2;
230     BOOST_CHECK( ! t2.valid() );
231 
232     // swap
233     t1.swap( t2);
234     BOOST_CHECK( ! t1.valid() );
235     BOOST_CHECK( t2.valid() );
236 }
237 
test_packaged_task_reset()238 void test_packaged_task_reset() {
239     {
240         boost::fibers::packaged_task< int() > p( fn3);
241         boost::fibers::future< int > f( p.get_future() );
242         BOOST_CHECK( p.valid() );
243 
244         p();
245         BOOST_CHECK( 3 == f.get() );
246 
247         // reset
248         p.reset();
249         p();
250         f = p.get_future();
251         BOOST_CHECK( 3 == f.get() );
252     }
253     {
254         boost::fibers::packaged_task< int() > p;
255 
256         bool thrown = false;
257         try {
258             p.reset();
259         } catch ( boost::fibers::packaged_task_uninitialized const&) {
260             thrown = true;
261         }
262         BOOST_CHECK( thrown);
263     }
264 }
265 
test_packaged_task_reset_destruction()266 void test_packaged_task_reset_destruction() {
267         gi = 0;
268         boost::fibers::packaged_task< B( bool) > p( fn11);
269         BOOST_CHECK( p.valid() );
270 
271         BOOST_CHECK( 0 == gi);
272         p( true);
273         BOOST_CHECK( 3 == gi);
274 
275         // reset
276         p.reset();
277         BOOST_CHECK( -1 == gi);
278         p( false);
279         BOOST_CHECK( 3 == gi);
280 
281         // reset
282         p.reset();
283         BOOST_CHECK( 3 == gi);
284 }
285 
test_packaged_task_reset_move()286 void test_packaged_task_reset_move() {
287     {
288         boost::fibers::packaged_task< A() > p( fn9);
289         boost::fibers::future< A > f( p.get_future() );
290         BOOST_CHECK( p.valid() );
291 
292         p();
293         BOOST_CHECK( 3 == f.get().value);
294 
295         // reset
296         p.reset();
297         p();
298         f = p.get_future();
299         BOOST_CHECK( 3 == f.get().value);
300     }
301     {
302         boost::fibers::packaged_task< A() > p;
303 
304         bool thrown = false;
305         try {
306             p.reset();
307         } catch ( boost::fibers::packaged_task_uninitialized const&) {
308             thrown = true;
309         }
310         BOOST_CHECK( thrown);
311     }
312 }
313 
test_packaged_task_reset_void()314 void test_packaged_task_reset_void() {
315     {
316         boost::fibers::packaged_task< void() > p( fn4);
317         boost::fibers::future< void > f( p.get_future() );
318         BOOST_CHECK( p.valid() );
319 
320         p();
321         f.get();
322 
323         // reset
324         p.reset();
325         p();
326         f = p.get_future();
327         f.get();
328     }
329     {
330         boost::fibers::packaged_task< void() > p;
331 
332         bool thrown = false;
333         try {
334             p.reset();
335         } catch ( boost::fibers::packaged_task_uninitialized const&) {
336             thrown = true;
337         }
338         BOOST_CHECK( thrown);
339     }
340 }
341 
test_packaged_task_get_future()342 void test_packaged_task_get_future() {
343     boost::fibers::packaged_task< int() > t1( fn3);
344     BOOST_CHECK( t1.valid() );
345 
346     // retrieve future
347     boost::fibers::future< int > f1 = t1.get_future();
348     BOOST_CHECK( f1.valid() );
349 
350     // retrieve future a second time
351     bool thrown = false;
352     try {
353         f1 = t1.get_future();
354     } catch ( boost::fibers::future_already_retrieved const&) {
355         thrown = true;
356     }
357     BOOST_CHECK( thrown);
358 
359     // move construction
360     boost::fibers::packaged_task< int() > t2( std::move( t1) );
361     BOOST_CHECK( ! t1.valid() );
362     BOOST_CHECK( t2.valid() );
363 
364     // retrieve future from uninitialized
365     thrown = false;
366     try {
367         f1 = t1.get_future();
368     } catch ( boost::fibers::packaged_task_uninitialized const&) {
369         thrown = true;
370     }
371     BOOST_CHECK( thrown);
372 }
373 
test_packaged_task_get_future_move()374 void test_packaged_task_get_future_move() {
375     boost::fibers::packaged_task< A() > t1( fn9);
376     BOOST_CHECK( t1.valid() );
377 
378     // retrieve future
379     boost::fibers::future< A > f1 = t1.get_future();
380     BOOST_CHECK( f1.valid() );
381 
382     // retrieve future a second time
383     bool thrown = false;
384     try {
385         f1 = t1.get_future();
386     } catch ( boost::fibers::future_already_retrieved const&) {
387         thrown = true;
388     }
389     BOOST_CHECK( thrown);
390 
391     // move construction
392     boost::fibers::packaged_task< A() > t2( std::move( t1) );
393     BOOST_CHECK( ! t1.valid() );
394     BOOST_CHECK( t2.valid() );
395 
396     // retrieve future from uninitialized
397     thrown = false;
398     try {
399         f1 = t1.get_future();
400     } catch ( boost::fibers::packaged_task_uninitialized const&) {
401         thrown = true;
402     }
403     BOOST_CHECK( thrown);
404 }
405 
test_packaged_task_get_future_void()406 void test_packaged_task_get_future_void() {
407     boost::fibers::packaged_task< void() > t1( fn4);
408     BOOST_CHECK( t1.valid() );
409 
410     // retrieve future
411     boost::fibers::future< void > f1 = t1.get_future();
412     BOOST_CHECK( f1.valid() );
413 
414     // retrieve future a second time
415     bool thrown = false;
416     try {
417         f1 = t1.get_future();
418     } catch ( boost::fibers::future_already_retrieved const&) {
419         thrown = true;
420     }
421     BOOST_CHECK( thrown);
422 
423     // move construction
424     boost::fibers::packaged_task< void() > t2( std::move( t1) );
425     BOOST_CHECK( ! t1.valid() );
426     BOOST_CHECK( t2.valid() );
427 
428     // retrieve future from uninitialized
429     thrown = false;
430     try {
431         f1 = t1.get_future();
432     } catch ( boost::fibers::packaged_task_uninitialized const&) {
433         thrown = true;
434     }
435     BOOST_CHECK( thrown);
436 }
437 
test_packaged_task_exec()438 void test_packaged_task_exec() {
439     // promise takes a copyable as return type
440     boost::fibers::packaged_task< int() > t1( fn3);
441     BOOST_CHECK( t1.valid() );
442     boost::fibers::future< int > f1 = t1.get_future();
443     BOOST_CHECK( f1.valid() );
444 
445     // exec
446     t1();
447     BOOST_CHECK( 3 == f1.get() );
448 
449     // exec a second time
450     bool thrown = false;
451     try {
452         t1();
453     } catch ( boost::fibers::promise_already_satisfied const&) {
454         thrown = true;
455     }
456     BOOST_CHECK( thrown);
457 }
458 
test_packaged_task_exec_move()459 void test_packaged_task_exec_move() {
460     // promise takes a copyable as return type
461     boost::fibers::packaged_task< A() > t1( fn9);
462     BOOST_CHECK( t1.valid() );
463     boost::fibers::future< A > f1 = t1.get_future();
464     BOOST_CHECK( f1.valid() );
465 
466     // exec
467     t1();
468     BOOST_CHECK( 3 == f1.get().value);
469 
470     // exec a second time
471     bool thrown = false;
472     try {
473         t1();
474     } catch ( boost::fibers::promise_already_satisfied const&) {
475         thrown = true;
476     }
477     BOOST_CHECK( thrown);
478 }
479 
test_packaged_task_exec_param()480 void test_packaged_task_exec_param() {
481     // promise takes a copyable as return type
482     boost::fibers::packaged_task< int( int) > t1( fn8);
483     BOOST_CHECK( t1.valid() );
484     boost::fibers::future< int > f1 = t1.get_future();
485     BOOST_CHECK( f1.valid() );
486 
487     // exec
488     t1( 3);
489     BOOST_CHECK( 3 == f1.get() );
490 
491     // exec a second time
492     bool thrown = false;
493     try {
494         t1( 7);
495     } catch ( boost::fibers::promise_already_satisfied const&) {
496         thrown = true;
497     }
498     BOOST_CHECK( thrown);
499 
500     //TODO: packaged_task returns a moveable-only as return type
501 }
502 
test_packaged_task_exec_ref()503 void test_packaged_task_exec_ref() {
504     // promise takes a copyable as return type
505     boost::fibers::packaged_task< int&() > t1( fn7);
506     BOOST_CHECK( t1.valid() );
507     boost::fibers::future< int& > f1 = t1.get_future();
508     BOOST_CHECK( f1.valid() );
509 
510     // exec
511     t1();
512     int & i = f1.get();
513     BOOST_CHECK( &gi == &i);
514 
515     // exec a second time
516     bool thrown = false;
517     try {
518         t1();
519     } catch ( boost::fibers::promise_already_satisfied const&) {
520         thrown = true;
521     }
522     BOOST_CHECK( thrown);
523 
524     //TODO: packaged_task returns a moveable-only as return type
525 }
526 
test_packaged_task_exec_void()527 void test_packaged_task_exec_void() {
528     // promise takes a copyable as return type
529     boost::fibers::packaged_task< void() > t1( fn4);
530     BOOST_CHECK( t1.valid() );
531     boost::fibers::future< void > f1 = t1.get_future();
532     BOOST_CHECK( f1.valid() );
533 
534     // set void
535     t1();
536     f1.get();
537 
538     // exec a second time
539     bool thrown = false;
540     try {
541         t1();
542     } catch ( boost::fibers::promise_already_satisfied const&) {
543         thrown = true;
544     }
545     BOOST_CHECK( thrown);
546 }
547 
test_packaged_task_exception()548 void test_packaged_task_exception() {
549     // promise takes a copyable as return type
550     boost::fibers::packaged_task< int() > t1( fn5);
551     BOOST_CHECK( t1.valid() );
552     boost::fibers::future< int > f1 = t1.get_future();
553     BOOST_CHECK( f1.valid() );
554 
555     // exec
556     t1();
557     bool thrown = false;
558     try {
559         f1.get();
560     } catch ( my_exception const&) {
561         thrown = true;
562     }
563     BOOST_CHECK( thrown);
564 
565     boost::fibers::packaged_task< int() > t2( fn5);
566     BOOST_CHECK( t2.valid() );
567     boost::fibers::future< int > f2 = t2.get_future();
568     BOOST_CHECK( f2.valid() );
569 
570     // exec
571     t2();
572     BOOST_CHECK( f2.get_exception_ptr() );
573     thrown = false;
574     try
575     { std::rethrow_exception( f2.get_exception_ptr() ); }
576     catch ( my_exception const&)
577     { thrown = true; }
578     BOOST_CHECK( thrown);
579 }
580 
test_packaged_task_exception_move()581 void test_packaged_task_exception_move() {
582     // promise takes a moveable as return type
583     boost::fibers::packaged_task< A() > t1( fn10);
584     BOOST_CHECK( t1.valid() );
585     boost::fibers::future< A > f1 = t1.get_future();
586     BOOST_CHECK( f1.valid() );
587 
588     // exec
589     t1();
590     bool thrown = false;
591     try {
592         f1.get();
593     } catch ( my_exception const&) {
594         thrown = true;
595     }
596     BOOST_CHECK( thrown);
597 
598     boost::fibers::packaged_task< A() > t2( fn10);
599     BOOST_CHECK( t2.valid() );
600     boost::fibers::future< A > f2 = t2.get_future();
601     BOOST_CHECK( f2.valid() );
602 
603     // exec
604     t2();
605     BOOST_CHECK( f2.get_exception_ptr() );
606     thrown = false;
607     try
608     { std::rethrow_exception( f2.get_exception_ptr() ); }
609     catch ( my_exception const&)
610     { thrown = true; }
611     BOOST_CHECK( thrown);
612 }
613 
test_packaged_task_exception_void()614 void test_packaged_task_exception_void() {
615     // promise takes a copyable as return type
616     boost::fibers::packaged_task< void() > t1( fn6);
617     BOOST_CHECK( t1.valid() );
618     boost::fibers::future< void > f1 = t1.get_future();
619     BOOST_CHECK( f1.valid() );
620 
621     // set void
622     t1();
623     bool thrown = false;
624     try {
625         f1.get();
626     } catch ( my_exception const&) {
627         thrown = true;
628     }
629     BOOST_CHECK( thrown);
630 
631     boost::fibers::packaged_task< void() > t2( fn6);
632     BOOST_CHECK( t2.valid() );
633     boost::fibers::future< void > f2 = t2.get_future();
634     BOOST_CHECK( f2.valid() );
635 
636     // exec
637     t2();
638     BOOST_CHECK( f2.get_exception_ptr() );
639     thrown = false;
640     try {
641         std::rethrow_exception( f2.get_exception_ptr() );
642     } catch ( my_exception const&) {
643         thrown = true;
644     }
645     BOOST_CHECK( thrown);
646 }
647 
648 
init_unit_test_suite(int,char * [])649 boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) {
650     boost::unit_test_framework::test_suite* test =
651         BOOST_TEST_SUITE("Boost.Fiber: packaged_task test suite");
652 
653     test->add(BOOST_TEST_CASE(test_packaged_task_create));
654     test->add(BOOST_TEST_CASE(test_packaged_task_create_move));
655     test->add(BOOST_TEST_CASE(test_packaged_task_create_void));
656     test->add(BOOST_TEST_CASE(test_packaged_task_move));
657     test->add(BOOST_TEST_CASE(test_packaged_task_move_move));
658     test->add(BOOST_TEST_CASE(test_packaged_task_move_void));
659     test->add(BOOST_TEST_CASE(test_packaged_task_swap));
660     test->add(BOOST_TEST_CASE(test_packaged_task_swap_move));
661     test->add(BOOST_TEST_CASE(test_packaged_task_swap_void));
662     test->add(BOOST_TEST_CASE(test_packaged_task_reset));
663     test->add(BOOST_TEST_CASE(test_packaged_task_reset_destruction));
664     test->add(BOOST_TEST_CASE(test_packaged_task_reset_move));
665     test->add(BOOST_TEST_CASE(test_packaged_task_reset_void));
666     test->add(BOOST_TEST_CASE(test_packaged_task_get_future));
667     test->add(BOOST_TEST_CASE(test_packaged_task_get_future_move));
668     test->add(BOOST_TEST_CASE(test_packaged_task_get_future_void));
669     test->add(BOOST_TEST_CASE(test_packaged_task_exec));
670     test->add(BOOST_TEST_CASE(test_packaged_task_exec_move));
671     test->add(BOOST_TEST_CASE(test_packaged_task_exec_param));
672     test->add(BOOST_TEST_CASE(test_packaged_task_exec_ref));
673     test->add(BOOST_TEST_CASE(test_packaged_task_exec_void));
674     test->add(BOOST_TEST_CASE(test_packaged_task_exception));
675     test->add(BOOST_TEST_CASE(test_packaged_task_exception_move));
676     test->add(BOOST_TEST_CASE(test_packaged_task_exception_void));
677 
678     return test;
679 }
680