2
0
mirror of https://github.com/boostorg/asio.git synced 2026-01-19 04:02:09 +00:00
Files
asio/test/redirect_disposition.cpp
2025-11-04 23:42:51 +11:00

444 lines
11 KiB
C++

//
// redirect_disposition.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2025 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// 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 <boost/asio/redirect_disposition.hpp>
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/deferred.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/system_timer.hpp>
#include <boost/asio/use_future.hpp>
#include "unit_test.hpp"
struct redirect_disposition_handler
{
int* count_;
explicit redirect_disposition_handler(int* c)
: count_(c)
{
}
void operator()()
{
++(*count_);
}
};
void redirect_disposition_test()
{
boost::asio::io_context io1;
boost::asio::io_context io2;
boost::asio::system_timer timer1(io1);
boost::system::error_code ec = boost::asio::error::would_block;
int count = 0;
timer1.expires_after(boost::asio::chrono::seconds(0));
timer1.async_wait(
boost::asio::redirect_disposition(
boost::asio::bind_executor(io2.get_executor(),
redirect_disposition_handler(&count)), ec));
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(count == 0);
io1.run();
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(count == 0);
io2.run();
BOOST_ASIO_CHECK(!ec);
BOOST_ASIO_CHECK(count == 1);
ec = boost::asio::error::would_block;
timer1.async_wait(
boost::asio::redirect_disposition(
boost::asio::bind_executor(io2.get_executor(),
boost::asio::deferred), ec))(redirect_disposition_handler(&count));
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(count == 1);
io1.restart();
io1.run();
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(count == 1);
io2.restart();
io2.run();
BOOST_ASIO_CHECK(!ec);
BOOST_ASIO_CHECK(count == 2);
#if defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
ec = boost::asio::error::would_block;
std::future<void> f = timer1.async_wait(
boost::asio::redirect_disposition(
boost::asio::bind_executor(io2.get_executor(),
boost::asio::use_future), ec));
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
== std::future_status::timeout);
io1.restart();
io1.run();
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
== std::future_status::timeout);
io2.restart();
io2.run();
BOOST_ASIO_CHECK(!ec);
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
== std::future_status::ready);
#endif // defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
}
void partial_redirect_disposition_test()
{
boost::asio::io_context io1;
boost::asio::io_context io2;
boost::asio::system_timer timer1(io1);
boost::system::error_code ec = boost::asio::error::would_block;
int count = 0;
timer1.expires_after(boost::asio::chrono::seconds(0));
timer1.async_wait(boost::asio::redirect_disposition(ec))(
boost::asio::bind_executor(io2.get_executor(),
redirect_disposition_handler(&count)));
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(count == 0);
io1.run();
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(count == 0);
io2.run();
BOOST_ASIO_CHECK(!ec);
BOOST_ASIO_CHECK(count == 1);
ec = boost::asio::error::would_block;
timer1.async_wait(boost::asio::redirect_disposition(ec))(
boost::asio::bind_executor(io2.get_executor(),
boost::asio::deferred))(redirect_disposition_handler(&count));
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(count == 1);
io1.restart();
io1.run();
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(count == 1);
io2.restart();
io2.run();
BOOST_ASIO_CHECK(!ec);
BOOST_ASIO_CHECK(count == 2);
ec = boost::asio::error::would_block;
timer1.async_wait()(boost::asio::redirect_disposition(ec))(
boost::asio::bind_executor(io2.get_executor(),
boost::asio::deferred))(redirect_disposition_handler(&count));
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(count == 2);
io1.restart();
io1.run();
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(count == 2);
io2.restart();
io2.run();
BOOST_ASIO_CHECK(!ec);
BOOST_ASIO_CHECK(count == 3);
#if defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
ec = boost::asio::error::would_block;
std::future<void> f = timer1.async_wait(boost::asio::redirect_disposition(ec))(
boost::asio::bind_executor(io2.get_executor(), boost::asio::use_future));
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
== std::future_status::timeout);
io1.restart();
io1.run();
BOOST_ASIO_CHECK(ec == boost::asio::error::would_block);
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
== std::future_status::timeout);
io2.restart();
io2.run();
BOOST_ASIO_CHECK(!ec);
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
== std::future_status::ready);
#endif // defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
}
void redirect_disposition_to_exception_ptr_test()
{
boost::asio::io_context io1;
boost::asio::io_context io2;
boost::asio::system_timer timer1(io1);
std::exception_ptr ex = nullptr;
int count = 0;
timer1.expires_after(boost::asio::chrono::seconds(100));
timer1.async_wait(
boost::asio::redirect_disposition(
boost::asio::bind_executor(io2.get_executor(),
redirect_disposition_handler(&count)), ex));
timer1.cancel();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(count == 0);
io1.run();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(count == 0);
io2.run();
BOOST_ASIO_CHECK(ex != nullptr);
BOOST_ASIO_CHECK(count == 1);
#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
try
{
std::rethrow_exception(ex);
}
catch (const boost::system::system_error& e)
{
BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted);
}
#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
ex = nullptr;
timer1.async_wait(
boost::asio::redirect_disposition(
boost::asio::bind_executor(io2.get_executor(),
boost::asio::deferred), ex))(redirect_disposition_handler(&count));
timer1.cancel();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(count == 1);
io1.restart();
io1.run();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(count == 1);
io2.restart();
io2.run();
BOOST_ASIO_CHECK(ex != nullptr);
BOOST_ASIO_CHECK(count == 2);
#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
try
{
std::rethrow_exception(ex);
}
catch (const boost::system::system_error& e)
{
BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted);
}
#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
#if defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
ex = nullptr;
std::future<void> f = timer1.async_wait(
boost::asio::redirect_disposition(
boost::asio::bind_executor(io2.get_executor(),
boost::asio::use_future), ex));
timer1.cancel();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
== std::future_status::timeout);
io1.restart();
io1.run();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
== std::future_status::timeout);
io2.restart();
io2.run();
BOOST_ASIO_CHECK(ex != nullptr);
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
== std::future_status::ready);
#endif // defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
}
void partial_redirect_disposition_to_exception_ptr_test()
{
boost::asio::io_context io1;
boost::asio::io_context io2;
boost::asio::system_timer timer1(io1);
std::exception_ptr ex = nullptr;
int count = 0;
timer1.expires_after(boost::asio::chrono::seconds(100));
timer1.async_wait(boost::asio::redirect_disposition(ex))(
boost::asio::bind_executor(io2.get_executor(),
redirect_disposition_handler(&count)));
timer1.cancel();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(count == 0);
io1.run();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(count == 0);
io2.run();
BOOST_ASIO_CHECK(ex != nullptr);
BOOST_ASIO_CHECK(count == 1);
#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
try
{
std::rethrow_exception(ex);
}
catch (const boost::system::system_error& e)
{
BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted);
}
#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
ex = nullptr;
timer1.async_wait(boost::asio::redirect_disposition(ex))(
boost::asio::bind_executor(io2.get_executor(),
boost::asio::deferred))(redirect_disposition_handler(&count));
timer1.cancel();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(count == 1);
io1.restart();
io1.run();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(count == 1);
io2.restart();
io2.run();
BOOST_ASIO_CHECK(ex != nullptr);
BOOST_ASIO_CHECK(count == 2);
#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
try
{
std::rethrow_exception(ex);
}
catch (const boost::system::system_error& e)
{
BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted);
}
#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
ex = nullptr;
timer1.async_wait()(boost::asio::redirect_disposition(ex))(
boost::asio::bind_executor(io2.get_executor(),
boost::asio::deferred))(redirect_disposition_handler(&count));
timer1.cancel();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(count == 2);
io1.restart();
io1.run();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(count == 2);
io2.restart();
io2.run();
BOOST_ASIO_CHECK(ex != nullptr);
BOOST_ASIO_CHECK(count == 3);
#if !defined(BOOST_ASIO_NO_EXCEPTIONS)
try
{
std::rethrow_exception(ex);
}
catch (const boost::system::system_error& e)
{
BOOST_ASIO_CHECK(e.code() == boost::asio::error::operation_aborted);
}
#endif // !defined(BOOST_ASIO_NO_EXCEPTIONS)
#if defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
ex = nullptr;
std::future<void> f = timer1.async_wait(boost::asio::redirect_disposition(ex))(
boost::asio::bind_executor(io2.get_executor(), boost::asio::use_future));
timer1.cancel();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
== std::future_status::timeout);
io1.restart();
io1.run();
BOOST_ASIO_CHECK(ex == nullptr);
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
== std::future_status::timeout);
io2.restart();
io2.run();
BOOST_ASIO_CHECK(ex != nullptr);
BOOST_ASIO_CHECK(f.wait_for(std::chrono::seconds(0))
== std::future_status::ready);
#endif // defined(BOOST_ASIO_HAS_STD_FUTURE_CLASS)
}
BOOST_ASIO_TEST_SUITE
(
"redirect_disposition",
BOOST_ASIO_TEST_CASE(redirect_disposition_test)
BOOST_ASIO_TEST_CASE(partial_redirect_disposition_test)
BOOST_ASIO_TEST_CASE(redirect_disposition_to_exception_ptr_test)
BOOST_ASIO_TEST_CASE(partial_redirect_disposition_to_exception_ptr_test)
)