2 // Copyright (c) 2016-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
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)
7 // Official repository: https://github.com/boostorg/beast
10 #ifndef BOOST_BEAST_UNIT_TEST_SUITE_HPP
11 #define BOOST_BEAST_UNIT_TEST_SUITE_HPP
13 #include <boost/beast/unit_test/runner.hpp>
14 #include <boost/throw_exception.hpp>
25 template<class String>
28 make_reason(String const& reason,
29 char const* file, int line)
31 std::string s(reason);
34 char const* path = file + strlen(file);
47 s.append(std::to_string(line));
62 /** A testsuite class.
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
73 bool aborted_ = false;
74 runner* runner_ = nullptr;
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
81 what() const noexcept override
83 return "test suite aborted";
87 template<class CharT, class Traits, class Allocator>
89 : public std::basic_stringbuf<CharT, Traits, Allocator>
108 auto const& s = this->str();
110 suite_.runner_->log(s);
118 class Traits = std::char_traits<CharT>,
119 class Allocator = std::allocator<CharT>
121 class log_os : public std::basic_ostream<CharT, Traits>
123 log_buf<CharT, Traits, Allocator> buf_;
128 : std::basic_ostream<CharT, Traits>(&buf_)
134 class scoped_testcase;
139 std::stringstream ss_;
143 testcase_t(suite& self)
148 /** Open a new testcase.
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
156 @param abort Determines if suite continues running after a failure.
159 operator()(std::string const& name,
160 abort_t abort = no_abort_on_fail);
163 operator()(abort_t abort);
167 operator<<(T const& t);
171 /** Logging output stream.
173 Text sent to the log output stream will be forwarded to
174 the output stream associated with the runner.
178 /** Memberspace for declaring test cases. */
181 /** Returns the "current" running suite.
182 If no suite is running, nullptr is returned.
188 return *p_this_suite();
197 /** Invokes the test using the specified runner.
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.
204 template<class = void>
206 operator()(runner& r);
208 /** Record a successful test condition. */
209 template<class = void>
213 /** Record a failure.
215 @param reason Optional text added to the output on a failure.
217 @param file The source code file where the test failed.
219 @param line The source code line number where the test failed.
222 template<class String>
224 fail(String const& reason, char const* file, int line);
226 template<class = void>
228 fail(std::string const& reason = "");
231 /** Evaluate a test condition.
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.
237 @param shouldBeTrue The condition to test. The condition
238 is evaluated in a boolean context.
240 @param reason Optional added text to output on a failure.
242 @param file The source code file where the test failed.
244 @param line The source code line number where the test failed.
246 @return `true` if the test condition indicates success.
249 template<class Condition>
251 expect(Condition const& shouldBeTrue)
253 return expect(shouldBeTrue, "");
256 template<class Condition, class String>
258 expect(Condition const& shouldBeTrue, String const& reason);
260 template<class Condition>
262 expect(Condition const& shouldBeTrue,
263 char const* file, int line)
265 return expect(shouldBeTrue, "", file, line);
268 template<class Condition, class String>
270 expect(Condition const& shouldBeTrue,
271 String const& reason, char const* file, int line);
277 // Expect an exception from f()
278 template<class F, class String>
280 except(F&& f, String const& reason);
285 return except(f, "");
287 template<class E, class F, class String>
289 except(F&& f, String const& reason);
290 template<class E, class F>
294 return except<E>(f, "");
296 template<class F, class String>
298 unexcept(F&& f, String const& reason);
303 return unexcept(f, "");
306 /** Return the argument associated with the runner. */
310 return runner_->arg();
314 // @return `true` if the test condition indicates success(a false value)
315 template<class Condition, class String>
317 unexpected(Condition shouldBeFalse,
318 String const& reason);
320 template<class Condition>
322 unexpected(Condition shouldBeFalse)
324 return unexpected(shouldBeFalse, "");
334 static suite* pts = nullptr;
338 /** Runs the suite. */
346 template<class = void>
351 //------------------------------------------------------------------------------
353 // Helper for streaming testcase names
354 class suite::scoped_testcase
358 std::stringstream& ss_;
361 scoped_testcase& operator=(scoped_testcase const&) = delete;
365 auto const& name = ss_.str();
367 suite_.runner_->testcase(name);
370 scoped_testcase(suite& self, std::stringstream& ss)
379 scoped_testcase(suite& self,
380 std::stringstream& ss, T const& t)
391 operator<<(T const& t)
398 //------------------------------------------------------------------------------
402 suite::testcase_t::operator()(
403 std::string const& name, abort_t abort)
405 suite_.abort_ = abort == abort_on_fail;
406 suite_.runner_->testcase(name);
410 suite::scoped_testcase
411 suite::testcase_t::operator()(abort_t abort)
413 suite_.abort_ = abort == abort_on_fail;
414 return { suite_, ss_ };
419 suite::scoped_testcase
420 suite::testcase_t::operator<<(T const& t)
422 return { suite_, ss_, t };
425 //------------------------------------------------------------------------------
430 operator()(runner& r)
432 *p_this_suite() = this;
436 *p_this_suite() = nullptr;
440 *p_this_suite() = nullptr;
445 template<class Condition, class String>
449 Condition const& shouldBeTrue, String const& reason)
460 template<class Condition, class String>
463 expect(Condition const& shouldBeTrue,
464 String const& reason, char const* file, int line)
471 fail(detail::make_reason(reason, file, line));
477 template<class F, class String>
480 except(F&& f, String const& reason)
495 template<class E, class F, class String>
498 except(F&& f, String const& reason)
513 template<class F, class String>
516 unexcept(F&& f, String const& reason)
531 template<class Condition, class String>
535 Condition shouldBeFalse, String const& reason)
538 static_cast<bool>(shouldBeFalse);
559 fail(std::string const& reason)
562 runner_->fail(reason);
566 BOOST_THROW_EXCEPTION(abort_exception());
570 template<class String>
573 fail(String const& reason, char const* file, int line)
575 fail(detail::make_reason(reason, file, line));
583 if(abort_ && aborted_)
584 BOOST_THROW_EXCEPTION(abort_exception());
598 catch(abort_exception const&)
602 catch(std::exception const& e)
604 runner_->fail("unhandled exception: " +
605 std::string(e.what()));
609 runner_->fail("unhandled exception");
614 /** Check a precondition.
616 If the condition is false, the file and line number are reported.
618 #define BEAST_EXPECT(cond) expect(cond, __FILE__, __LINE__)
621 #ifndef BEAST_EXPECTS
622 /** Check a precondition.
624 If the condition is false, the file and line number are reported.
626 #define BEAST_EXPECTS(cond, reason) ((cond) ? (pass(), true) : \
627 (fail((reason), __FILE__, __LINE__), false))
634 //------------------------------------------------------------------------------
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)
643 //------------------------------------------------------------------------------
645 // Preprocessor directives for controlling unit test definitions.
647 // If this is already defined, don't redefine it. This allows
648 // programs to provide custom behavior for testsuite definitions
650 #ifndef BEAST_DEFINE_TESTSUITE
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
657 #ifndef BEAST_NO_UNIT_TEST_INLINE
658 #define BEAST_NO_UNIT_TEST_INLINE 0
661 /** Define a unit test suite.
663 Library Identifies the library.
664 Module Identifies the module.
665 Class The type representing the class being tested.
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:
673 struct aged_ordered_container_test : beast::unit_test::suite
680 The macro invocation must appear in the same namespace as the test class.
683 #if BEAST_NO_UNIT_TEST_INLINE
684 #define BEAST_DEFINE_TESTSUITE(Class,Module,Library)
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)
697 //------------------------------------------------------------------------------