Files
boost_beast/test/beast/core/bind_handler.cpp

630 lines
17 KiB
C++
Raw Permalink Normal View History

2017-07-20 08:01:46 -07:00
//
2019-02-21 07:00:31 -08:00
// Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
2017-07-20 08:01:46 -07:00
//
// 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)
//
2017-07-20 13:40:34 -07:00
// Official repository: https://github.com/boostorg/beast
//
2017-07-20 08:01:46 -07:00
// Test that header file is self-contained.
2017-07-20 13:40:34 -07:00
#include <boost/beast/core/bind_handler.hpp>
2017-07-20 08:01:46 -07:00
2019-01-09 09:52:19 -08:00
#include "test_handler.hpp"
2017-07-20 13:40:34 -07:00
#include <boost/beast/core/detail/type_traits.hpp>
2018-11-11 14:07:55 -08:00
#include <boost/beast/_experimental/unit_test/suite.hpp>
#include <boost/beast/_experimental/test/stream.hpp>
#include <boost/asio/io_context.hpp>
2018-12-11 13:35:35 -08:00
#include <boost/asio/bind_executor.hpp>
#include <boost/asio/executor_work_guard.hpp>
#include <boost/asio/dispatch.hpp>
#include <boost/asio/defer.hpp>
#include <boost/asio/post.hpp>
#include <boost/asio/strand.hpp>
2018-12-11 13:35:35 -08:00
#include <boost/bind/placeholders.hpp>
#include <boost/core/exchange.hpp>
#include <memory>
2017-07-19 09:50:16 -07:00
#include <string>
2017-07-20 08:01:46 -07:00
2017-07-20 13:40:34 -07:00
namespace boost {
2017-07-20 08:01:46 -07:00
namespace beast {
class bind_handler_test : public unit_test::suite
2017-07-20 08:01:46 -07:00
{
public:
2017-07-19 09:50:16 -07:00
template<class... Args>
struct handler
{
void
2017-07-19 09:50:16 -07:00
operator()(Args const&...) const
{
}
};
struct copyable
{
template<class... Args>
void
operator()(Args&&...) const
{
}
};
struct move_only
{
move_only() = default;
move_only(move_only&&) = default;
move_only(move_only const&) = delete;
void operator()() const{};
};
2018-12-11 13:35:35 -08:00
// A move-only parameter
template<std::size_t I>
struct move_arg
{
move_arg() = default;
move_arg(move_arg&&) = default;
move_arg(move_arg const&) = delete;
void operator()() const
{
};
};
void
callback(int v)
{
BEAST_EXPECT(v == 42);
}
2018-12-11 13:35:35 -08:00
class test_executor
{
bind_handler_test& s_;
2020-06-25 16:03:59 +02:00
2020-06-26 14:43:48 +02:00
#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
net::any_io_executor ex_;
// Storing the blocking property as a member is not strictly necessary,
// as we could simply forward the calls
// require(ex_, blocking.possibly)
// and
// require(ex_, blocking.never)
// to the underlying executor, and then
// query(ex_, blocking)
// when required. This forwarding approach is used here for the
// outstanding_work property.
net::execution::blocking_t blocking_;
2018-12-11 13:35:35 -08:00
2020-06-25 16:03:59 +02:00
#else // defined(BOOST_ASIO_NO_TS_EXECUTORS)
net::io_context::executor_type ex_;
#endif // defined(BOOST_ASIO_NO_TS_EXECUTORS)
2018-12-11 13:35:35 -08:00
public:
test_executor(
test_executor const&) = default;
test_executor(
bind_handler_test& s,
net::io_context& ioc)
: s_(s)
, ex_(ioc.get_executor())
2020-06-25 16:03:59 +02:00
#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
, blocking_(net::execution::blocking.possibly)
2020-06-25 16:03:59 +02:00
#endif
2018-12-11 13:35:35 -08:00
{
}
bool operator==(
test_executor const& other) const noexcept
{
return ex_ == other.ex_;
}
bool operator!=(
test_executor const& other) const noexcept
{
return ex_ != other.ex_;
}
2020-06-26 14:43:48 +02:00
#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
2020-06-25 16:03:59 +02:00
2020-07-04 07:33:22 +02:00
net::execution_context&
query(
net::execution::context_t c) const noexcept
{
return net::query(ex_, c);
}
2020-07-04 07:33:22 +02:00
net::execution::blocking_t
query(
net::execution::blocking_t) const noexcept
{
return blocking_;
}
2020-07-04 07:33:22 +02:00
net::execution::outstanding_work_t
query(
net::execution::outstanding_work_t w) const noexcept
{
return net::query(ex_, w);
}
2020-07-04 07:33:22 +02:00
test_executor
require(
net::execution::blocking_t::possibly_t b) const
{
test_executor new_ex(*this);
new_ex.blocking_ = b;
return new_ex;
}
2020-07-04 07:33:22 +02:00
test_executor
require(
net::execution::blocking_t::never_t b) const
{
test_executor new_ex(*this);
new_ex.blocking_ = b;
return new_ex;
}
test_executor prefer(net::execution::outstanding_work_t::untracked_t w) const
{
test_executor new_ex(*this);
new_ex.ex_ = net::prefer(ex_, w);
return new_ex;
}
test_executor prefer(net::execution::outstanding_work_t::tracked_t w) const
{
test_executor new_ex(*this);
new_ex.ex_ = net::prefer(ex_, w);
return new_ex;
}
template<class F>
void execute(F&& f) const
{
if (blocking_ == net::execution::blocking.possibly)
{
s_.on_invoke();
net::execution::execute(ex_, std::forward<F>(f));
}
else
{
// shouldn't be called since the enclosing
// networking wrapper only uses dispatch
BEAST_FAIL();
}
}
2020-06-26 14:43:48 +02:00
#endif
#if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
net::execution_context&
2018-12-11 13:35:35 -08:00
context() const noexcept
{
return ex_.context();
}
2020-07-04 07:33:22 +02:00
void
on_work_started() const noexcept
2018-12-11 13:35:35 -08:00
{
ex_.on_work_started();
}
2020-07-04 07:33:22 +02:00
void
on_work_finished() const noexcept
2018-12-11 13:35:35 -08:00
{
ex_.on_work_finished();
}
template<class F, class Alloc>
2020-07-04 07:33:22 +02:00
void
dispatch(F&& f, Alloc const& a)
2018-12-11 13:35:35 -08:00
{
s_.on_invoke();
2020-06-26 14:43:48 +02:00
net::execution::execute(
net::prefer(ex_,
net::execution::blocking.possibly,
net::execution::allocator(a)),
std::forward<F>(f));
// previously equivalent to
// ex_.dispatch(std::forward<F>(f), a);
2018-12-11 13:35:35 -08:00
}
template<class F, class Alloc>
2020-07-04 07:33:22 +02:00
void
post(F&& f, Alloc const& a)
2018-12-11 13:35:35 -08:00
{
// shouldn't be called since the enclosing
// networking wrapper only uses dispatch
2019-02-07 20:11:21 -08:00
BEAST_FAIL();
2018-12-11 13:35:35 -08:00
}
template<class F, class Alloc>
2020-07-04 07:33:22 +02:00
void
defer(F&& f, Alloc const& a)
2018-12-11 13:35:35 -08:00
{
// shouldn't be called since the enclosing
// networking wrapper only uses dispatch
2019-02-07 20:11:21 -08:00
BEAST_FAIL();
2018-12-11 13:35:35 -08:00
}
#endif // !defined(BOOST_ASIO_NO_TS_EXECUTORS)
2018-12-11 13:35:35 -08:00
};
2020-06-26 14:43:48 +02:00
#if defined(BOOST_ASIO_NO_TS_EXECUTORS)
2020-06-25 16:03:59 +02:00
BOOST_STATIC_ASSERT(net::execution::is_executor<test_executor>::value);
2020-06-26 14:43:48 +02:00
#else
BOOST_STATIC_ASSERT(net::is_executor<test_executor>::value);
#endif
2018-12-11 13:35:35 -08:00
class test_cb
{
bool fail_ = true;
public:
test_cb() = default;
2018-12-11 13:35:35 -08:00
test_cb(test_cb const&) = delete;
test_cb(test_cb&& other)
: fail_(boost::exchange(
2018-12-11 13:35:35 -08:00
other.fail_, false))
{
}
~test_cb()
{
BEAST_EXPECT(! fail_);
2018-12-11 13:35:35 -08:00
}
void
operator()()
{
fail_ = false;
BEAST_EXPECT(true);
2018-12-11 13:35:35 -08:00
}
void
operator()(int v)
{
fail_ = false;
BEAST_EXPECT(v == 42);
2018-12-11 13:35:35 -08:00
}
void
operator()(int v, string_view s)
{
fail_ = false;
BEAST_EXPECT(v == 42);
BEAST_EXPECT(s == "s");
2018-12-11 13:35:35 -08:00
}
void
operator()(int v, string_view s, move_arg<1>)
{
fail_ = false;
BEAST_EXPECT(v == 42);
BEAST_EXPECT(s == "s");
2018-12-11 13:35:35 -08:00
}
void
operator()(int v, string_view s, move_arg<1>, move_arg<2>)
{
fail_ = false;
BEAST_EXPECT(v == 42);
BEAST_EXPECT(s == "s");
2018-12-11 13:35:35 -08:00
}
void
operator()(error_code, std::size_t n)
{
fail_ = false;
BEAST_EXPECT(n == 256);
2018-12-11 13:35:35 -08:00
}
void
operator()(
error_code, std::size_t n, string_view s)
{
boost::ignore_unused(s);
fail_ = false;
BEAST_EXPECT(n == 256);
2018-12-11 13:35:35 -08:00
}
void
operator()(std::shared_ptr<int> const& sp)
{
fail_ = false;
BEAST_EXPECT(sp.get() != nullptr);
2018-12-11 13:35:35 -08:00
}
};
#if 0
2018-12-11 13:35:35 -08:00
// These functions should fail to compile
void
failStdBind()
{
std::bind(bind_handler(test_cb{}));
}
2018-12-11 13:35:35 -08:00
void
failStdBindFront()
2017-07-20 08:01:46 -07:00
{
std::bind(bind_front_handler(test_cb{}));
2017-07-20 08:01:46 -07:00
}
#endif
2018-12-11 13:35:35 -08:00
//--------------------------------------------------------------------------
bool invoked_;
void
on_invoke()
{
invoked_ = true;
}
template<class F>
void
testHooks(net::io_context& ioc, F&& f)
{
invoked_ = false;
net::post(ioc, std::forward<F>(f));
ioc.run();
ioc.restart();
BEAST_EXPECT(invoked_);
}
//--------------------------------------------------------------------------
2017-07-19 09:50:16 -07:00
void
testBindHandler()
2017-07-19 09:50:16 -07:00
{
2018-12-11 13:35:35 -08:00
using m1 = move_arg<1>;
using m2 = move_arg<2>;
{
2018-12-11 13:35:35 -08:00
using namespace std::placeholders;
2017-07-20 08:01:46 -07:00
2018-12-11 13:35:35 -08:00
// 0-ary
bind_handler(test_cb{})();
2018-12-11 13:35:35 -08:00
// 1-ary
bind_handler(test_cb{}, 42)();
bind_handler(test_cb{}, _1)(42);
bind_handler(test_cb{}, _2)(0, 42);
2018-12-11 13:35:35 -08:00
// 2-ary
bind_handler(test_cb{}, 42, "s")();
bind_handler(test_cb{}, 42, "s")(0);
bind_handler(test_cb{}, _1, "s")(42);
bind_handler(test_cb{}, 42, _1) ("s");
bind_handler(test_cb{}, _1, _2)(42, "s");
bind_handler(test_cb{}, _1, _2)(42, "s", "X");
bind_handler(test_cb{}, _2, _1)("s", 42);
bind_handler(test_cb{}, _3, _2)("X", "s", 42);
2018-12-11 13:35:35 -08:00
// 3-ary
bind_handler(test_cb{}, 42, "s")(m1{});
bind_handler(test_cb{}, 42, "s", _1)(m1{});
bind_handler(test_cb{}, 42, _1, m1{})("s");
2018-12-11 13:35:35 -08:00
// 4-ary
bind_handler(test_cb{}, 42, "s")(m1{}, m2{});
bind_handler(test_cb{}, 42, "s", m1{})(m2{});
bind_handler(test_cb{}, 42, "s", m1{}, m2{})();
bind_handler(test_cb{}, 42, _1, m1{})("s", m2{});
bind_handler(test_cb{}, _3, _1, m1{})("s", m2{}, 42);
2018-12-11 13:35:35 -08:00
}
{
using namespace boost::placeholders;
// 0-ary
bind_handler(test_cb{})();
2018-12-11 13:35:35 -08:00
// 1-ary
bind_handler(test_cb{}, 42)();
bind_handler(test_cb{}, _1)(42);
bind_handler(test_cb{}, _2)(0, 42);
2018-12-11 13:35:35 -08:00
// 2-ary
bind_handler(test_cb{}, 42, "s")();
bind_handler(test_cb{}, 42, "s")(0);
bind_handler(test_cb{}, _1, "s")(42);
bind_handler(test_cb{}, 42, _1) ("s");
bind_handler(test_cb{}, _1, _2)(42, "s");
bind_handler(test_cb{}, _1, _2)(42, "s", "X");
bind_handler(test_cb{}, _2, _1)("s", 42);
bind_handler(test_cb{}, _3, _2)("X", "s", 42);
2018-12-11 13:35:35 -08:00
// 3-ary
bind_handler(test_cb{}, 42, "s")(m1{});
bind_handler(test_cb{}, 42, "s", _1)(m1{});
bind_handler(test_cb{}, 42, _1, m1{})("s");
2018-12-11 13:35:35 -08:00
// 4-ary
bind_handler(test_cb{}, 42, "s")(m1{}, m2{});
bind_handler(test_cb{}, 42, "s", m1{})(m2{});
bind_handler(test_cb{}, 42, "s", m1{}, m2{})();
bind_handler(test_cb{}, 42, _1, m1{})("s", m2{});
bind_handler(test_cb{}, _3, _1, m1{})("s", m2{}, 42);
}
2018-12-11 13:35:35 -08:00
// perfect forwarding
{
2018-12-11 13:35:35 -08:00
std::shared_ptr<int> const sp =
std::make_shared<int>(42);
{
bind_handler(test_cb{}, sp)();
2018-12-11 13:35:35 -08:00
BEAST_EXPECT(sp.get() != nullptr);
}
{
bind_handler(test_cb{})(sp);
2018-12-11 13:35:35 -08:00
BEAST_EXPECT(sp.get() != nullptr);
}
}
2018-12-11 13:35:35 -08:00
// associated executor
{
2018-12-11 13:35:35 -08:00
net::io_context ioc;
testHooks(ioc, bind_handler(net::bind_executor(
test_executor(*this, ioc), test_cb{})));
}
// asio_handler_invoke
{
// make sure things compile, also can set a
// breakpoint in asio_handler_invoke to make sure
// it is instantiated.
net::io_context ioc;
net::strand<
net::io_context::executor_type> s{
ioc.get_executor()};
net::post(s,
bind_handler(test_cb{}, 42));
2018-12-11 13:35:35 -08:00
ioc.run();
}
2019-01-09 09:52:19 -08:00
// legacy hooks
legacy_handler::test(
2019-01-09 09:52:19 -08:00
[](legacy_handler h)
{
return bind_handler(h);
});
}
void
testBindFrontHandler()
{
2018-12-11 13:35:35 -08:00
using m1 = move_arg<1>;
using m2 = move_arg<2>;
// 0-ary
bind_front_handler(test_cb{})();
2018-12-11 13:35:35 -08:00
// 1-ary
bind_front_handler(test_cb{}, 42)();
bind_front_handler(test_cb{})(42);
2018-12-11 13:35:35 -08:00
// 2-ary
bind_front_handler(test_cb{}, 42, "s")();
bind_front_handler(test_cb{}, 42)("s");
bind_front_handler(test_cb{})(42, "s");
2018-12-11 13:35:35 -08:00
// 3-ary
bind_front_handler(test_cb{}, 42, "s", m1{})();
bind_front_handler(test_cb{}, 42, "s")(m1{});
bind_front_handler(test_cb{}, 42)("s", m1{});
bind_front_handler(test_cb{})(42, "s", m1{});
2018-12-11 13:35:35 -08:00
// 4-ary
bind_front_handler(test_cb{}, 42, "s", m1{}, m2{})();
bind_front_handler(test_cb{}, 42, "s", m1{})(m2{});
bind_front_handler(test_cb{}, 42, "s")(m1{}, m2{});
bind_front_handler(test_cb{}, 42)("s", m1{}, m2{});
bind_front_handler(test_cb{})(42, "s", m1{}, m2{});
2018-12-11 13:35:35 -08:00
error_code ec;
std::size_t n = 256;
2018-12-11 13:35:35 -08:00
// void(error_code, size_t)
bind_front_handler(test_cb{}, ec, n)();
2018-12-11 13:35:35 -08:00
// void(error_code, size_t)(string_view)
bind_front_handler(test_cb{}, ec, n)("s");
2018-12-11 13:35:35 -08:00
// perfect forwarding
{
std::shared_ptr<int> const sp =
std::make_shared<int>(42);
bind_front_handler(test_cb{}, sp)();
2018-12-11 13:35:35 -08:00
BEAST_EXPECT(sp.get() != nullptr);
}
2018-12-11 13:35:35 -08:00
// associated executor
{
net::io_context ioc;
2018-12-11 13:35:35 -08:00
testHooks(ioc, bind_front_handler(net::bind_executor(
test_executor(*this, ioc), test_cb{})
2018-12-11 13:35:35 -08:00
));
testHooks(ioc, bind_front_handler(net::bind_executor(
test_executor(*this, ioc), test_cb{}),
2018-12-11 13:35:35 -08:00
42));
testHooks(ioc, bind_front_handler(net::bind_executor(
test_executor(*this, ioc), test_cb{}),
2018-12-11 13:35:35 -08:00
42, "s"));
testHooks(ioc, bind_front_handler(net::bind_executor(
test_executor(*this, ioc), test_cb{}),
2018-12-11 13:35:35 -08:00
42, "s", m1{}));
testHooks(ioc, bind_front_handler(net::bind_executor(
test_executor(*this, ioc), test_cb{}),
2018-12-11 13:35:35 -08:00
42, "s", m1{}, m2{}));
testHooks(ioc, bind_front_handler(net::bind_executor(
test_executor(*this, ioc), test_cb{}),
2018-12-11 13:35:35 -08:00
ec, n));
}
2019-01-09 09:52:19 -08:00
// legacy hooks
legacy_handler::test(
2019-01-09 09:52:19 -08:00
[](legacy_handler h)
{
return bind_front_handler(h);
});
legacy_handler::test(
2019-01-09 09:52:19 -08:00
[](legacy_handler h)
{
return bind_front_handler(
h, error_code{}, std::size_t{});
});
}
2019-01-09 09:52:19 -08:00
//--------------------------------------------------------------------------
template <class AsyncReadStream, class ReadHandler>
void
signal_aborted (AsyncReadStream& stream, ReadHandler&& handler)
{
net::post(
stream.get_executor(),
bind_handler (std::forward <ReadHandler> (handler),
net::error::operation_aborted, 0));
}
template <class AsyncReadStream, class ReadHandler>
void
signal_eof (AsyncReadStream& stream, ReadHandler&& handler)
{
net::post(
stream.get_executor(),
bind_front_handler (std::forward<ReadHandler> (handler),
net::error::eof, 0));
}
void
testJavadocs()
{
BEAST_EXPECT((
&bind_handler_test::signal_aborted<
test::stream, handler<error_code, std::size_t>>));
BEAST_EXPECT((
&bind_handler_test::signal_eof<
test::stream, handler<error_code, std::size_t>>));
}
//--------------------------------------------------------------------------
2017-07-19 09:50:16 -07:00
void
run() override
2017-07-20 08:01:46 -07:00
{
testBindHandler();
testBindFrontHandler();
2019-01-09 09:52:19 -08:00
testJavadocs();
2017-07-20 08:01:46 -07:00
}
};
2017-08-01 17:01:57 -07:00
BEAST_DEFINE_TESTSUITE(beast,core,bind_handler);
2017-07-20 08:01:46 -07:00
} // beast
2017-07-20 13:40:34 -07:00
} // boost