Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:29:23

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