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