mirror of
https://github.com/boostorg/beast.git
synced 2025-08-01 05:44:38 +02:00
Tidy up bind_handler tests
This commit is contained in:
@@ -9,6 +9,7 @@ Version 198:
|
|||||||
* Tidy up experimental files
|
* Tidy up experimental files
|
||||||
* Tidy up core files
|
* Tidy up core files
|
||||||
* Fix bind_handler, bind_front_handler
|
* Fix bind_handler, bind_front_handler
|
||||||
|
* Improved handler bind wrapper tests
|
||||||
|
|
||||||
API Changes:
|
API Changes:
|
||||||
|
|
||||||
|
@@ -11,15 +11,24 @@
|
|||||||
#include <boost/beast/core/bind_handler.hpp>
|
#include <boost/beast/core/bind_handler.hpp>
|
||||||
|
|
||||||
#include <boost/beast/core/detail/type_traits.hpp>
|
#include <boost/beast/core/detail/type_traits.hpp>
|
||||||
#include <boost/beast/_experimental/test/stream.hpp>
|
|
||||||
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
#include <boost/beast/_experimental/unit_test/suite.hpp>
|
||||||
#include <boost/asio/io_context.hpp>
|
#include <boost/asio/io_context.hpp>
|
||||||
|
#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>
|
#include <boost/asio/strand.hpp>
|
||||||
|
#include <boost/bind/placeholders.hpp>
|
||||||
|
#include <boost/core/exchange.hpp>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace beast {
|
namespace beast {
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
class bind_handler_test : public unit_test::suite
|
class bind_handler_test : public unit_test::suite
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -49,53 +58,324 @@ public:
|
|||||||
void operator()() const{};
|
void operator()() const{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 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
|
void
|
||||||
callback(int v)
|
callback(int v)
|
||||||
{
|
{
|
||||||
BEAST_EXPECT(v == 42);
|
BEAST_EXPECT(v == 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class test_executor
|
||||||
|
{
|
||||||
|
bind_handler_test& s_;
|
||||||
|
net::io_context::executor_type ex_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
test_executor(
|
||||||
|
test_executor const&) = default;
|
||||||
|
|
||||||
|
test_executor(
|
||||||
|
bind_handler_test& s,
|
||||||
|
net::io_context& ioc)
|
||||||
|
: s_(s)
|
||||||
|
, ex_(ioc.get_executor())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(
|
||||||
|
test_executor const& other) const noexcept
|
||||||
|
{
|
||||||
|
return ex_ == other.ex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(
|
||||||
|
test_executor const& other) const noexcept
|
||||||
|
{
|
||||||
|
return ex_ != other.ex_;
|
||||||
|
}
|
||||||
|
|
||||||
|
net::io_context&
|
||||||
|
context() const noexcept
|
||||||
|
{
|
||||||
|
return ex_.context();
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_work_started() const noexcept
|
||||||
|
{
|
||||||
|
ex_.on_work_started();
|
||||||
|
}
|
||||||
|
|
||||||
|
void on_work_finished() const noexcept
|
||||||
|
{
|
||||||
|
ex_.on_work_finished();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F, class Alloc>
|
||||||
|
void dispatch(F&& f, Alloc const& a)
|
||||||
|
{
|
||||||
|
s_.on_invoke();
|
||||||
|
ex_.dispatch(std::forward<F>(f), a);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F, class Alloc>
|
||||||
|
void post(F&& f, Alloc const& a)
|
||||||
|
{
|
||||||
|
// shouldn't be called since the enclosing
|
||||||
|
// networking wrapper only uses dispatch
|
||||||
|
s_.fail("unexpected post", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class F, class Alloc>
|
||||||
|
void defer(F&& f, Alloc const& a)
|
||||||
|
{
|
||||||
|
// shouldn't be called since the enclosing
|
||||||
|
// networking wrapper only uses dispatch
|
||||||
|
s_.fail("unexpected defer", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class test_cb
|
||||||
|
{
|
||||||
|
bind_handler_test& s_;
|
||||||
|
bool fail_ = true;
|
||||||
|
|
||||||
|
public:
|
||||||
|
test_cb(test_cb const&) = delete;
|
||||||
|
|
||||||
|
test_cb(bind_handler_test& s)
|
||||||
|
: s_(s)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
test_cb(test_cb&& other)
|
||||||
|
: s_(other.s_)
|
||||||
|
, fail_(boost::exchange(
|
||||||
|
other.fail_, false))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~test_cb()
|
||||||
|
{
|
||||||
|
if(fail_)
|
||||||
|
s_.fail("handler not invoked",
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()()
|
||||||
|
{
|
||||||
|
fail_ = false;
|
||||||
|
s_.pass();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(int v)
|
||||||
|
{
|
||||||
|
fail_ = false;
|
||||||
|
s_.expect(
|
||||||
|
v == 42, __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(int v, string_view s)
|
||||||
|
{
|
||||||
|
fail_ = false;
|
||||||
|
s_.expect(
|
||||||
|
v == 42, __FILE__, __LINE__);
|
||||||
|
s_.expect(
|
||||||
|
s == "s", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(int v, string_view s, move_arg<1>)
|
||||||
|
{
|
||||||
|
fail_ = false;
|
||||||
|
s_.expect(
|
||||||
|
v == 42, __FILE__, __LINE__);
|
||||||
|
s_.expect(
|
||||||
|
s == "s", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(int v, string_view s, move_arg<1>, move_arg<2>)
|
||||||
|
{
|
||||||
|
fail_ = false;
|
||||||
|
s_.expect(
|
||||||
|
v == 42, __FILE__, __LINE__);
|
||||||
|
s_.expect(
|
||||||
|
s == "s", __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(error_code, std::size_t n)
|
||||||
|
{
|
||||||
|
fail_ = false;
|
||||||
|
s_.expect(
|
||||||
|
n == 256, __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(
|
||||||
|
error_code, std::size_t n, string_view s)
|
||||||
|
{
|
||||||
|
boost::ignore_unused(s);
|
||||||
|
fail_ = false;
|
||||||
|
s_.expect(
|
||||||
|
n == 256, __FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
operator()(std::shared_ptr<int> const& sp)
|
||||||
|
{
|
||||||
|
fail_ = false;
|
||||||
|
s_.expect(sp.get() != nullptr,
|
||||||
|
__FILE__, __LINE__);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// This function should fail to compile
|
// These functions should fail to compile
|
||||||
|
|
||||||
void
|
void
|
||||||
failStdBind()
|
failStdBind()
|
||||||
{
|
{
|
||||||
std::bind(bind_handler(handler<>{}));
|
std::bind(bind_handler(test_cb{*this}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
failStdBindFront()
|
failStdBindFront()
|
||||||
{
|
{
|
||||||
std::bind(bind_front_handler(handler<>{}));
|
std::bind(bind_front_handler(test_cb{*this}));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
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_);
|
||||||
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------
|
||||||
|
|
||||||
void
|
void
|
||||||
testBindHandler()
|
testBindHandler()
|
||||||
{
|
{
|
||||||
// invocation
|
using m1 = move_arg<1>;
|
||||||
{
|
using m2 = move_arg<2>;
|
||||||
auto f = bind_handler(std::bind(
|
|
||||||
&bind_handler_test::callback, this,
|
|
||||||
std::placeholders::_1), 42);
|
|
||||||
f();
|
|
||||||
|
|
||||||
|
{
|
||||||
|
using namespace std::placeholders;
|
||||||
|
|
||||||
|
// 0-ary
|
||||||
|
bind_handler(test_cb{*this})();
|
||||||
|
|
||||||
|
// 1-ary
|
||||||
|
bind_handler(test_cb{*this}, 42)();
|
||||||
|
bind_handler(test_cb{*this}, _1)(42);
|
||||||
|
bind_handler(test_cb{*this}, _2)(0, 42);
|
||||||
|
|
||||||
|
// 2-ary
|
||||||
|
bind_handler(test_cb{*this}, 42, "s")();
|
||||||
|
bind_handler(test_cb{*this}, 42, "s")(0);
|
||||||
|
bind_handler(test_cb{*this}, _1, "s")(42);
|
||||||
|
bind_handler(test_cb{*this}, 42, _1) ("s");
|
||||||
|
bind_handler(test_cb{*this}, _1, _2)(42, "s");
|
||||||
|
bind_handler(test_cb{*this}, _1, _2)(42, "s", "X");
|
||||||
|
bind_handler(test_cb{*this}, _2, _1)("s", 42);
|
||||||
|
bind_handler(test_cb{*this}, _3, _2)("X", "s", 42);
|
||||||
|
|
||||||
|
// 3-ary
|
||||||
|
bind_handler(test_cb{*this}, 42, "s")(m1{});
|
||||||
|
bind_handler(test_cb{*this}, 42, "s", _1)(m1{});
|
||||||
|
bind_handler(test_cb{*this}, 42, _1, m1{})("s");
|
||||||
|
|
||||||
|
// 4-ary
|
||||||
|
bind_handler(test_cb{*this}, 42, "s")(m1{}, m2{});
|
||||||
|
bind_handler(test_cb{*this}, 42, "s", m1{})(m2{});
|
||||||
|
bind_handler(test_cb{*this}, 42, "s", m1{}, m2{})();
|
||||||
|
bind_handler(test_cb{*this}, 42, _1, m1{})("s", m2{});
|
||||||
|
bind_handler(test_cb{*this}, _3, _1, m1{})("s", m2{}, 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
// placeholders
|
|
||||||
{
|
{
|
||||||
namespace ph = std::placeholders;
|
using namespace boost::placeholders;
|
||||||
bind_handler(handler<>{})();
|
|
||||||
bind_handler(handler<int>{}, 1)();
|
// 0-ary
|
||||||
bind_handler(handler<int, std::string>{}, 1, "hello")();
|
bind_handler(test_cb{*this})();
|
||||||
bind_handler(handler<int>{}, ph::_1)(1);
|
|
||||||
bind_handler(handler<int, std::string>{}, ph::_1, ph::_2)(1, "hello");
|
// 1-ary
|
||||||
|
bind_handler(test_cb{*this}, 42)();
|
||||||
|
bind_handler(test_cb{*this}, _1)(42);
|
||||||
|
bind_handler(test_cb{*this}, _2)(0, 42);
|
||||||
|
|
||||||
|
// 2-ary
|
||||||
|
bind_handler(test_cb{*this}, 42, "s")();
|
||||||
|
bind_handler(test_cb{*this}, 42, "s")(0);
|
||||||
|
bind_handler(test_cb{*this}, _1, "s")(42);
|
||||||
|
bind_handler(test_cb{*this}, 42, _1) ("s");
|
||||||
|
bind_handler(test_cb{*this}, _1, _2)(42, "s");
|
||||||
|
bind_handler(test_cb{*this}, _1, _2)(42, "s", "X");
|
||||||
|
bind_handler(test_cb{*this}, _2, _1)("s", 42);
|
||||||
|
bind_handler(test_cb{*this}, _3, _2)("X", "s", 42);
|
||||||
|
|
||||||
|
// 3-ary
|
||||||
|
bind_handler(test_cb{*this}, 42, "s")(m1{});
|
||||||
|
bind_handler(test_cb{*this}, 42, "s", _1)(m1{});
|
||||||
|
bind_handler(test_cb{*this}, 42, _1, m1{})("s");
|
||||||
|
|
||||||
|
// 4-ary
|
||||||
|
bind_handler(test_cb{*this}, 42, "s")(m1{}, m2{});
|
||||||
|
bind_handler(test_cb{*this}, 42, "s", m1{})(m2{});
|
||||||
|
bind_handler(test_cb{*this}, 42, "s", m1{}, m2{})();
|
||||||
|
bind_handler(test_cb{*this}, 42, _1, m1{})("s", m2{});
|
||||||
|
bind_handler(test_cb{*this}, _3, _1, m1{})("s", m2{}, 42);
|
||||||
}
|
}
|
||||||
|
|
||||||
// move-only
|
// perfect forwarding
|
||||||
{
|
{
|
||||||
bind_handler([](move_only){}, move_only{})();
|
std::shared_ptr<int> const sp =
|
||||||
bind_handler([](move_only){}, std::placeholders::_1)(move_only{});
|
std::make_shared<int>(42);
|
||||||
bind_handler([](move_only, move_only){}, move_only{}, std::placeholders::_1)(move_only{});
|
{
|
||||||
|
bind_handler(test_cb{*this}, sp)();
|
||||||
|
BEAST_EXPECT(sp.get() != nullptr);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
bind_handler(test_cb{*this})(sp);
|
||||||
|
BEAST_EXPECT(sp.get() != nullptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// associated executor
|
||||||
|
{
|
||||||
|
net::io_context ioc;
|
||||||
|
testHooks(ioc, bind_handler(net::bind_executor(
|
||||||
|
test_executor(*this, ioc), test_cb{*this})));
|
||||||
}
|
}
|
||||||
|
|
||||||
// asio_handler_invoke
|
// asio_handler_invoke
|
||||||
@@ -107,80 +387,82 @@ public:
|
|||||||
net::strand<
|
net::strand<
|
||||||
net::io_context::executor_type> s{
|
net::io_context::executor_type> s{
|
||||||
ioc.get_executor()};
|
ioc.get_executor()};
|
||||||
test::stream ts{ioc};
|
|
||||||
net::post(s,
|
net::post(s,
|
||||||
bind_handler(copyable{}, 42));
|
bind_handler(test_cb{*this}, 42));
|
||||||
|
ioc.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
testBindFrontHandler()
|
testBindFrontHandler()
|
||||||
{
|
{
|
||||||
// invocation
|
using m1 = move_arg<1>;
|
||||||
{
|
using m2 = move_arg<2>;
|
||||||
bind_front_handler(
|
|
||||||
std::bind(
|
|
||||||
&bind_handler_test::callback,
|
|
||||||
this,
|
|
||||||
42));
|
|
||||||
|
|
||||||
bind_front_handler(
|
// 0-ary
|
||||||
std::bind(
|
bind_front_handler(test_cb{*this})();
|
||||||
&bind_handler_test::callback,
|
|
||||||
this,
|
|
||||||
std::placeholders::_1), 42);
|
|
||||||
|
|
||||||
bind_front_handler(
|
// 1-ary
|
||||||
std::bind(
|
bind_front_handler(test_cb{*this}, 42)();
|
||||||
&bind_handler_test::callback,
|
bind_front_handler(test_cb{*this})(42);
|
||||||
this,
|
|
||||||
std::placeholders::_1))(42);
|
|
||||||
|
|
||||||
bind_front_handler(
|
// 2-ary
|
||||||
bind_front_handler(
|
bind_front_handler(test_cb{*this}, 42, "s")();
|
||||||
std::bind(
|
bind_front_handler(test_cb{*this}, 42)("s");
|
||||||
&bind_handler_test::callback,
|
bind_front_handler(test_cb{*this})(42, "s");
|
||||||
this,
|
|
||||||
std::placeholders::_1)),
|
|
||||||
42);
|
|
||||||
|
|
||||||
bind_front_handler(
|
// 3-ary
|
||||||
bind_front_handler(
|
bind_front_handler(test_cb{*this}, 42, "s", m1{})();
|
||||||
std::bind(
|
bind_front_handler(test_cb{*this}, 42, "s")(m1{});
|
||||||
&bind_handler_test::callback,
|
bind_front_handler(test_cb{*this}, 42)("s", m1{});
|
||||||
this,
|
bind_front_handler(test_cb{*this})(42, "s", m1{});
|
||||||
std::placeholders::_1)))(42);
|
|
||||||
}
|
|
||||||
|
|
||||||
// move-only
|
// 4-ary
|
||||||
{
|
bind_front_handler(test_cb{*this}, 42, "s", m1{}, m2{})();
|
||||||
bind_front_handler([]{});
|
bind_front_handler(test_cb{*this}, 42, "s", m1{})(m2{});
|
||||||
}
|
bind_front_handler(test_cb{*this}, 42, "s")(m1{}, m2{});
|
||||||
|
bind_front_handler(test_cb{*this}, 42)("s", m1{}, m2{});
|
||||||
|
bind_front_handler(test_cb{*this})(42, "s", m1{}, m2{});
|
||||||
|
|
||||||
|
error_code ec;
|
||||||
|
std::size_t n = 256;
|
||||||
|
|
||||||
// specializations
|
// void(error_code, size_t)
|
||||||
{
|
bind_front_handler(test_cb{*this}, ec, n)();
|
||||||
bind_front_handler(copyable{});
|
|
||||||
bind_front_handler(copyable{}, 1);
|
|
||||||
bind_front_handler(copyable{}, 1, 2);
|
|
||||||
bind_front_handler(copyable{}, 1, 2, 3);
|
|
||||||
bind_front_handler(copyable{}, 1, 2, 3, 4);
|
|
||||||
|
|
||||||
bind_front_handler(copyable{},
|
// void(error_code, size_t)(string_view)
|
||||||
error_code{}, std::size_t(4));
|
bind_front_handler(test_cb{*this}, ec, n)("s");
|
||||||
|
|
||||||
|
// perfect forwarding
|
||||||
|
{
|
||||||
|
std::shared_ptr<int> const sp =
|
||||||
|
std::make_shared<int>(42);
|
||||||
|
bind_front_handler(test_cb{*this}, sp)();
|
||||||
|
BEAST_EXPECT(sp.get() != nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
// asio_handler_invoke
|
// associated executor
|
||||||
{
|
{
|
||||||
// make sure things compile, also can set a
|
|
||||||
// breakpoint in asio_handler_invoke to make sure
|
|
||||||
// it is instantiated.
|
|
||||||
net::io_context ioc;
|
net::io_context ioc;
|
||||||
net::strand<
|
|
||||||
net::io_context::executor_type> s{
|
testHooks(ioc, bind_front_handler(net::bind_executor(
|
||||||
ioc.get_executor()};
|
test_executor(*this, ioc), test_cb{*this})
|
||||||
test::stream ts{ioc};
|
));
|
||||||
net::post(s,
|
testHooks(ioc, bind_front_handler(net::bind_executor(
|
||||||
bind_front_handler(copyable{}, 42));
|
test_executor(*this, ioc), test_cb{*this}),
|
||||||
|
42));
|
||||||
|
testHooks(ioc, bind_front_handler(net::bind_executor(
|
||||||
|
test_executor(*this, ioc), test_cb{*this}),
|
||||||
|
42, "s"));
|
||||||
|
testHooks(ioc, bind_front_handler(net::bind_executor(
|
||||||
|
test_executor(*this, ioc), test_cb{*this}),
|
||||||
|
42, "s", m1{}));
|
||||||
|
testHooks(ioc, bind_front_handler(net::bind_executor(
|
||||||
|
test_executor(*this, ioc), test_cb{*this}),
|
||||||
|
42, "s", m1{}, m2{}));
|
||||||
|
testHooks(ioc, bind_front_handler(net::bind_executor(
|
||||||
|
test_executor(*this, ioc), test_cb{*this}),
|
||||||
|
ec, n));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user