]>
Commit | Line | Data |
---|---|---|
7c673cae | 1 | // |
b32b8144 | 2 | // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com) |
7c673cae FG |
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 | // | |
b32b8144 FG |
7 | // Official repository: https://github.com/boostorg/beast |
8 | // | |
7c673cae | 9 | |
b32b8144 FG |
10 | #ifndef BOOST_BEAST_UNIT_TEST_RUNNER_H_INCLUDED |
11 | #define BOOST_BEAST_UNIT_TEST_RUNNER_H_INCLUDED | |
7c673cae | 12 | |
b32b8144 | 13 | #include <boost/beast/unit_test/suite_info.hpp> |
7c673cae FG |
14 | #include <boost/assert.hpp> |
15 | #include <mutex> | |
16 | #include <ostream> | |
17 | #include <string> | |
18 | ||
b32b8144 | 19 | namespace boost { |
7c673cae FG |
20 | namespace beast { |
21 | namespace unit_test { | |
22 | ||
23 | /** Unit test runner interface. | |
24 | ||
25 | Derived classes can customize the reporting behavior. This interface is | |
26 | injected into the unit_test class to receive the results of the tests. | |
27 | */ | |
28 | class runner | |
29 | { | |
30 | std::string arg_; | |
31 | bool default_ = false; | |
32 | bool failed_ = false; | |
33 | bool cond_ = false; | |
34 | std::recursive_mutex mutex_; | |
35 | ||
36 | public: | |
37 | runner() = default; | |
38 | virtual ~runner() = default; | |
39 | runner(runner const&) = delete; | |
40 | runner& operator=(runner const&) = delete; | |
41 | ||
42 | /** Set the argument string. | |
43 | ||
44 | The argument string is available to suites and | |
45 | allows for customization of the test. Each suite | |
46 | defines its own syntax for the argumnet string. | |
47 | The same argument is passed to all suites. | |
48 | */ | |
49 | void | |
50 | arg(std::string const& s) | |
51 | { | |
52 | arg_ = s; | |
53 | } | |
54 | ||
55 | /** Returns the argument string. */ | |
56 | std::string const& | |
57 | arg() const | |
58 | { | |
59 | return arg_; | |
60 | } | |
61 | ||
62 | /** Run the specified suite. | |
63 | @return `true` if any conditions failed. | |
64 | */ | |
65 | template<class = void> | |
66 | bool | |
67 | run(suite_info const& s); | |
68 | ||
69 | /** Run a sequence of suites. | |
70 | The expression | |
71 | `FwdIter::value_type` | |
72 | must be convertible to `suite_info`. | |
73 | @return `true` if any conditions failed. | |
74 | */ | |
75 | template<class FwdIter> | |
76 | bool | |
77 | run(FwdIter first, FwdIter last); | |
78 | ||
79 | /** Conditionally run a sequence of suites. | |
80 | pred will be called as: | |
81 | @code | |
82 | bool pred(suite_info const&); | |
83 | @endcode | |
84 | @return `true` if any conditions failed. | |
85 | */ | |
86 | template<class FwdIter, class Pred> | |
87 | bool | |
88 | run_if(FwdIter first, FwdIter last, Pred pred = Pred{}); | |
89 | ||
90 | /** Run all suites in a container. | |
91 | @return `true` if any conditions failed. | |
92 | */ | |
93 | template<class SequenceContainer> | |
94 | bool | |
95 | run_each(SequenceContainer const& c); | |
96 | ||
97 | /** Conditionally run suites in a container. | |
98 | pred will be called as: | |
99 | @code | |
100 | bool pred(suite_info const&); | |
101 | @endcode | |
102 | @return `true` if any conditions failed. | |
103 | */ | |
104 | template<class SequenceContainer, class Pred> | |
105 | bool | |
106 | run_each_if(SequenceContainer const& c, Pred pred = Pred{}); | |
107 | ||
108 | protected: | |
109 | /// Called when a new suite starts. | |
110 | virtual | |
111 | void | |
112 | on_suite_begin(suite_info const&) | |
113 | { | |
114 | } | |
115 | ||
116 | /// Called when a suite ends. | |
117 | virtual | |
118 | void | |
119 | on_suite_end() | |
120 | { | |
121 | } | |
122 | ||
123 | /// Called when a new case starts. | |
124 | virtual | |
125 | void | |
126 | on_case_begin(std::string const&) | |
127 | { | |
128 | } | |
129 | ||
130 | /// Called when a new case ends. | |
131 | virtual | |
132 | void | |
133 | on_case_end() | |
134 | { | |
135 | } | |
136 | ||
137 | /// Called for each passing condition. | |
138 | virtual | |
139 | void | |
140 | on_pass() | |
141 | { | |
142 | } | |
143 | ||
144 | /// Called for each failing condition. | |
145 | virtual | |
146 | void | |
147 | on_fail(std::string const&) | |
148 | { | |
149 | } | |
150 | ||
151 | /// Called when a test logs output. | |
152 | virtual | |
153 | void | |
154 | on_log(std::string const&) | |
155 | { | |
156 | } | |
157 | ||
158 | private: | |
159 | friend class suite; | |
160 | ||
161 | // Start a new testcase. | |
162 | template<class = void> | |
163 | void | |
164 | testcase(std::string const& name); | |
165 | ||
166 | template<class = void> | |
167 | void | |
168 | pass(); | |
169 | ||
170 | template<class = void> | |
171 | void | |
172 | fail(std::string const& reason); | |
173 | ||
174 | template<class = void> | |
175 | void | |
176 | log(std::string const& s); | |
177 | }; | |
178 | ||
179 | //------------------------------------------------------------------------------ | |
180 | ||
181 | template<class> | |
182 | bool | |
183 | runner::run(suite_info const& s) | |
184 | { | |
185 | // Enable 'default' testcase | |
186 | default_ = true; | |
187 | failed_ = false; | |
188 | on_suite_begin(s); | |
189 | s.run(*this); | |
190 | // Forgot to call pass or fail. | |
191 | BOOST_ASSERT(cond_); | |
192 | on_case_end(); | |
193 | on_suite_end(); | |
194 | return failed_; | |
195 | } | |
196 | ||
197 | template<class FwdIter> | |
198 | bool | |
199 | runner::run(FwdIter first, FwdIter last) | |
200 | { | |
201 | bool failed(false); | |
202 | for(;first != last; ++first) | |
203 | failed = run(*first) || failed; | |
204 | return failed; | |
205 | } | |
206 | ||
207 | template<class FwdIter, class Pred> | |
208 | bool | |
209 | runner::run_if(FwdIter first, FwdIter last, Pred pred) | |
210 | { | |
211 | bool failed(false); | |
212 | for(;first != last; ++first) | |
213 | if(pred(*first)) | |
214 | failed = run(*first) || failed; | |
215 | return failed; | |
216 | } | |
217 | ||
218 | template<class SequenceContainer> | |
219 | bool | |
220 | runner::run_each(SequenceContainer const& c) | |
221 | { | |
222 | bool failed(false); | |
223 | for(auto const& s : c) | |
224 | failed = run(s) || failed; | |
225 | return failed; | |
226 | } | |
227 | ||
228 | template<class SequenceContainer, class Pred> | |
229 | bool | |
230 | runner::run_each_if(SequenceContainer const& c, Pred pred) | |
231 | { | |
232 | bool failed(false); | |
233 | for(auto const& s : c) | |
234 | if(pred(s)) | |
235 | failed = run(s) || failed; | |
236 | return failed; | |
237 | } | |
238 | ||
239 | template<class> | |
240 | void | |
241 | runner::testcase(std::string const& name) | |
242 | { | |
243 | std::lock_guard<std::recursive_mutex> lock(mutex_); | |
244 | // Name may not be empty | |
245 | BOOST_ASSERT(default_ || ! name.empty()); | |
246 | // Forgot to call pass or fail | |
247 | BOOST_ASSERT(default_ || cond_); | |
248 | if(! default_) | |
249 | on_case_end(); | |
250 | default_ = false; | |
251 | cond_ = false; | |
252 | on_case_begin(name); | |
253 | } | |
254 | ||
255 | template<class> | |
256 | void | |
257 | runner::pass() | |
258 | { | |
259 | std::lock_guard<std::recursive_mutex> lock(mutex_); | |
260 | if(default_) | |
261 | testcase(""); | |
262 | on_pass(); | |
263 | cond_ = true; | |
264 | } | |
265 | ||
266 | template<class> | |
267 | void | |
268 | runner::fail(std::string const& reason) | |
269 | { | |
270 | std::lock_guard<std::recursive_mutex> lock(mutex_); | |
271 | if(default_) | |
272 | testcase(""); | |
273 | on_fail(reason); | |
274 | failed_ = true; | |
275 | cond_ = true; | |
276 | } | |
277 | ||
278 | template<class> | |
279 | void | |
280 | runner::log(std::string const& s) | |
281 | { | |
282 | std::lock_guard<std::recursive_mutex> lock(mutex_); | |
283 | if(default_) | |
284 | testcase(""); | |
285 | on_log(s); | |
286 | } | |
287 | ||
288 | } // unit_test | |
289 | } // beast | |
b32b8144 | 290 | } // boost |
7c673cae FG |
291 | |
292 | #endif |