// // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail 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) // // Official repository: https://github.com/boostorg/beast // // Test that header file is self-contained. #include #include #include #include #include #include #include #include #include namespace boost { namespace beast { class stream_traits_test : public beast::unit_test::suite { public: struct without { int dummy = 0; without() = default; template std::size_t write_some(T const&) { return 0; } template std::size_t write_some(T const&, boost::system::error_code&) { return 0; } }; template struct with { T t; with() = default; T& next_layer() { return t; } T const& next_layer() const { return t; } }; BOOST_STATIC_ASSERT( ! detail::has_next_layer::value); BOOST_STATIC_ASSERT( detail::has_next_layer>::value); BOOST_STATIC_ASSERT( detail::has_next_layer>>::value); void testGetLowestLayer() { { without w{}; BEAST_EXPECT(&get_lowest_layer(w) == &w); } { without const w{}; BEAST_EXPECT(&get_lowest_layer(w) == &w); } { with w{}; BEAST_EXPECT(&get_lowest_layer(w) == &w.t); } { with const w{}; BEAST_EXPECT(&get_lowest_layer(w) == &w.t); } { with> w{}; BEAST_EXPECT(&get_lowest_layer(w) == &w.t.t); } { with> const w{}; BEAST_EXPECT(&get_lowest_layer(w) == &w.t.t); } { with>> w{}; BEAST_EXPECT(&get_lowest_layer(w) == &w.t.t.t); } { with>> const w{}; BEAST_EXPECT(&get_lowest_layer(w) == &w.t.t.t); } } //-------------------------------------------------------------------------- /* @par Example This code implements a SyncWriteStream wrapper which calls `std::terminate` upon any error. */ template class write_stream { NextLayer next_layer_; public: static_assert(is_sync_write_stream::value, "SyncWriteStream type requirements not met"); template explicit write_stream(Args&&... args) : next_layer_(std::forward(args)...) { } NextLayer& next_layer() noexcept { return next_layer_; } NextLayer const& next_layer() const noexcept { return next_layer_; } template std::size_t write_some(ConstBufferSequence const& buffers) { error_code ec; auto const bytes_transferred = next_layer_.write_some(buffers, ec); if(ec) std::terminate(); return bytes_transferred; } template std::size_t write_some(ConstBufferSequence const& buffers, error_code& ec) { auto const bytes_transferred = next_layer_.write_some(buffers, ec); if(ec) std::terminate(); return bytes_transferred; } }; void testGetLowestLayerJavadoc() { write_stream s; BOOST_STATIC_ASSERT( is_sync_write_stream::value); BOOST_STATIC_ASSERT(std::is_same< decltype(get_lowest_layer(s)), without&>::value); #if 0 BEAST_EXPECT(static_cast< std::size_t(type::*)(net::const_buffer)>( &type::write_some)); #endif } //-------------------------------------------------------------------------- void testExecutorType() { } void testExecutorTypeJavadoc() { } //-------------------------------------------------------------------------- struct sync_read_stream { template std::size_t read_some(MutableBufferSequence const&); template std::size_t read_some(MutableBufferSequence const&, error_code& ec); }; struct sync_write_stream { template std::size_t write_some(ConstBufferSequence const&); template std::size_t write_some(ConstBufferSequence const&, error_code&); }; struct async_read_stream { net::io_context::executor_type get_executor() noexcept; template void async_read_some(MutableBufferSequence const&, ReadHandler&&); }; struct async_write_stream { net::io_context::executor_type get_executor() noexcept; template void async_write_some(ConstBufferSequence const&, WriteHandler&&); }; struct sync_stream : sync_read_stream, sync_write_stream { }; struct async_stream : async_read_stream, async_write_stream { net::io_context::executor_type get_executor() noexcept; template void async_read_some(MutableBufferSequence const&, ReadHandler&&); template void async_write_some(ConstBufferSequence const&, WriteHandler&&); }; BOOST_STATIC_ASSERT(is_sync_read_stream::value); BOOST_STATIC_ASSERT(is_sync_read_stream::value); BOOST_STATIC_ASSERT(is_sync_write_stream::value); BOOST_STATIC_ASSERT(is_sync_write_stream::value); BOOST_STATIC_ASSERT(is_sync_stream::value); BOOST_STATIC_ASSERT(! is_sync_read_stream::value); BOOST_STATIC_ASSERT(! is_sync_write_stream::value); BOOST_STATIC_ASSERT(! is_sync_stream::value); BOOST_STATIC_ASSERT(has_get_executor::value); BOOST_STATIC_ASSERT(has_get_executor::value); BOOST_STATIC_ASSERT(has_get_executor::value); BOOST_STATIC_ASSERT(! has_get_executor::value); BOOST_STATIC_ASSERT(! has_get_executor::value); BOOST_STATIC_ASSERT(! has_get_executor::value); BOOST_STATIC_ASSERT(is_async_read_stream::value); BOOST_STATIC_ASSERT(is_async_read_stream::value); #if BOOST_WORKAROUND(BOOST_MSVC, < 1910) BOOST_STATIC_ASSERT(is_async_write_stream::value); #else BOOST_STATIC_ASSERT(is_async_write_stream::value); #endif BOOST_STATIC_ASSERT(is_async_write_stream::value); BOOST_STATIC_ASSERT(is_async_stream::value); BOOST_STATIC_ASSERT(! is_async_write_stream::value); BOOST_STATIC_ASSERT(! is_async_read_stream::value); BOOST_STATIC_ASSERT(! is_async_stream::value); //-------------------------------------------------------------------------- template struct layer { T t; template explicit layer(U&& u) : t(std::forward(u)) { } T& next_layer() { return t; } }; void testClose() { net::io_context ioc; { net::ip::tcp::socket sock(ioc); sock.open(net::ip::tcp::v4()); BEAST_EXPECT(sock.is_open()); close_socket(get_lowest_layer(sock)); BEAST_EXPECT(! sock.is_open()); } { using type = layer; type layer(ioc); layer.next_layer().open(net::ip::tcp::v4()); BEAST_EXPECT(layer.next_layer().is_open()); BOOST_STATIC_ASSERT(detail::has_next_layer::value); BOOST_STATIC_ASSERT((std::is_same< typename std::decay::type, lowest_layer_type>::value)); BOOST_STATIC_ASSERT(std::is_same::value); BOOST_STATIC_ASSERT(std::is_same>::value); close_socket(get_lowest_layer(layer)); BEAST_EXPECT(! layer.next_layer().is_open()); } { test::stream ts(ioc); close_socket(ts); } } //-------------------------------------------------------------------------- template void hello_and_close (WriteStream& stream) { net::write(stream, net::const_buffer("Hello, world!", 13)); close_socket(get_lowest_layer(stream)); } class my_socket { net::ip::tcp::socket sock_; public: my_socket(net::io_context& ioc) : sock_(ioc) { } friend void beast_close_socket(my_socket& s) { error_code ec; s.sock_.close(ec); // ignore the error } }; void testCloseJavadoc() { BEAST_EXPECT(&stream_traits_test::template hello_and_close); { net::io_context ioc; my_socket s(ioc); close_socket(s); } } //-------------------------------------------------------------------------- void run() override { testGetLowestLayer(); testGetLowestLayerJavadoc(); testExecutorType(); testExecutorTypeJavadoc(); testClose(); testCloseJavadoc(); } }; BEAST_DEFINE_TESTSUITE(beast,core,stream_traits); } // beast } // boost