// // promise.cpp // ~~~~~~~~~~~ // // Copyright (c) 2021-2023 Klemens D. Morgenstern // (klemens dot morgenstern at gmx dot net) // // 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) // // Disable autolinking for unit tests. #if !defined(BOOST_ALL_NO_LIB) #define BOOST_ALL_NO_LIB 1 #endif // !defined(BOOST_ALL_NO_LIB) // Test that header file is self-contained. #include #include #include #include #include #include #include #include "../unit_test.hpp" namespace promise { void promise_tester() { using namespace boost::asio; using namespace std::chrono; io_context ctx; steady_timer timer1{ctx}, timer2{ctx}; const auto started_when = steady_clock::now(); timer1.expires_at(started_when + milliseconds(5000)); timer2.expires_at(started_when + milliseconds(1000)); auto p1 = timer1.async_wait(experimental::use_promise); steady_clock::time_point completed_when; boost::system::error_code ec; bool called = false; p1([&](boost::system::error_code ec_) { ec = ec_; called = true; completed_when = steady_clock::now(); }); steady_clock::time_point timer2_done; timer2.async_wait( [&](boost::system::error_code) { timer2_done = steady_clock::now(); p1.cancel(); }); ctx.run(); static_assert( boost::asio::is_async_operation::value, "promise is async_op"); BOOST_ASIO_CHECK(timer2_done + milliseconds(1) > started_when); BOOST_ASIO_CHECK(completed_when > timer2_done); BOOST_ASIO_CHECK(called); BOOST_ASIO_CHECK(ec == error::operation_aborted); timer1.expires_after(milliseconds(0)); auto p2 = timer1.async_wait( boost::asio::append(experimental::use_promise, 123)); ec = boost::asio::error::would_block; called = false; p2([&](boost::system::error_code ec_, int i) { BOOST_ASIO_CHECK(i == 123); ec = ec_; called = true; }); BOOST_ASIO_CHECK(ec == boost::asio::error::would_block); BOOST_ASIO_CHECK(!called); ctx.restart(); ctx.run(); static_assert( boost::asio::is_async_operation::value, "promise is async_op"); BOOST_ASIO_CHECK(!ec); BOOST_ASIO_CHECK(called); } void promise_slot_tester() { using namespace boost::asio; using namespace std::chrono; io_context ctx; steady_timer timer1{ctx}, timer2{ctx}; const auto started_when = steady_clock::now(); timer1.expires_at(started_when + milliseconds(2500)); timer2.expires_at(started_when + milliseconds(1000)); auto p = timer1.async_wait(experimental::use_promise); steady_clock::time_point completed_when; boost::system::error_code ec; bool called = false; boost::asio::cancellation_signal sig; p(boost::asio::bind_cancellation_slot( sig.slot(), [&](boost::system::error_code ec_) { ec = ec_; called = true; completed_when = steady_clock::now(); })); steady_clock::time_point timer2_done; timer2.async_wait( [&](boost::system::error_code) { timer2_done = steady_clock::now(); sig.emit(boost::asio::cancellation_type::all); }); ctx.run(); static_assert( boost::asio::is_async_operation::value, "promise is async_op"); BOOST_ASIO_CHECK(timer2_done + milliseconds(1) > started_when); BOOST_ASIO_CHECK(completed_when > timer2_done); BOOST_ASIO_CHECK(called); BOOST_ASIO_CHECK(ec == error::operation_aborted); } void early_completion() { using namespace boost::asio; using namespace std::chrono; io_context ctx; auto p = boost::asio::post(ctx, boost::asio::experimental::use_promise); ctx.run(); BOOST_ASIO_CHECK(p.completed()); bool completed = false; p([&]{completed = true;}); BOOST_ASIO_CHECK(!completed); ctx.restart(); ctx.run(); BOOST_ASIO_CHECK(completed); } struct test_cancel_impl_op { boost::asio::steady_timer & tim; boost::system::error_code &ec; template void operator()(Self& self) { tim.async_wait(std::forward(self)); } template void operator()(Self& self, boost::system::error_code ec_) { ec = ec_; self.complete(ec_); } }; template BOOST_ASIO_INITFN_AUTO_RESULT_TYPE( CompletionToken, void(boost::system::error_code)) test_cancel_impl(boost::asio::steady_timer & tim, boost::system::error_code &ec, CompletionToken&& token) { return boost::asio::async_compose( test_cancel_impl_op{tim, ec}, token, tim); } void test_cancel() { boost::asio::io_context ctx; boost::asio::steady_timer tim{ctx, std::chrono::seconds(10)}; boost::system::error_code ec; { auto p = test_cancel_impl( tim, ec, boost::asio::experimental::use_promise); } ctx.run(); BOOST_ASIO_CHECK_MESSAGE( ec == boost::asio::error::operation_aborted, ec.message()); } } // namespace promise BOOST_ASIO_TEST_SUITE ( "promise", BOOST_ASIO_TEST_CASE(promise::promise_tester) BOOST_ASIO_TEST_CASE(promise::promise_slot_tester) BOOST_ASIO_TEST_CASE(promise::early_completion) BOOST_ASIO_TEST_CASE(promise::test_cancel) )