• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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