// (C) Copyright 2008-10 Anthony Williams // 2015 Oliver Kowalke // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include #include typedef std::chrono::milliseconds ms; typedef std::chrono::high_resolution_clock Clock; int gi = 7; struct my_exception : public std::runtime_error { my_exception() : std::runtime_error("my_exception") { } }; struct A { A() = default; A( A const&) = delete; A( A &&) = default; A & operator=( A const&) = delete; A & operator=( A &&) = default; int value; }; void fn1( boost::fibers::promise< int > * p, int i) { boost::this_fiber::yield(); p->set_value( i); } void fn2() { boost::fibers::promise< int > p; boost::fibers::future< int > f( p.get_future() ); boost::this_fiber::yield(); boost::fibers::fiber( boost::fibers::launch::dispatch, fn1, & p, 7).detach(); boost::this_fiber::yield(); BOOST_CHECK( 7 == f.get() ); } int fn3() { return 3; } void fn4() { } int fn5() { boost::throw_exception( my_exception() ); return 3; } void fn6() { boost::throw_exception( my_exception() ); } int & fn7() { return gi; } int fn8( int i) { return i; } A fn9() { A a; a.value = 3; return a; } A fn10() { boost::throw_exception( my_exception() ); return A(); } void fn11( boost::fibers::promise< int > p) { boost::this_fiber::sleep_for( ms(500) ); p.set_value(3); } void fn12( boost::fibers::promise< int& > p) { boost::this_fiber::sleep_for( ms(500) ); gi = 5; p.set_value( gi); } void fn13( boost::fibers::promise< void > p) { boost::this_fiber::sleep_for( ms(400) ); p.set_value(); } // future void test_future_create() { // default constructed future is not valid boost::fibers::future< int > f1; BOOST_CHECK( ! f1.valid() ); // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int > p2; boost::fibers::future< int > f2 = p2.get_future(); BOOST_CHECK( f2.valid() ); } void test_future_create_ref() { // default constructed future is not valid boost::fibers::future< int& > f1; BOOST_CHECK( ! f1.valid() ); // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int& > p2; boost::fibers::future< int& > f2 = p2.get_future(); BOOST_CHECK( f2.valid() ); } void test_future_create_void() { // default constructed future is not valid boost::fibers::future< void > f1; BOOST_CHECK( ! f1.valid() ); // future retrieved from promise is valid (if it is the first) boost::fibers::promise< void > p2; boost::fibers::future< void > f2 = p2.get_future(); BOOST_CHECK( f2.valid() ); } void test_future_move() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int > p1; boost::fibers::future< int > f1 = p1.get_future(); BOOST_CHECK( f1.valid() ); // move construction boost::fibers::future< int > f2( std::move( f1) ); BOOST_CHECK( ! f1.valid() ); BOOST_CHECK( f2.valid() ); // move assignment f1 = std::move( f2); BOOST_CHECK( f1.valid() ); BOOST_CHECK( ! f2.valid() ); } void test_future_move_ref() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int& > p1; boost::fibers::future< int& > f1 = p1.get_future(); BOOST_CHECK( f1.valid() ); // move construction boost::fibers::future< int& > f2( std::move( f1) ); BOOST_CHECK( ! f1.valid() ); BOOST_CHECK( f2.valid() ); // move assignment f1 = std::move( f2); BOOST_CHECK( f1.valid() ); BOOST_CHECK( ! f2.valid() ); } void test_future_move_void() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< void > p1; boost::fibers::future< void > f1 = p1.get_future(); BOOST_CHECK( f1.valid() ); // move construction boost::fibers::future< void > f2( std::move( f1) ); BOOST_CHECK( ! f1.valid() ); BOOST_CHECK( f2.valid() ); // move assignment f1 = std::move( f2); BOOST_CHECK( f1.valid() ); BOOST_CHECK( ! f2.valid() ); } void test_future_get() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int > p1; p1.set_value( 7); boost::fibers::future< int > f1 = p1.get_future(); BOOST_CHECK( f1.valid() ); // get BOOST_CHECK( ! f1.get_exception_ptr() ); BOOST_CHECK( 7 == f1.get() ); BOOST_CHECK( ! f1.valid() ); // throw broken_promise if promise is destroyed without set { boost::fibers::promise< int > p2; f1 = p2.get_future(); } bool thrown = false; try { f1.get(); } catch ( boost::fibers::broken_promise const&) { thrown = true; } BOOST_CHECK( ! f1.valid() ); BOOST_CHECK( thrown); } void test_future_get_move() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< A > p1; A a; a.value = 7; p1.set_value( std::move( a) ); boost::fibers::future< A > f1 = p1.get_future(); BOOST_CHECK( f1.valid() ); // get BOOST_CHECK( ! f1.get_exception_ptr() ); BOOST_CHECK( 7 == f1.get().value); BOOST_CHECK( ! f1.valid() ); // throw broken_promise if promise is destroyed without set { boost::fibers::promise< A > p2; f1 = p2.get_future(); } bool thrown = false; try { f1.get(); } catch ( boost::fibers::broken_promise const&) { thrown = true; } BOOST_CHECK( ! f1.valid() ); BOOST_CHECK( thrown); } void test_future_get_ref() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int& > p1; int i = 7; p1.set_value( i); boost::fibers::future< int& > f1 = p1.get_future(); BOOST_CHECK( f1.valid() ); // get BOOST_CHECK( ! f1.get_exception_ptr() ); int & j = f1.get(); BOOST_CHECK( &i == &j); BOOST_CHECK( ! f1.valid() ); // throw broken_promise if promise is destroyed without set { boost::fibers::promise< int& > p2; f1 = p2.get_future(); } bool thrown = false; try { f1.get(); } catch ( boost::fibers::broken_promise const&) { thrown = true; } BOOST_CHECK( ! f1.valid() ); BOOST_CHECK( thrown); } void test_future_get_void() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< void > p1; p1.set_value(); boost::fibers::future< void > f1 = p1.get_future(); BOOST_CHECK( f1.valid() ); // get BOOST_CHECK( ! f1.get_exception_ptr() ); f1.get(); BOOST_CHECK( ! f1.valid() ); // throw broken_promise if promise is destroyed without set { boost::fibers::promise< void > p2; f1 = p2.get_future(); } bool thrown = false; try { f1.get(); } catch ( boost::fibers::broken_promise const&) { thrown = true; } BOOST_CHECK( ! f1.valid() ); BOOST_CHECK( thrown); } void test_future_share() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int > p1; int i = 7; p1.set_value( i); boost::fibers::future< int > f1 = p1.get_future(); BOOST_CHECK( f1.valid() ); // share boost::fibers::shared_future< int > sf1 = f1.share(); BOOST_CHECK( sf1.valid() ); BOOST_CHECK( ! f1.valid() ); // get BOOST_CHECK( ! sf1.get_exception_ptr() ); int j = sf1.get(); BOOST_CHECK_EQUAL( i, j); BOOST_CHECK( sf1.valid() ); } void test_future_share_ref() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int& > p1; int i = 7; p1.set_value( i); boost::fibers::future< int& > f1 = p1.get_future(); BOOST_CHECK( f1.valid() ); // share boost::fibers::shared_future< int& > sf1 = f1.share(); BOOST_CHECK( sf1.valid() ); BOOST_CHECK( ! f1.valid() ); // get BOOST_CHECK( ! sf1.get_exception_ptr() ); int & j = sf1.get(); BOOST_CHECK( &i == &j); BOOST_CHECK( sf1.valid() ); } void test_future_share_void() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< void > p1; p1.set_value(); boost::fibers::future< void > f1 = p1.get_future(); BOOST_CHECK( f1.valid() ); // share boost::fibers::shared_future< void > sf1 = f1.share(); BOOST_CHECK( sf1.valid() ); BOOST_CHECK( ! f1.valid() ); // get BOOST_CHECK( ! sf1.get_exception_ptr() ); sf1.get(); BOOST_CHECK( sf1.valid() ); } void test_future_wait() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int > p1; boost::fibers::future< int > f1 = p1.get_future(); // wait on future p1.set_value( 7); f1.wait(); BOOST_CHECK( 7 == f1.get() ); } void test_future_wait_ref() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int& > p1; boost::fibers::future< int& > f1 = p1.get_future(); // wait on future int i = 7; p1.set_value( i); f1.wait(); int & j = f1.get(); BOOST_CHECK( &i == &j); } void test_future_wait_void() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< void > p1; boost::fibers::future< void > f1 = p1.get_future(); // wait on future p1.set_value(); f1.wait(); f1.get(); BOOST_CHECK( ! f1.valid() ); } void test_future_wait_for() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int > p1; boost::fibers::future< int > f1 = p1.get_future(); boost::fibers::fiber( boost::fibers::launch::dispatch, fn11, std::move( p1) ).detach(); // wait on future BOOST_CHECK( f1.valid() ); boost::fibers::future_status status = f1.wait_for( ms(300) ); BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); status = f1.wait_for( ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); f1.wait(); } void test_future_wait_for_ref() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int& > p1; boost::fibers::future< int& > f1 = p1.get_future(); boost::fibers::fiber( boost::fibers::launch::dispatch, fn12, std::move( p1) ).detach(); // wait on future BOOST_CHECK( f1.valid() ); boost::fibers::future_status status = f1.wait_for( ms(300) ); BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); status = f1.wait_for( ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); f1.wait(); } void test_future_wait_for_void() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< void > p1; boost::fibers::future< void > f1 = p1.get_future(); boost::fibers::fiber( boost::fibers::launch::dispatch, fn13, std::move( p1) ).detach(); // wait on future BOOST_CHECK( f1.valid() ); boost::fibers::future_status status = f1.wait_for( ms(300) ); BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); status = f1.wait_for( ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); f1.wait(); } void test_future_wait_until() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int > p1; boost::fibers::future< int > f1 = p1.get_future(); boost::fibers::fiber( boost::fibers::launch::dispatch, fn11, std::move( p1) ).detach(); // wait on future BOOST_CHECK( f1.valid() ); boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); status = f1.wait_until( Clock::now() + ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); f1.wait(); } void test_future_wait_until_ref() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< int& > p1; boost::fibers::future< int& > f1 = p1.get_future(); boost::fibers::fiber( boost::fibers::launch::dispatch, fn12, std::move( p1) ).detach(); // wait on future BOOST_CHECK( f1.valid() ); boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); status = f1.wait_until( Clock::now() + ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); f1.wait(); } void test_future_wait_until_void() { // future retrieved from promise is valid (if it is the first) boost::fibers::promise< void > p1; boost::fibers::future< void > f1 = p1.get_future(); boost::fibers::fiber( boost::fibers::launch::dispatch, fn13, std::move( p1) ).detach(); // wait on future BOOST_CHECK( f1.valid() ); boost::fibers::future_status status = f1.wait_until( Clock::now() + ms(300) ); BOOST_CHECK( boost::fibers::future_status::timeout == status); BOOST_CHECK( f1.valid() ); status = f1.wait_until( Clock::now() + ms(400) ); BOOST_CHECK( boost::fibers::future_status::ready == status); BOOST_CHECK( f1.valid() ); f1.wait(); } void test_future_wait_with_fiber_1() { boost::fibers::promise< int > p1; boost::fibers::fiber( boost::fibers::launch::dispatch, fn1, & p1, 7).detach(); boost::fibers::future< int > f1 = p1.get_future(); // wait on future BOOST_CHECK( 7 == f1.get() ); } void test_future_wait_with_fiber_2() { boost::fibers::fiber( boost::fibers::launch::dispatch, fn2).join(); } boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[]) { boost::unit_test_framework::test_suite* test = BOOST_TEST_SUITE("Boost.Fiber: future test suite"); test->add(BOOST_TEST_CASE(test_future_create)); test->add(BOOST_TEST_CASE(test_future_create_ref)); test->add(BOOST_TEST_CASE(test_future_create_void)); test->add(BOOST_TEST_CASE(test_future_move)); test->add(BOOST_TEST_CASE(test_future_move_ref)); test->add(BOOST_TEST_CASE(test_future_move_void)); test->add(BOOST_TEST_CASE(test_future_get)); test->add(BOOST_TEST_CASE(test_future_get_move)); test->add(BOOST_TEST_CASE(test_future_get_ref)); test->add(BOOST_TEST_CASE(test_future_get_void)); test->add(BOOST_TEST_CASE(test_future_share)); test->add(BOOST_TEST_CASE(test_future_share_ref)); test->add(BOOST_TEST_CASE(test_future_share_void)); test->add(BOOST_TEST_CASE(test_future_wait)); test->add(BOOST_TEST_CASE(test_future_wait_ref)); test->add(BOOST_TEST_CASE(test_future_wait_void)); test->add(BOOST_TEST_CASE(test_future_wait_for)); test->add(BOOST_TEST_CASE(test_future_wait_for_ref)); test->add(BOOST_TEST_CASE(test_future_wait_for_void)); test->add(BOOST_TEST_CASE(test_future_wait_until)); test->add(BOOST_TEST_CASE(test_future_wait_until_ref)); test->add(BOOST_TEST_CASE(test_future_wait_until_void)); test->add(BOOST_TEST_CASE(test_future_wait_with_fiber_1)); test->add(BOOST_TEST_CASE(test_future_wait_with_fiber_2)); return test; }