File indexing completed on 2025-12-17 09:40:01
0001
0002
0003
0004
0005
0006
0007
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 }
0057
0058 class thread;
0059
0060 enum abort_t
0061 {
0062 no_abort_on_fail,
0063 abort_on_fail
0064 };
0065
0066
0067
0068
0069
0070
0071
0072
0073 class suite
0074 {
0075 private:
0076 bool abort_ = false;
0077 bool aborted_ = false;
0078 runner* runner_ = nullptr;
0079
0080
0081
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
0153
0154
0155
0156
0157
0158
0159
0160
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
0176
0177
0178
0179
0180 log_os<char> log;
0181
0182
0183 testcase_t testcase;
0184
0185
0186
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
0206
0207
0208
0209
0210
0211
0212 template<class = void>
0213 void
0214 operator()(runner& r);
0215
0216
0217 template<class = void>
0218 void
0219 pass();
0220
0221
0222
0223
0224
0225
0226
0227
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
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
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
0284
0285
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
0315 std::string const&
0316 arg() const
0317 {
0318 return runner_->arg();
0319 }
0320
0321
0322
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
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
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
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
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
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
0631
0632
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
0639
0640
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
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
0662
0663 #define BEAST_NO_THROW( EXPR ) \
0664 try { \
0665 EXPR; \
0666 BEAST_PASS(); \
0667 } \
0668 catch(...) { \
0669 BEAST_FAIL(); \
0670 }
0671
0672 }
0673 }
0674 }
0675
0676
0677
0678
0679
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
0688
0689
0690
0691
0692 #ifndef BEAST_DEFINE_TESTSUITE
0693
0694
0695
0696
0697
0698
0699 #ifndef BEAST_NO_UNIT_TEST_INLINE
0700 #define BEAST_NO_UNIT_TEST_INLINE 0
0701 #endif
0702
0703
0704
0705
0706
0707
0708
0709
0710
0711
0712
0713
0714
0715
0716
0717
0718
0719
0720
0721
0722
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