]> git.proxmox.com Git - ceph.git/blob - 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
1 //
2 // Copyright (c) 2016-2017 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_UNIT_TEST_SUITE_HPP
11 #define BOOST_BEAST_UNIT_TEST_SUITE_HPP
12
13 #include <boost/beast/unit_test/runner.hpp>
14 #include <boost/throw_exception.hpp>
15 #include <ostream>
16 #include <sstream>
17 #include <string>
18
19 namespace boost {
20 namespace beast {
21 namespace unit_test {
22
23 namespace detail {
24
25 template<class String>
26 static
27 std::string
28 make_reason(String const& reason,
29 char const* file, int line)
30 {
31 std::string s(reason);
32 if(! s.empty())
33 s.append(": ");
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);
46 s.append("(");
47 s.append(std::to_string(line));
48 s.append(")");
49 return s;
50 }
51
52 } // detail
53
54 class thread;
55
56 enum 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,
66 derive from it and use the BOOST_BEAST_DEFINE_UNIT_TEST macro in a
67 translation unit.
68 */
69 class suite
70 {
71 private:
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
170 public:
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
327 private:
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
354 class suite::scoped_testcase
355 {
356 private:
357 suite& suite_;
358 std::stringstream& ss_;
359
360 public:
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
400 inline
401 void
402 suite::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
409 inline
410 suite::scoped_testcase
411 suite::testcase_t::operator()(abort_t abort)
412 {
413 suite_.abort_ = abort == abort_on_fail;
414 return { suite_, ss_ };
415 }
416
417 template<class T>
418 inline
419 suite::scoped_testcase
420 suite::testcase_t::operator<<(T const& t)
421 {
422 return { suite_, ss_, t };
423 }
424
425 //------------------------------------------------------------------------------
426
427 template<class>
428 void
429 suite::
430 operator()(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
445 template<class Condition, class String>
446 bool
447 suite::
448 expect(
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
460 template<class Condition, class String>
461 bool
462 suite::
463 expect(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
477 template<class F, class String>
478 bool
479 suite::
480 except(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
495 template<class E, class F, class String>
496 bool
497 suite::
498 except(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
513 template<class F, class String>
514 bool
515 suite::
516 unexcept(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
531 template<class Condition, class String>
532 bool
533 suite::
534 unexpected(
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
546 template<class>
547 void
548 suite::
549 pass()
550 {
551 propagate_abort();
552 runner_->pass();
553 }
554
555 // ::fail
556 template<class>
557 void
558 suite::
559 fail(std::string const& reason)
560 {
561 propagate_abort();
562 runner_->fail(reason);
563 if(abort_)
564 {
565 aborted_ = true;
566 BOOST_THROW_EXCEPTION(abort_exception());
567 }
568 }
569
570 template<class String>
571 void
572 suite::
573 fail(String const& reason, char const* file, int line)
574 {
575 fail(detail::make_reason(reason, file, line));
576 }
577
578 inline
579 void
580 suite::
581 propagate_abort()
582 {
583 if(abort_ && aborted_)
584 BOOST_THROW_EXCEPTION(abort_exception());
585 }
586
587 template<class>
588 void
589 suite::
590 run(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
632 } // boost
633
634 //------------------------------------------------------------------------------
635
636 // detail:
637 // This inserts the suite with the given manual flag
638 #define BEAST_DEFINE_TESTSUITE_INSERT(Library,Module,Class,manual) \
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
663 Library Identifies the library.
664 Module Identifies the module.
665 Class The type representing the class being tested.
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
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)
692
693 #endif
694
695 #endif
696
697 //------------------------------------------------------------------------------
698
699 #endif