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 #ifndef BOOST_BEAST_TEST_HANDLER_HPP
11 #define BOOST_BEAST_TEST_HANDLER_HPP
12 
13 #include <boost/beast/_experimental/unit_test/suite.hpp>
14 #include <boost/beast/core/error.hpp>
15 #include <boost/asio/io_context.hpp>
16 #include <boost/core/exchange.hpp>
17 #include <boost/optional.hpp>
18 
19 namespace boost {
20 namespace beast {
21 namespace test {
22 
23 /** A CompletionHandler used for testing.
24 
25     This completion handler is used by tests to ensure correctness
26     of behavior. It is designed as a single type to reduce template
27     instantiations, with configurable settings through constructor
28     arguments. Typically this type will be used in type lists and
29     not instantiated directly; instances of this class are returned
30     by the helper functions listed below.
31 
32     @see success_handler, @ref fail_handler, @ref any_handler
33 */
34 class handler
35 {
36     boost::optional<error_code> ec_;
37     bool pass_ = false;
38 
39 public:
40     handler() = default;
41 
42     explicit
handler(error_code ec)43     handler(error_code ec)
44         : ec_(ec)
45     {
46     }
47 
48     explicit
handler(boost::none_t)49     handler(boost::none_t)
50     {
51     }
52 
handler(handler && other)53     handler(handler&& other)
54         : ec_(other.ec_)
55         , pass_(boost::exchange(other.pass_, true))
56     {
57     }
58 
~handler()59     ~handler()
60     {
61         BEAST_EXPECT(pass_);
62     }
63 
64     template<class... Args>
65     void
operator ()(error_code ec,Args &&...)66     operator()(error_code ec, Args&&...)
67     {
68         BEAST_EXPECT(! pass_); // can't call twice
69         BEAST_EXPECTS(! ec_ || ec == *ec_,
70             ec.message());
71         pass_ = true;
72     }
73 
74     void
operator ()()75     operator()()
76     {
77         BEAST_EXPECT(! pass_); // can't call twice
78         BEAST_EXPECT(! ec_);
79         pass_ = true;
80     }
81 
82     template<class Arg0, class... Args,
83         class = typename std::enable_if<
84             ! std::is_convertible<Arg0, error_code>::value>::type>
85     void
operator ()(Arg0 &&,Args &&...)86     operator()(Arg0&&, Args&&...)
87     {
88         BEAST_EXPECT(! pass_); // can't call twice
89         BEAST_EXPECT(! ec_);
90         pass_ = true;
91     }
92 };
93 
94 /** Return a test CompletionHandler which requires success.
95 
96     The returned handler can be invoked with any signature whose
97     first parameter is an `error_code`. The handler fails the test
98     if:
99 
100     @li The handler is destroyed without being invoked, or
101 
102     @li The handler is invoked with a non-successful error code.
103 */
104 inline
105 handler
success_handler()106 success_handler() noexcept
107 {
108     return handler(error_code{});
109 }
110 
111 /** Return a test CompletionHandler which requires invocation.
112 
113     The returned handler can be invoked with any signature.
114     The handler fails the test if:
115 
116     @li The handler is destroyed without being invoked.
117 */
118 inline
119 handler
any_handler()120 any_handler() noexcept
121 {
122     return handler(boost::none);
123 }
124 
125 /** Return a test CompletionHandler which requires a specific error code.
126 
127     This handler can be invoked with any signature whose first
128     parameter is an `error_code`. The handler fails the test if:
129 
130     @li The handler is destroyed without being invoked.
131 
132     @li The handler is invoked with an error code different from
133     what is specified.
134 
135     @param ec The error code to specify.
136 */
137 inline
138 handler
fail_handler(error_code ec)139 fail_handler(error_code ec) noexcept
140 {
141     return handler(ec);
142 }
143 
144 /** Run an I/O context.
145 
146     This function runs and dispatches handlers on the specified
147     I/O context, until one of the following conditions is true:
148 
149     @li The I/O context runs out of work.
150 
151     @param ioc The I/O context to run
152 */
153 inline
154 void
run(net::io_context & ioc)155 run(net::io_context& ioc)
156 {
157     ioc.run();
158     ioc.restart();
159 }
160 
161 /** Run an I/O context for a certain amount of time.
162 
163     This function runs and dispatches handlers on the specified
164     I/O context, until one of the following conditions is true:
165 
166     @li The I/O context runs out of work.
167 
168     @li No completions occur and the specified amount of time has elapsed.
169 
170     @param ioc The I/O context to run
171 
172     @param elapsed The maximum amount of time to run for.
173 */
174 template<class Rep, class Period>
175 void
run_for(net::io_context & ioc,std::chrono::duration<Rep,Period> elapsed)176 run_for(
177     net::io_context& ioc,
178     std::chrono::duration<Rep, Period> elapsed)
179 {
180     ioc.run_for(elapsed);
181     ioc.restart();
182 }
183 
184 } // test
185 } // beast
186 } // boost
187 
188 #endif
189