1 // 2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 // 7 // Official repository: https://github.com/boostorg/beast 8 // 9 10 // Test that header file is self-contained. 11 #include <boost/beast/core/stream_traits.hpp> 12 13 #include <boost/beast/_experimental/unit_test/suite.hpp> 14 #include <boost/beast/core/error.hpp> 15 #include <boost/beast/_experimental/test/stream.hpp> 16 #include <boost/beast/core/string.hpp> 17 #include <boost/asio/io_context.hpp> 18 #include <boost/asio/ip/tcp.hpp> 19 #include <boost/asio/write.hpp> 20 #include <utility> 21 22 namespace boost { 23 namespace beast { 24 25 class stream_traits_test 26 : public beast::unit_test::suite 27 { 28 public: 29 struct without 30 { 31 int dummy = 0; 32 33 without() = default; 34 35 template<class T> write_someboost::beast::stream_traits_test::without36 std::size_t write_some(T const&) 37 { 38 return 0; 39 } 40 41 template<class T> write_someboost::beast::stream_traits_test::without42 std::size_t write_some(T const&, boost::system::error_code&) 43 { 44 return 0; 45 } 46 }; 47 48 template<class T> 49 struct with 50 { 51 T t; 52 53 with() = default; 54 55 T& next_layerboost::beast::stream_traits_test::with56 next_layer() 57 { 58 return t; 59 } 60 61 T const& next_layerboost::beast::stream_traits_test::with62 next_layer() const 63 { 64 return t; 65 } 66 }; 67 68 BOOST_STATIC_ASSERT( 69 ! detail::has_next_layer<without>::value); 70 71 BOOST_STATIC_ASSERT( 72 detail::has_next_layer<with<without>>::value); 73 74 BOOST_STATIC_ASSERT( 75 detail::has_next_layer<with<with<without>>>::value); 76 77 void testGetLowestLayer()78 testGetLowestLayer() 79 { 80 { 81 without w{}; 82 BEAST_EXPECT(&get_lowest_layer(w) == &w); 83 } 84 { 85 without const w{}; 86 BEAST_EXPECT(&get_lowest_layer(w) == &w); 87 } 88 { 89 with<without> w{}; 90 BEAST_EXPECT(&get_lowest_layer(w) == &w.t); 91 } 92 { 93 with<without> const w{}; 94 BEAST_EXPECT(&get_lowest_layer(w) == &w.t); 95 } 96 { 97 with<with<without>> w{}; 98 BEAST_EXPECT(&get_lowest_layer(w) == &w.t.t); 99 } 100 { 101 with<with<without>> const w{}; 102 BEAST_EXPECT(&get_lowest_layer(w) == &w.t.t); 103 } 104 { 105 with<with<with<without>>> w{}; 106 BEAST_EXPECT(&get_lowest_layer(w) == &w.t.t.t); 107 } 108 { 109 with<with<with<without>>> const w{}; 110 BEAST_EXPECT(&get_lowest_layer(w) == &w.t.t.t); 111 } 112 } 113 114 //-------------------------------------------------------------------------- 115 /* 116 @par Example 117 This code implements a <em>SyncWriteStream</em> wrapper which calls 118 `std::terminate` upon any error. 119 */ 120 template <class NextLayer> 121 class write_stream 122 { 123 NextLayer next_layer_; 124 125 public: 126 static_assert(is_sync_write_stream<NextLayer>::value, 127 "SyncWriteStream type requirements not met"); 128 129 template<class... Args> 130 explicit write_stream(Args &&...args)131 write_stream(Args&&... args) 132 : next_layer_(std::forward<Args>(args)...) 133 { 134 } 135 next_layer()136 NextLayer& next_layer() noexcept 137 { 138 return next_layer_; 139 } 140 next_layer() const141 NextLayer const& next_layer() const noexcept 142 { 143 return next_layer_; 144 } 145 146 template<class ConstBufferSequence> 147 std::size_t write_some(ConstBufferSequence const & buffers)148 write_some(ConstBufferSequence const& buffers) 149 { 150 error_code ec; 151 auto const bytes_transferred = next_layer_.write_some(buffers, ec); 152 if(ec) 153 std::terminate(); 154 return bytes_transferred; 155 } 156 157 template<class ConstBufferSequence> 158 std::size_t write_some(ConstBufferSequence const & buffers,error_code & ec)159 write_some(ConstBufferSequence const& buffers, error_code& ec) 160 { 161 auto const bytes_transferred = next_layer_.write_some(buffers, ec); 162 if(ec) 163 std::terminate(); 164 return bytes_transferred; 165 } 166 }; 167 168 void testGetLowestLayerJavadoc()169 testGetLowestLayerJavadoc() 170 { 171 write_stream<without> s; 172 BOOST_STATIC_ASSERT( 173 is_sync_write_stream<without>::value); 174 BOOST_STATIC_ASSERT(std::is_same< 175 decltype(get_lowest_layer(s)), without&>::value); 176 177 #if 0 178 BEAST_EXPECT(static_cast< 179 std::size_t(type::*)(net::const_buffer)>( 180 &type::write_some<net::const_buffer>)); 181 #endif 182 } 183 184 //-------------------------------------------------------------------------- 185 186 void testExecutorType()187 testExecutorType() 188 { 189 } 190 191 void testExecutorTypeJavadoc()192 testExecutorTypeJavadoc() 193 { 194 } 195 196 //-------------------------------------------------------------------------- 197 198 struct sync_read_stream 199 { 200 template<class MutableBufferSequence> 201 std::size_t read_some(MutableBufferSequence const&); 202 template<class MutableBufferSequence> 203 std::size_t read_some(MutableBufferSequence const&, error_code& ec); 204 }; 205 206 struct sync_write_stream 207 { 208 template<class ConstBufferSequence> 209 std::size_t write_some(ConstBufferSequence const&); 210 template<class ConstBufferSequence> 211 std::size_t write_some(ConstBufferSequence const&, error_code&); 212 }; 213 214 struct async_read_stream 215 { 216 net::io_context::executor_type get_executor() noexcept; 217 template<class MutableBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler> 218 void async_read_some(MutableBufferSequence const&, ReadHandler&&); 219 }; 220 221 struct async_write_stream 222 { 223 net::io_context::executor_type get_executor() noexcept; 224 template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler> 225 void async_write_some(ConstBufferSequence const&, WriteHandler&&); 226 }; 227 228 struct sync_stream : sync_read_stream, sync_write_stream 229 { 230 }; 231 232 struct async_stream : async_read_stream, async_write_stream 233 { 234 net::io_context::executor_type get_executor() noexcept; 235 template<class MutableBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 ReadHandler> 236 void async_read_some(MutableBufferSequence const&, ReadHandler&&); 237 template<class ConstBufferSequence, BOOST_BEAST_ASYNC_TPARAM2 WriteHandler> 238 void async_write_some(ConstBufferSequence const&, WriteHandler&&); 239 }; 240 241 BOOST_STATIC_ASSERT(is_sync_read_stream<sync_read_stream>::value); 242 BOOST_STATIC_ASSERT(is_sync_read_stream<sync_stream>::value); 243 BOOST_STATIC_ASSERT(is_sync_write_stream<sync_write_stream>::value); 244 BOOST_STATIC_ASSERT(is_sync_write_stream<sync_stream>::value); 245 BOOST_STATIC_ASSERT(is_sync_stream<sync_stream>::value); 246 247 BOOST_STATIC_ASSERT(! is_sync_read_stream<sync_write_stream>::value); 248 BOOST_STATIC_ASSERT(! is_sync_write_stream<sync_read_stream>::value); 249 BOOST_STATIC_ASSERT(! is_sync_stream<async_stream>::value); 250 251 BOOST_STATIC_ASSERT(has_get_executor<async_read_stream>::value); 252 BOOST_STATIC_ASSERT(has_get_executor<async_write_stream>::value); 253 BOOST_STATIC_ASSERT(has_get_executor<async_stream>::value); 254 255 BOOST_STATIC_ASSERT(! has_get_executor<sync_read_stream>::value); 256 BOOST_STATIC_ASSERT(! has_get_executor<sync_write_stream>::value); 257 BOOST_STATIC_ASSERT(! has_get_executor<sync_stream>::value); 258 259 BOOST_STATIC_ASSERT(is_async_read_stream<async_read_stream>::value); 260 BOOST_STATIC_ASSERT(is_async_read_stream<async_stream>::value); 261 #if BOOST_WORKAROUND(BOOST_MSVC, < 1910) 262 BOOST_STATIC_ASSERT(is_async_write_stream<net::ip::tcp::socket>::value); 263 #else 264 BOOST_STATIC_ASSERT(is_async_write_stream<async_write_stream>::value); 265 #endif 266 BOOST_STATIC_ASSERT(is_async_write_stream<async_stream>::value); 267 BOOST_STATIC_ASSERT(is_async_stream<async_stream>::value); 268 269 BOOST_STATIC_ASSERT(! is_async_write_stream<async_read_stream>::value); 270 BOOST_STATIC_ASSERT(! is_async_read_stream<async_write_stream>::value); 271 BOOST_STATIC_ASSERT(! is_async_stream<sync_stream>::value); 272 273 //-------------------------------------------------------------------------- 274 275 template<class T> 276 struct layer 277 { 278 T t; 279 280 template<class U> 281 explicit layerboost::beast::stream_traits_test::layer282 layer(U&& u) 283 : t(std::forward<U>(u)) 284 { 285 } 286 next_layerboost::beast::stream_traits_test::layer287 T& next_layer() 288 { 289 return t; 290 } 291 }; 292 293 void testClose()294 testClose() 295 { 296 net::io_context ioc; 297 { 298 net::ip::tcp::socket sock(ioc); 299 sock.open(net::ip::tcp::v4()); 300 BEAST_EXPECT(sock.is_open()); 301 close_socket(get_lowest_layer(sock)); 302 BEAST_EXPECT(! sock.is_open()); 303 } 304 { 305 using type = layer<net::ip::tcp::socket>; 306 type layer(ioc); 307 layer.next_layer().open(net::ip::tcp::v4()); 308 BEAST_EXPECT(layer.next_layer().is_open()); 309 BOOST_STATIC_ASSERT(detail::has_next_layer<type>::value); 310 BOOST_STATIC_ASSERT((std::is_same< 311 typename std::decay<decltype(get_lowest_layer(layer))>::type, 312 lowest_layer_type<decltype(layer)>>::value)); 313 BOOST_STATIC_ASSERT(std::is_same<net::ip::tcp::socket&, 314 decltype(get_lowest_layer(layer))>::value); 315 BOOST_STATIC_ASSERT(std::is_same<net::ip::tcp::socket, 316 lowest_layer_type<decltype(layer)>>::value); 317 close_socket(get_lowest_layer(layer)); 318 BEAST_EXPECT(! layer.next_layer().is_open()); 319 } 320 { 321 test::stream ts(ioc); 322 close_socket(ts); 323 } 324 } 325 326 //-------------------------------------------------------------------------- 327 328 template <class WriteStream> hello_and_close(WriteStream & stream)329 void hello_and_close (WriteStream& stream) 330 { 331 net::write(stream, net::const_buffer("Hello, world!", 13)); 332 close_socket(get_lowest_layer(stream)); 333 } 334 335 class my_socket 336 { 337 net::ip::tcp::socket sock_; 338 339 public: my_socket(net::io_context & ioc)340 my_socket(net::io_context& ioc) 341 : sock_(ioc) 342 { 343 } 344 beast_close_socket(my_socket & s)345 friend void beast_close_socket(my_socket& s) 346 { 347 error_code ec; 348 s.sock_.close(ec); 349 // ignore the error 350 } 351 }; 352 353 void testCloseJavadoc()354 testCloseJavadoc() 355 { 356 BEAST_EXPECT(&stream_traits_test::template hello_and_close<net::ip::tcp::socket>); 357 { 358 net::io_context ioc; 359 my_socket s(ioc); 360 close_socket(s); 361 } 362 } 363 364 //-------------------------------------------------------------------------- 365 366 void run()367 run() override 368 { 369 testGetLowestLayer(); 370 testGetLowestLayerJavadoc(); 371 testExecutorType(); 372 testExecutorTypeJavadoc(); 373 testClose(); 374 testCloseJavadoc(); 375 } 376 }; 377 378 BEAST_DEFINE_TESTSUITE(beast,core,stream_traits); 379 380 } // beast 381 } // boost 382