Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-12-17 09:40:01

0001 //
0002 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com)
0003 //
0004 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0005 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0006 //
0007 // Official repository: https://github.com/boostorg/beast
0008 //
0009 
0010 #ifndef BOOST_BEAST_UNIT_TEST_SUITE_HPP
0011 #define BOOST_BEAST_UNIT_TEST_SUITE_HPP
0012 
0013 #include <boost/beast/_experimental/unit_test/runner.hpp>
0014 #include <boost/throw_exception.hpp>
0015 #include <ostream>
0016 #include <sstream>
0017 #include <string>
0018 
0019 #if defined(BOOST_GCC) && BOOST_GCC >= 70000 && BOOST_GCC < 80000
0020 #pragma GCC diagnostic push
0021 #pragma GCC diagnostic ignored "-Wnoexcept-type"
0022 #endif
0023 
0024 namespace boost {
0025 namespace beast {
0026 namespace unit_test {
0027 
0028 namespace detail {
0029 
0030 template<class String>
0031 std::string
0032 make_reason(String const& reason,
0033     char const* file, int line)
0034 {
0035     std::string s(reason);
0036     if(! s.empty())
0037         s.append(": ");
0038     char const* path = file + strlen(file);
0039     while(path != file)
0040     {
0041     #ifdef _MSC_VER
0042         if(path[-1] == '\\')
0043     #else
0044         if(path[-1] == '/')
0045     #endif
0046             break;
0047         --path;
0048     }
0049     s.append(path);
0050     s.append("(");
0051     s.append(std::to_string(line));
0052     s.append(")");
0053     return s;
0054 }
0055 
0056 } // detail
0057 
0058 class thread;
0059 
0060 enum abort_t
0061 {
0062     no_abort_on_fail,
0063     abort_on_fail
0064 };
0065 
0066 /** A testsuite class.
0067 
0068     Derived classes execute a series of testcases, where each testcase is
0069     a series of pass/fail tests. To provide a unit test using this class,
0070     derive from it and use the BOOST_BEAST_DEFINE_UNIT_TEST macro in a
0071     translation unit.
0072 */
0073 class suite
0074 {
0075 private:
0076     bool abort_ = false;
0077     bool aborted_ = false;
0078     runner* runner_ = nullptr;
0079 
0080     // This exception is thrown internally to stop the current suite
0081     // in the event of a failure, if the option to stop is set.
0082     struct abort_exception : public std::exception
0083     {
0084         char const*
0085         what() const noexcept override
0086         {
0087             return "test suite aborted";
0088         }
0089     };
0090 
0091     template<class CharT, class Traits, class Allocator>
0092     class log_buf
0093         : public std::basic_stringbuf<CharT, Traits, Allocator>
0094     {
0095         suite& suite_;
0096 
0097     public:
0098         explicit
0099         log_buf(suite& self)
0100             : suite_(self)
0101         {
0102         }
0103 
0104         ~log_buf()
0105         {
0106             sync();
0107         }
0108 
0109         int
0110         sync() override
0111         {
0112             auto const& s = this->str();
0113             if(s.size() > 0)
0114                 suite_.runner_->log(s);
0115             this->str("");
0116             return 0;
0117         }
0118     };
0119 
0120     template<
0121         class CharT,
0122         class Traits = std::char_traits<CharT>,
0123         class Allocator = std::allocator<CharT>
0124     >
0125     class log_os : public std::basic_ostream<CharT, Traits>
0126     {
0127         log_buf<CharT, Traits, Allocator> buf_;
0128 
0129     public:
0130         explicit
0131         log_os(suite& self)
0132             : std::basic_ostream<CharT, Traits>(&buf_)
0133             , buf_(self)
0134         {
0135         }
0136     };
0137 
0138     class scoped_testcase;
0139 
0140     class testcase_t
0141     {
0142         suite& suite_;
0143         std::stringstream ss_;
0144 
0145     public:
0146         explicit
0147         testcase_t(suite& self)
0148             : suite_(self)
0149         {
0150         }
0151 
0152         /** Open a new testcase.
0153 
0154             A testcase is a series of evaluated test conditions. A test
0155             suite may have multiple test cases. A test is associated with
0156             the last opened testcase. When the test first runs, a default
0157             unnamed case is opened. Tests with only one case may omit the
0158             call to testcase.
0159 
0160             @param abort Determines if suite continues running after a failure.
0161         */
0162         void
0163         operator()(std::string const& name,
0164             abort_t abort = no_abort_on_fail);
0165 
0166         scoped_testcase
0167         operator()(abort_t abort);
0168 
0169         template<class T>
0170         scoped_testcase
0171         operator<<(T const& t);
0172     };
0173 
0174 public:
0175     /** Logging output stream.
0176 
0177         Text sent to the log output stream will be forwarded to
0178         the output stream associated with the runner.
0179     */
0180     log_os<char> log;
0181 
0182     /** Memberspace for declaring test cases. */
0183     testcase_t testcase;
0184 
0185     /** Returns the "current" running suite.
0186         If no suite is running, nullptr is returned.
0187     */
0188     static
0189     suite*
0190     this_suite()
0191     {
0192         return *p_this_suite();
0193     }
0194 
0195     suite()
0196         : log(*this)
0197         , testcase(*this)
0198     {
0199     }
0200 
0201     virtual ~suite() = default;
0202     suite(suite const&) = delete;
0203     suite& operator=(suite const&) = delete;
0204 
0205     /** Invokes the test using the specified runner.
0206 
0207         Data members are set up here instead of the constructor as a
0208         convenience to writing the derived class to avoid repetition of
0209         forwarded constructor arguments to the base.
0210         Normally this is called by the framework for you.
0211     */
0212     template<class = void>
0213     void
0214     operator()(runner& r);
0215 
0216     /** Record a successful test condition. */
0217     template<class = void>
0218     void
0219     pass();
0220 
0221     /** Record a failure.
0222 
0223         @param reason Optional text added to the output on a failure.
0224 
0225         @param file The source code file where the test failed.
0226 
0227         @param line The source code line number where the test failed.
0228     */
0229     /** @{ */
0230     template<class String>
0231     void
0232     fail(String const& reason, char const* file, int line);
0233 
0234     template<class = void>
0235     void
0236     fail(std::string const& reason = "");
0237     /** @} */
0238 
0239     /** Evaluate a test condition.
0240 
0241         This function provides improved logging by incorporating the
0242         file name and line number into the reported output on failure,
0243         as well as additional text specified by the caller.
0244 
0245         @param shouldBeTrue The condition to test. The condition
0246         is evaluated in a boolean context.
0247 
0248         @param reason Optional added text to output on a failure.
0249 
0250         @param file The source code file where the test failed.
0251 
0252         @param line The source code line number where the test failed.
0253 
0254         @return `true` if the test condition indicates success.
0255     */
0256     /** @{ */
0257     template<class Condition>
0258     bool
0259     expect(Condition const& shouldBeTrue)
0260     {
0261         return expect(shouldBeTrue, "");
0262     }
0263 
0264     template<class Condition, class String>
0265     bool
0266     expect(Condition const& shouldBeTrue, String const& reason);
0267 
0268     template<class Condition>
0269     bool
0270     expect(Condition const& shouldBeTrue,
0271         char const* file, int line)
0272     {
0273         return expect(shouldBeTrue, "", file, line);
0274     }
0275 
0276     template<class Condition, class String>
0277     bool
0278     expect(Condition const& shouldBeTrue,
0279         String const& reason, char const* file, int line);
0280     /** @} */
0281 
0282     //
0283     // DEPRECATED
0284     //
0285     // Expect an exception from f()
0286     template<class F, class String>
0287     bool
0288     except(F&& f, String const& reason);
0289     template<class F>
0290     bool
0291     except(F&& f)
0292     {
0293         return except(f, "");
0294     }
0295     template<class E, class F, class String>
0296     bool
0297     except(F&& f, String const& reason);
0298     template<class E, class F>
0299     bool
0300     except(F&& f)
0301     {
0302         return except<E>(f, "");
0303     }
0304     template<class F, class String>
0305     bool
0306     unexcept(F&& f, String const& reason);
0307     template<class F>
0308     bool
0309     unexcept(F&& f)
0310     {
0311         return unexcept(f, "");
0312     }
0313 
0314     /** Return the argument associated with the runner. */
0315     std::string const&
0316     arg() const
0317     {
0318         return runner_->arg();
0319     }
0320 
0321     // DEPRECATED
0322     // @return `true` if the test condition indicates success(a false value)
0323     template<class Condition, class String>
0324     bool
0325     unexpected(Condition shouldBeFalse,
0326         String const& reason);
0327 
0328     template<class Condition>
0329     bool
0330     unexpected(Condition shouldBeFalse)
0331     {
0332         return unexpected(shouldBeFalse, "");
0333     }
0334 
0335 private:
0336     friend class thread;
0337 
0338     static
0339     suite**
0340     p_this_suite()
0341     {
0342         static suite* pts = nullptr;
0343         return &pts;
0344     }
0345 
0346     /** Runs the suite. */
0347     virtual
0348     void
0349     run() = 0;
0350 
0351     void
0352     propagate_abort();
0353 
0354     template<class = void>
0355     void
0356     run(runner& r);
0357 };
0358 
0359 //------------------------------------------------------------------------------
0360 
0361 // Helper for streaming testcase names
0362 class suite::scoped_testcase
0363 {
0364 private:
0365     suite& suite_;
0366     std::stringstream& ss_;
0367 
0368 public:
0369     scoped_testcase& operator=(scoped_testcase const&) = delete;
0370 
0371     ~scoped_testcase()
0372     {
0373         auto const& name = ss_.str();
0374         if(! name.empty())
0375             suite_.runner_->testcase(name);
0376     }
0377 
0378     scoped_testcase(suite& self, std::stringstream& ss)
0379         : suite_(self)
0380         , ss_(ss)
0381     {
0382         ss_.clear();
0383         ss_.str({});
0384     }
0385 
0386     template<class T>
0387     scoped_testcase(suite& self,
0388             std::stringstream& ss, T const& t)
0389         : suite_(self)
0390         , ss_(ss)
0391     {
0392         ss_.clear();
0393         ss_.str({});
0394         ss_ << t;
0395     }
0396 
0397     template<class T>
0398     scoped_testcase&
0399     operator<<(T const& t)
0400     {
0401         ss_ << t;
0402         return *this;
0403     }
0404 };
0405 
0406 //------------------------------------------------------------------------------
0407 
0408 inline
0409 void
0410 suite::testcase_t::operator()(
0411     std::string const& name, abort_t abort)
0412 {
0413     suite_.abort_ = abort == abort_on_fail;
0414     suite_.runner_->testcase(name);
0415 }
0416 
0417 inline
0418 suite::scoped_testcase
0419 suite::testcase_t::operator()(abort_t abort)
0420 {
0421     suite_.abort_ = abort == abort_on_fail;
0422     return { suite_, ss_ };
0423 }
0424 
0425 template<class T>
0426 inline
0427 suite::scoped_testcase
0428 suite::testcase_t::operator<<(T const& t)
0429 {
0430     return { suite_, ss_, t };
0431 }
0432 
0433 //------------------------------------------------------------------------------
0434 
0435 template<class>
0436 void
0437 suite::
0438 operator()(runner& r)
0439 {
0440     *p_this_suite() = this;
0441     try
0442     {
0443         run(r);
0444         *p_this_suite() = nullptr;
0445     }
0446     catch(...)
0447     {
0448         *p_this_suite() = nullptr;
0449         throw;
0450     }
0451 }
0452 
0453 template<class Condition, class String>
0454 bool
0455 suite::
0456 expect(
0457     Condition const& shouldBeTrue, String const& reason)
0458 {
0459     if(shouldBeTrue)
0460     {
0461         pass();
0462         return true;
0463     }
0464     fail(reason);
0465     return false;
0466 }
0467 
0468 template<class Condition, class String>
0469 bool
0470 suite::
0471 expect(Condition const& shouldBeTrue,
0472     String const& reason, char const* file, int line)
0473 {
0474     if(shouldBeTrue)
0475     {
0476         pass();
0477         return true;
0478     }
0479     fail(detail::make_reason(reason, file, line));
0480     return false;
0481 }
0482 
0483 // DEPRECATED
0484 
0485 template<class F, class String>
0486 bool
0487 suite::
0488 except(F&& f, String const& reason)
0489 {
0490     try
0491     {
0492         f();
0493         fail(reason);
0494         return false;
0495     }
0496     catch(...)
0497     {
0498         pass();
0499     }
0500     return true;
0501 }
0502 
0503 template<class E, class F, class String>
0504 bool
0505 suite::
0506 except(F&& f, String const& reason)
0507 {
0508     try
0509     {
0510         f();
0511         fail(reason);
0512         return false;
0513     }
0514     catch(E const&)
0515     {
0516         pass();
0517     }
0518     return true;
0519 }
0520 
0521 template<class F, class String>
0522 bool
0523 suite::
0524 unexcept(F&& f, String const& reason)
0525 {
0526     try
0527     {
0528         f();
0529         pass();
0530         return true;
0531     }
0532     catch(...)
0533     {
0534         fail(reason);
0535     }
0536     return false;
0537 }
0538 
0539 template<class Condition, class String>
0540 bool
0541 suite::
0542 unexpected(
0543     Condition shouldBeFalse, String const& reason)
0544 {
0545     bool const b =
0546         static_cast<bool>(shouldBeFalse);
0547     if(! b)
0548         pass();
0549     else
0550         fail(reason);
0551     return ! b;
0552 }
0553 
0554 template<class>
0555 void
0556 suite::
0557 pass()
0558 {
0559     propagate_abort();
0560     runner_->pass();
0561 }
0562 
0563 // ::fail
0564 template<class>
0565 void
0566 suite::
0567 fail(std::string const& reason)
0568 {
0569     propagate_abort();
0570     runner_->fail(reason);
0571     if(abort_)
0572     {
0573         aborted_ = true;
0574         BOOST_THROW_EXCEPTION(abort_exception());
0575     }
0576 }
0577 
0578 template<class String>
0579 void
0580 suite::
0581 fail(String const& reason, char const* file, int line)
0582 {
0583     fail(detail::make_reason(reason, file, line));
0584 }
0585 
0586 inline
0587 void
0588 suite::
0589 propagate_abort()
0590 {
0591     if(abort_ && aborted_)
0592         BOOST_THROW_EXCEPTION(abort_exception());
0593 }
0594 
0595 template<class>
0596 void
0597 suite::
0598 run(runner& r)
0599 {
0600     runner_ = &r;
0601 
0602     try
0603     {
0604         run();
0605     }
0606     catch(abort_exception const&)
0607     {
0608         // ends the suite
0609     }
0610     catch(std::exception const& e)
0611     {
0612         runner_->fail("unhandled exception: " +
0613             std::string(e.what()));
0614     }
0615     catch(...)
0616     {
0617         runner_->fail("unhandled exception");
0618     }
0619 }
0620 
0621 #ifndef BEAST_PASS
0622 #define BEAST_PASS() ::boost::beast::unit_test::suite::this_suite()->pass()
0623 #endif
0624 
0625 #ifndef BEAST_FAIL
0626 #define BEAST_FAIL() ::boost::beast::unit_test::suite::this_suite()->fail("", __FILE__, __LINE__)
0627 #endif
0628 
0629 #ifndef BEAST_EXPECT
0630 /** Check a precondition.
0631 
0632     If the condition is false, the file and line number are reported.
0633 */
0634 #define BEAST_EXPECT(cond) ::boost::beast::unit_test::suite::this_suite()->expect(cond, __FILE__, __LINE__)
0635 #endif
0636 
0637 #ifndef BEAST_EXPECTS
0638 /** Check a precondition.
0639 
0640     If the condition is false, the file and line number are reported.
0641 */
0642 #define BEAST_EXPECTS(cond, reason) ((cond) ? \
0643     (::boost::beast::unit_test::suite::this_suite()->pass(), true) : \
0644     (::boost::beast::unit_test::suite::this_suite()->fail((reason), __FILE__, __LINE__), false))
0645 #endif
0646 
0647 /** Ensure an exception is thrown
0648 */
0649 #define BEAST_THROWS( EXPR, EXCEP ) \
0650     try { \
0651         EXPR; \
0652         BEAST_FAIL(); \
0653     } \
0654     catch(EXCEP const&) { \
0655         BEAST_PASS(); \
0656     } \
0657     catch(...) { \
0658         BEAST_FAIL(); \
0659     }
0660 
0661 /** Ensure an exception is not thrown
0662 */
0663 #define BEAST_NO_THROW( EXPR ) \
0664     try { \
0665         EXPR; \
0666         BEAST_PASS(); \
0667     } \
0668     catch(...) { \
0669         BEAST_FAIL(); \
0670     }
0671 
0672 } // unit_test
0673 } // beast
0674 } // boost
0675 
0676 //------------------------------------------------------------------------------
0677 
0678 // detail:
0679 // This inserts the suite with the given manual flag
0680 #define BEAST_DEFINE_TESTSUITE_INSERT(Library,Module,Class,manual) \
0681     static ::boost::beast::unit_test::detail::insert_suite <Class##_test>   \
0682         Library ## Module ## Class ## _test_instance(             \
0683             #Class, #Module, #Library, manual)
0684 
0685 //------------------------------------------------------------------------------
0686 
0687 // Preprocessor directives for controlling unit test definitions.
0688 
0689 // If this is already defined, don't redefine it. This allows
0690 // programs to provide custom behavior for testsuite definitions
0691 //
0692 #ifndef BEAST_DEFINE_TESTSUITE
0693 
0694 /** Enables insertion of test suites into the global container.
0695     The default is to insert all test suite definitions into the global
0696     container. If BEAST_DEFINE_TESTSUITE is user defined, this macro
0697     has no effect.
0698 */
0699 #ifndef BEAST_NO_UNIT_TEST_INLINE
0700 #define BEAST_NO_UNIT_TEST_INLINE 0
0701 #endif
0702 
0703 /** Define a unit test suite.
0704 
0705     Library   Identifies the library.
0706     Module    Identifies the module.
0707     Class     The type representing the class being tested.
0708 
0709     The declaration for the class implementing the test should be the same
0710     as Class ## _test. For example, if Class is aged_ordered_container, the
0711     test class must be declared as:
0712 
0713     @code
0714 
0715     struct aged_ordered_container_test : beast::unit_test::suite
0716     {
0717         //...
0718     };
0719 
0720     @endcode
0721 
0722     The macro invocation must appear in the same namespace as the test class.
0723 */
0724 
0725 #if BEAST_NO_UNIT_TEST_INLINE
0726 #define BEAST_DEFINE_TESTSUITE(Class,Module,Library)
0727 
0728 #else
0729 #include <boost/beast/_experimental/unit_test/global_suites.hpp>
0730 #define BEAST_DEFINE_TESTSUITE(Library,Module,Class) \
0731         BEAST_DEFINE_TESTSUITE_INSERT(Library,Module,Class,false)
0732 #define BEAST_DEFINE_TESTSUITE_MANUAL(Library,Module,Class) \
0733         BEAST_DEFINE_TESTSUITE_INSERT(Library,Module,Class,true)
0734 
0735 #endif
0736 
0737 #endif
0738 
0739 #if defined(BOOST_GCC) && BOOST_GCC >= 70000 && BOOST_GCC < 80000
0740 #pragma GCC diagnostic pop
0741 #endif
0742 
0743 //------------------------------------------------------------------------------
0744 
0745 #endif