]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/beast/subtree/unit_test/include/boost/beast/unit_test/suite.hpp
Add patch for failing prerm scripts
[ceph.git] / ceph / src / boost / libs / beast / subtree / unit_test / include / boost / beast / unit_test / suite.hpp
CommitLineData
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_SUITE_HPP
11#define BOOST_BEAST_UNIT_TEST_SUITE_HPP
7c673cae 12
b32b8144
FG
13#include <boost/beast/unit_test/runner.hpp>
14#include <boost/throw_exception.hpp>
7c673cae
FG
15#include <ostream>
16#include <sstream>
17#include <string>
18
b32b8144 19namespace boost {
7c673cae
FG
20namespace beast {
21namespace unit_test {
22
23namespace detail {
24
25template<class String>
26static
27std::string
28make_reason(String const& reason,
29 char const* file, int line)
30{
31 std::string s(reason);
32 if(! s.empty())
33 s.append(": ");
b32b8144
FG
34 char const* path = file + strlen(file);
35 while(path != file)
36 {
37 #ifdef _MSC_VER
38 if(path[-1] == '\\')
39 #else
40 if(path[-1] == '/')
41 #endif
42 break;
43 --path;
44 }
45 s.append(path);
7c673cae 46 s.append("(");
b32b8144 47 s.append(std::to_string(line));
7c673cae
FG
48 s.append(")");
49 return s;
50}
51
52} // detail
53
54class thread;
55
56enum abort_t
57{
58 no_abort_on_fail,
59 abort_on_fail
60};
61
62/** A testsuite class.
63
64 Derived classes execute a series of testcases, where each testcase is
65 a series of pass/fail tests. To provide a unit test using this class,
b32b8144 66 derive from it and use the BOOST_BEAST_DEFINE_UNIT_TEST macro in a
7c673cae
FG
67 translation unit.
68*/
69class suite
70{
71private:
72 bool abort_ = false;
73 bool aborted_ = false;
74 runner* runner_ = nullptr;
75
76 // This exception is thrown internally to stop the current suite
77 // in the event of a failure, if the option to stop is set.
78 struct abort_exception : public std::exception
79 {
80 char const*
81 what() const noexcept override
82 {
83 return "test suite aborted";
84 }
85 };
86
87 template<class CharT, class Traits, class Allocator>
88 class log_buf
89 : public std::basic_stringbuf<CharT, Traits, Allocator>
90 {
91 suite& suite_;
92
93 public:
94 explicit
95 log_buf(suite& self)
96 : suite_(self)
97 {
98 }
99
100 ~log_buf()
101 {
102 sync();
103 }
104
105 int
106 sync() override
107 {
108 auto const& s = this->str();
109 if(s.size() > 0)
110 suite_.runner_->log(s);
111 this->str("");
112 return 0;
113 }
114 };
115
116 template<
117 class CharT,
118 class Traits = std::char_traits<CharT>,
119 class Allocator = std::allocator<CharT>
120 >
121 class log_os : public std::basic_ostream<CharT, Traits>
122 {
123 log_buf<CharT, Traits, Allocator> buf_;
124
125 public:
126 explicit
127 log_os(suite& self)
128 : std::basic_ostream<CharT, Traits>(&buf_)
129 , buf_(self)
130 {
131 }
132 };
133
134 class scoped_testcase;
135
136 class testcase_t
137 {
138 suite& suite_;
139 std::stringstream ss_;
140
141 public:
142 explicit
143 testcase_t(suite& self)
144 : suite_(self)
145 {
146 }
147
148 /** Open a new testcase.
149
150 A testcase is a series of evaluated test conditions. A test
151 suite may have multiple test cases. A test is associated with
152 the last opened testcase. When the test first runs, a default
153 unnamed case is opened. Tests with only one case may omit the
154 call to testcase.
155
156 @param abort Determines if suite continues running after a failure.
157 */
158 void
159 operator()(std::string const& name,
160 abort_t abort = no_abort_on_fail);
161
162 scoped_testcase
163 operator()(abort_t abort);
164
165 template<class T>
166 scoped_testcase
167 operator<<(T const& t);
168 };
169
170public:
171 /** Logging output stream.
172
173 Text sent to the log output stream will be forwarded to
174 the output stream associated with the runner.
175 */
176 log_os<char> log;
177
178 /** Memberspace for declaring test cases. */
179 testcase_t testcase;
180
181 /** Returns the "current" running suite.
182 If no suite is running, nullptr is returned.
183 */
184 static
185 suite*
186 this_suite()
187 {
188 return *p_this_suite();
189 }
190
191 suite()
192 : log(*this)
193 , testcase(*this)
194 {
195 }
196
197 /** Invokes the test using the specified runner.
198
199 Data members are set up here instead of the constructor as a
200 convenience to writing the derived class to avoid repetition of
201 forwarded constructor arguments to the base.
202 Normally this is called by the framework for you.
203 */
204 template<class = void>
205 void
206 operator()(runner& r);
207
208 /** Record a successful test condition. */
209 template<class = void>
210 void
211 pass();
212
213 /** Record a failure.
214
215 @param reason Optional text added to the output on a failure.
216
217 @param file The source code file where the test failed.
218
219 @param line The source code line number where the test failed.
220 */
221 /** @{ */
222 template<class String>
223 void
224 fail(String const& reason, char const* file, int line);
225
226 template<class = void>
227 void
228 fail(std::string const& reason = "");
229 /** @} */
230
231 /** Evaluate a test condition.
232
233 This function provides improved logging by incorporating the
234 file name and line number into the reported output on failure,
235 as well as additional text specified by the caller.
236
237 @param shouldBeTrue The condition to test. The condition
238 is evaluated in a boolean context.
239
240 @param reason Optional added text to output on a failure.
241
242 @param file The source code file where the test failed.
243
244 @param line The source code line number where the test failed.
245
246 @return `true` if the test condition indicates success.
247 */
248 /** @{ */
249 template<class Condition>
250 bool
251 expect(Condition const& shouldBeTrue)
252 {
253 return expect(shouldBeTrue, "");
254 }
255
256 template<class Condition, class String>
257 bool
258 expect(Condition const& shouldBeTrue, String const& reason);
259
260 template<class Condition>
261 bool
262 expect(Condition const& shouldBeTrue,
263 char const* file, int line)
264 {
265 return expect(shouldBeTrue, "", file, line);
266 }
267
268 template<class Condition, class String>
269 bool
270 expect(Condition const& shouldBeTrue,
271 String const& reason, char const* file, int line);
272 /** @} */
273
274 //
275 // DEPRECATED
276 //
277 // Expect an exception from f()
278 template<class F, class String>
279 bool
280 except(F&& f, String const& reason);
281 template<class F>
282 bool
283 except(F&& f)
284 {
285 return except(f, "");
286 }
287 template<class E, class F, class String>
288 bool
289 except(F&& f, String const& reason);
290 template<class E, class F>
291 bool
292 except(F&& f)
293 {
294 return except<E>(f, "");
295 }
296 template<class F, class String>
297 bool
298 unexcept(F&& f, String const& reason);
299 template<class F>
300 bool
301 unexcept(F&& f)
302 {
303 return unexcept(f, "");
304 }
305
306 /** Return the argument associated with the runner. */
307 std::string const&
308 arg() const
309 {
310 return runner_->arg();
311 }
312
313 // DEPRECATED
314 // @return `true` if the test condition indicates success(a false value)
315 template<class Condition, class String>
316 bool
317 unexpected(Condition shouldBeFalse,
318 String const& reason);
319
320 template<class Condition>
321 bool
322 unexpected(Condition shouldBeFalse)
323 {
324 return unexpected(shouldBeFalse, "");
325 }
326
327private:
328 friend class thread;
329
330 static
331 suite**
332 p_this_suite()
333 {
334 static suite* pts = nullptr;
335 return &pts;
336 }
337
338 /** Runs the suite. */
339 virtual
340 void
341 run() = 0;
342
343 void
344 propagate_abort();
345
346 template<class = void>
347 void
348 run(runner& r);
349};
350
351//------------------------------------------------------------------------------
352
353// Helper for streaming testcase names
354class suite::scoped_testcase
355{
356private:
357 suite& suite_;
358 std::stringstream& ss_;
359
360public:
361 scoped_testcase& operator=(scoped_testcase const&) = delete;
362
363 ~scoped_testcase()
364 {
365 auto const& name = ss_.str();
366 if(! name.empty())
367 suite_.runner_->testcase(name);
368 }
369
370 scoped_testcase(suite& self, std::stringstream& ss)
371 : suite_(self)
372 , ss_(ss)
373 {
374 ss_.clear();
375 ss_.str({});
376 }
377
378 template<class T>
379 scoped_testcase(suite& self,
380 std::stringstream& ss, T const& t)
381 : suite_(self)
382 , ss_(ss)
383 {
384 ss_.clear();
385 ss_.str({});
386 ss_ << t;
387 }
388
389 template<class T>
390 scoped_testcase&
391 operator<<(T const& t)
392 {
393 ss_ << t;
394 return *this;
395 }
396};
397
398//------------------------------------------------------------------------------
399
400inline
401void
402suite::testcase_t::operator()(
403 std::string const& name, abort_t abort)
404{
405 suite_.abort_ = abort == abort_on_fail;
406 suite_.runner_->testcase(name);
407}
408
409inline
410suite::scoped_testcase
411suite::testcase_t::operator()(abort_t abort)
412{
413 suite_.abort_ = abort == abort_on_fail;
414 return { suite_, ss_ };
415}
416
417template<class T>
418inline
419suite::scoped_testcase
420suite::testcase_t::operator<<(T const& t)
421{
422 return { suite_, ss_, t };
423}
424
425//------------------------------------------------------------------------------
426
427template<class>
428void
429suite::
430operator()(runner& r)
431{
432 *p_this_suite() = this;
433 try
434 {
435 run(r);
436 *p_this_suite() = nullptr;
437 }
438 catch(...)
439 {
440 *p_this_suite() = nullptr;
441 throw;
442 }
443}
444
445template<class Condition, class String>
446bool
447suite::
448expect(
449 Condition const& shouldBeTrue, String const& reason)
450{
451 if(shouldBeTrue)
452 {
453 pass();
454 return true;
455 }
456 fail(reason);
457 return false;
458}
459
460template<class Condition, class String>
461bool
462suite::
463expect(Condition const& shouldBeTrue,
464 String const& reason, char const* file, int line)
465{
466 if(shouldBeTrue)
467 {
468 pass();
469 return true;
470 }
471 fail(detail::make_reason(reason, file, line));
472 return false;
473}
474
475// DEPRECATED
476
477template<class F, class String>
478bool
479suite::
480except(F&& f, String const& reason)
481{
482 try
483 {
484 f();
485 fail(reason);
486 return false;
487 }
488 catch(...)
489 {
490 pass();
491 }
492 return true;
493}
494
495template<class E, class F, class String>
496bool
497suite::
498except(F&& f, String const& reason)
499{
500 try
501 {
502 f();
503 fail(reason);
504 return false;
505 }
506 catch(E const&)
507 {
508 pass();
509 }
510 return true;
511}
512
513template<class F, class String>
514bool
515suite::
516unexcept(F&& f, String const& reason)
517{
518 try
519 {
520 f();
521 pass();
522 return true;
523 }
524 catch(...)
525 {
526 fail(reason);
527 }
528 return false;
529}
530
531template<class Condition, class String>
532bool
533suite::
534unexpected(
535 Condition shouldBeFalse, String const& reason)
536{
537 bool const b =
538 static_cast<bool>(shouldBeFalse);
539 if(! b)
540 pass();
541 else
542 fail(reason);
543 return ! b;
544}
545
546template<class>
547void
548suite::
549pass()
550{
551 propagate_abort();
552 runner_->pass();
553}
554
555// ::fail
556template<class>
557void
558suite::
559fail(std::string const& reason)
560{
561 propagate_abort();
562 runner_->fail(reason);
563 if(abort_)
564 {
565 aborted_ = true;
b32b8144 566 BOOST_THROW_EXCEPTION(abort_exception());
7c673cae
FG
567 }
568}
569
570template<class String>
571void
572suite::
573fail(String const& reason, char const* file, int line)
574{
575 fail(detail::make_reason(reason, file, line));
576}
577
578inline
579void
580suite::
581propagate_abort()
582{
583 if(abort_ && aborted_)
b32b8144 584 BOOST_THROW_EXCEPTION(abort_exception());
7c673cae
FG
585}
586
587template<class>
588void
589suite::
590run(runner& r)
591{
592 runner_ = &r;
593
594 try
595 {
596 run();
597 }
598 catch(abort_exception const&)
599 {
600 // ends the suite
601 }
602 catch(std::exception const& e)
603 {
604 runner_->fail("unhandled exception: " +
605 std::string(e.what()));
606 }
607 catch(...)
608 {
609 runner_->fail("unhandled exception");
610 }
611}
612
613#ifndef BEAST_EXPECT
614/** Check a precondition.
615
616 If the condition is false, the file and line number are reported.
617*/
618#define BEAST_EXPECT(cond) expect(cond, __FILE__, __LINE__)
619#endif
620
621#ifndef BEAST_EXPECTS
622/** Check a precondition.
623
624 If the condition is false, the file and line number are reported.
625*/
626#define BEAST_EXPECTS(cond, reason) ((cond) ? (pass(), true) : \
627 (fail((reason), __FILE__, __LINE__), false))
628#endif
629
630} // unit_test
631} // beast
b32b8144 632} // boost
7c673cae
FG
633
634//------------------------------------------------------------------------------
635
636// detail:
637// This inserts the suite with the given manual flag
b32b8144 638#define BEAST_DEFINE_TESTSUITE_INSERT(Library,Module,Class,manual) \
7c673cae
FG
639 static beast::unit_test::detail::insert_suite <Class##_test> \
640 Library ## Module ## Class ## _test_instance( \
641 #Class, #Module, #Library, manual)
642
643//------------------------------------------------------------------------------
644
645// Preprocessor directives for controlling unit test definitions.
646
647// If this is already defined, don't redefine it. This allows
648// programs to provide custom behavior for testsuite definitions
649//
650#ifndef BEAST_DEFINE_TESTSUITE
651
652/** Enables insertion of test suites into the global container.
653 The default is to insert all test suite definitions into the global
654 container. If BEAST_DEFINE_TESTSUITE is user defined, this macro
655 has no effect.
656*/
657#ifndef BEAST_NO_UNIT_TEST_INLINE
658#define BEAST_NO_UNIT_TEST_INLINE 0
659#endif
660
661/** Define a unit test suite.
662
7c673cae 663 Library Identifies the library.
b32b8144
FG
664 Module Identifies the module.
665 Class The type representing the class being tested.
7c673cae
FG
666
667 The declaration for the class implementing the test should be the same
668 as Class ## _test. For example, if Class is aged_ordered_container, the
669 test class must be declared as:
670
671 @code
672
673 struct aged_ordered_container_test : beast::unit_test::suite
674 {
675 //...
676 };
677
678 @endcode
679
680 The macro invocation must appear in the same namespace as the test class.
681*/
682
683#if BEAST_NO_UNIT_TEST_INLINE
684#define BEAST_DEFINE_TESTSUITE(Class,Module,Library)
685
686#else
b32b8144
FG
687#include <boost/beast/unit_test/global_suites.hpp>
688#define BEAST_DEFINE_TESTSUITE(Library,Module,Class) \
689 BEAST_DEFINE_TESTSUITE_INSERT(Library,Module,Class,false)
690#define BEAST_DEFINE_TESTSUITE_MANUAL(Library,Module,Class) \
691 BEAST_DEFINE_TESTSUITE_INSERT(Library,Module,Class,true)
7c673cae
FG
692
693#endif
694
695#endif
696
697//------------------------------------------------------------------------------
698
699#endif