xrpld
Loading...
Searching...
No Matches
suite.h
1// Distributed under the Boost Software License, Version 1.0. (See accompanying
2// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
3//
4
5#pragma once
6
7#include <xrpl/beast/unit_test/runner.h>
8
9#include <boost/throw_exception.hpp>
10
11#include <exception>
12#include <filesystem>
13#include <memory>
14#include <ostream>
15#include <sstream>
16#include <string>
17
18namespace beast::unit_test {
19
20namespace detail {
21
22template <class String>
23static std::string
24makeReason(String const& reason, char const* file, int line)
25{
26 std::string s(reason);
27 if (!s.empty())
28 s.append(": ");
29 namespace fs = std::filesystem;
30 s.append(fs::path{file}.filename().string());
31 s.append("(");
32 s.append(std::to_string(line));
33 s.append(")");
34 return s;
35}
36
37} // namespace detail
38
39class Thread;
40
42
51class Suite
52{
53private:
54 bool abort_ = false;
55 bool aborted_ = false;
56 Runner* runner_ = nullptr;
57
58 // This exception is thrown internally to stop the current suite
59 // in the event of a failure, if the option to stop is set.
61 {
62 [[nodiscard]] char const*
63 what() const noexcept override
64 {
65 return "test suite aborted";
66 }
67 };
68
69 template <class CharT, class Traits, class Allocator>
70 class LogBuf : public std::basic_stringbuf<CharT, Traits, Allocator>
71 {
73
74 public:
75 explicit LogBuf(Suite& self) : suite_(self)
76 {
77 }
78
79 ~LogBuf() override
80 {
81 sync();
82 }
83
84 int
85 sync() override
86 {
87 auto const& s = this->str();
88 if (s.size() > 0)
89 suite_.runner_->log(s);
90 this->str("");
91 return 0;
92 }
93 };
94
95 template <
96 class CharT,
97 class Traits = std::char_traits<CharT>,
98 class Allocator = std::allocator<CharT>>
99 class LogOs : public std::basic_ostream<CharT, Traits>
100 {
102
103 public:
104 explicit LogOs(Suite& self) : std::basic_ostream<CharT, Traits>(&buf_), buf_(self)
105 {
106 }
107 };
108
109 class ScopedTestcase;
110
112 {
115
116 public:
117 explicit TestcaseT(Suite& self) : suite_(self)
118 {
119 }
120
132 void
134
136 operator()(AbortT abort);
137
138 template <class T>
140 operator<<(T const& t);
141 };
142
143public:
151
156
161 static Suite*
163 {
164 return *pThisSuite();
165 }
166
167 Suite() : log(*this), testcase(*this)
168 {
169 }
170
171 virtual ~Suite() = default;
172 Suite(Suite const&) = delete;
173 Suite&
174 operator=(Suite const&) = delete;
175
184 template <class = void>
185 void
186 operator()(Runner& r);
187
191 template <class = void>
192 void
193 pass();
194
205 template <class String>
206 void
207 fail(String const& reason, char const* file, int line);
208
209 template <class = void>
210 void
211 fail(std::string const& reason = "");
213
233 template <class Condition>
234 bool
235 expect(Condition const& shouldBeTrue)
236 {
237 return expect(shouldBeTrue, "");
238 }
239
240 template <class Condition, class String>
241 bool
242 expect(Condition const& shouldBeTrue, String const& reason);
243
244 template <class Condition>
245 bool
246 expect(Condition const& shouldBeTrue, char const* file, int line)
247 {
248 return expect(shouldBeTrue, "", file, line);
249 }
250
251 template <class Condition, class String>
252 bool
253 expect(Condition const& shouldBeTrue, String const& reason, char const* file, int line);
255
256 //
257 // DEPRECATED
258 //
259 // Expect an exception from f()
260 template <class F, class String>
261 bool
262 except(F&& f, String const& reason);
263 template <class F>
264 bool
265 except(F&& f)
266 {
267 return except(f, "");
268 }
269 template <class E, class F, class String>
270 bool
271 except(F&& f, String const& reason);
272 template <class E, class F>
273 bool
274 except(F&& f)
275 {
276 return except<E>(f, "");
277 }
278 template <class F, class String>
279 bool
280 unexcept(F&& f, String const& reason);
281 template <class F>
282 bool
283 unexcept(F&& f)
284 {
285 return unexcept(f, "");
286 }
287
291 std::string const&
292 arg() const
293 {
294 return runner_->arg();
295 }
296
297protected:
304 Runner&
305 runner() const
306 {
307 return *runner_;
308 }
309
310public:
315 template <class Condition, class String>
316 bool
317 unexpected(Condition shouldBeFalse, String const& reason);
318
319 template <class Condition>
320 bool
321 unexpected(Condition shouldBeFalse)
322 {
323 return unexpected(shouldBeFalse, "");
324 }
325
326private:
327 friend class Thread;
328
329 static Suite**
331 {
332 static Suite* kPTs = nullptr; // NOLINT TODO
333 return &kPTs;
334 }
335
339 virtual void
340 run() = 0;
341
342 void
343 propagateAbort() const;
344
345 template <class = void>
346 void
347 run(Runner& r);
348};
349
350//------------------------------------------------------------------------------
351
352// Helper for streaming testcase names
354{
355private:
358
359public:
361 operator=(ScopedTestcase const&) = delete;
362
364 {
365 auto const& name = ss_.str();
366 if (!name.empty())
367 suite_.runner_->testcase(name);
368 }
369
371 {
372 ss_.clear();
373 ss_.str({});
374 }
375
376 template <class T>
377 ScopedTestcase(Suite& self, std::stringstream& ss, T const& t) : suite_(self), ss_(ss)
378 {
379 ss_.clear();
380 ss_.str({});
381 ss_ << t;
382 }
383
384 template <class T>
386 operator<<(T const& t)
387 {
388 ss_ << t;
389 return *this;
390 }
391};
392
393//------------------------------------------------------------------------------
394
395inline void
397{
398 suite_.abort_ = abort == AbortT::AbortOnFail;
399 suite_.runner_->testcase(name);
400}
401
404{
405 suite_.abort_ = abort == AbortT::AbortOnFail;
406 return {suite_, ss_};
407}
408
409template <class T>
412{
413 return {suite_, ss_, t};
414}
415
416//------------------------------------------------------------------------------
417
418template <class>
419void
421{
422 *pThisSuite() = this;
423 try
424 {
425 run(r);
426 *pThisSuite() = nullptr;
427 }
428 catch (...)
429 {
430 *pThisSuite() = nullptr;
431 throw;
432 }
433}
434
435template <class Condition, class String>
436bool
437Suite::expect(Condition const& shouldBeTrue, String const& reason)
438{
439 if (shouldBeTrue)
440 {
441 pass();
442 return true;
443 }
444 fail(reason);
445 return false;
446}
447
448template <class Condition, class String>
449bool
450Suite::expect(Condition const& shouldBeTrue, String const& reason, char const* file, int line)
451{
452 if (shouldBeTrue)
453 {
454 pass();
455 return true;
456 }
457 fail(detail::makeReason(reason, file, line));
458 return false;
459}
460
461// DEPRECATED
462
463template <class F, class String>
464bool
465Suite::except(F&& f, String const& reason)
466{
467 try
468 {
469 f();
470 fail(reason);
471 return false;
472 }
473 catch (...)
474 {
475 pass();
476 }
477 return true;
478}
479
480template <class E, class F, class String>
481bool
482Suite::except(F&& f, String const& reason)
483{
484 try
485 {
486 f();
487 fail(reason);
488 return false;
489 }
490 catch (E const&)
491 {
492 pass();
493 }
494 return true;
495}
496
497template <class F, class String>
498bool
499Suite::unexcept(F&& f, String const& reason)
500{
501 try
502 {
503 f();
504 pass();
505 return true;
506 }
507 catch (...)
508 {
509 fail(reason);
510 }
511 return false;
512}
513
514template <class Condition, class String>
515bool
516Suite::unexpected(Condition shouldBeFalse, String const& reason)
517{
518 bool const b = static_cast<bool>(shouldBeFalse);
519 if (!b)
520 {
521 pass();
522 }
523 else
524 {
525 fail(reason);
526 }
527 return !b;
528}
529
530template <class>
531void
533{
535 runner_->pass();
536}
537
538// ::fail
539template <class>
540void
542{
544 runner_->fail(reason);
545 if (abort_)
546 {
547 aborted_ = true;
548 BOOST_THROW_EXCEPTION(AbortException());
549 }
550}
551
552template <class String>
553void
554Suite::fail(String const& reason, char const* file, int line)
555{
556 fail(detail::makeReason(reason, file, line));
557}
558
559inline void
561{
562 if (abort_ && aborted_)
563 BOOST_THROW_EXCEPTION(AbortException());
564}
565
566template <class>
567void
569{
570 runner_ = &r;
571
572 try
573 {
574 run();
575 }
576 catch (AbortException const&) // NOLINT(bugprone-empty-catch)
577 {
578 // ends the suite
579 }
580 catch (std::exception const& e)
581 {
582 runner_->fail("unhandled exception: " + std::string(e.what()));
583 }
584 catch (...)
585 {
586 runner_->fail("unhandled exception");
587 }
588}
589
590#ifndef BEAST_EXPECT
596#define BEAST_EXPECT(cond) expect(cond, __FILE__, __LINE__)
597#endif
598
599#ifndef BEAST_EXPECTS
605#define BEAST_EXPECTS(cond, reason) \
606 ((cond) ? (pass(), true) : (fail((reason), __FILE__, __LINE__), false))
607#endif
608
609} // namespace beast::unit_test
610
611//------------------------------------------------------------------------------
612
613// detail:
614// This inserts the suite with the given manual flag
615#define BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, manual, priority) \
616 static beast::unit_test::detail::InsertSuite<Class##_test> \
617 Library##Module##Class##_test_instance(#Class, #Module, #Library, manual, priority)
618
619//------------------------------------------------------------------------------
620
621// Preprocessor directives for controlling unit test definitions.
622
623// If this is already defined, don't redefine it. This allows
624// programs to provide custom behavior for testsuite definitions
625//
626#ifndef BEAST_DEFINE_TESTSUITE
627
634#ifndef BEAST_NO_UNIT_TEST_INLINE
635#define BEAST_NO_UNIT_TEST_INLINE 0
636#endif
637
665
666#if BEAST_NO_UNIT_TEST_INLINE
667#define BEAST_DEFINE_TESTSUITE(Class, Module, Library)
668#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library)
669#define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority)
670#define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority)
671
672#else
673#include <xrpl/beast/unit_test/global_suites.h> // IWYU pragma: keep
674#define BEAST_DEFINE_TESTSUITE(Class, Module, Library) \
675 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, 0)
676#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library) \
677 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, 0)
678#define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority) \
679 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, Priority)
680#define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority) \
681 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, Priority)
682#endif
683
684#endif
685
686//------------------------------------------------------------------------------
T append(T... args)
Unit test runner interface.
Definition runner.h:23
LogBuf< CharT, Traits, Allocator > buf_
Definition suite.h:101
ScopedTestcase & operator=(ScopedTestcase const &)=delete
ScopedTestcase(Suite &self, std::stringstream &ss)
Definition suite.h:370
ScopedTestcase(Suite &self, std::stringstream &ss, T const &t)
Definition suite.h:377
ScopedTestcase & operator<<(T const &t)
Definition suite.h:386
ScopedTestcase operator<<(T const &t)
void operator()(std::string const &name, AbortT abort=AbortT::NoAbortOnFail)
Open a new testcase.
Definition suite.h:396
bool except(F &&f, String const &reason)
Definition suite.h:465
bool unexpected(Condition shouldBeFalse, String const &reason)
DEPRECATED.
Definition suite.h:516
bool unexcept(F &&f, String const &reason)
Definition suite.h:499
void pass()
Record a successful test condition.
Definition suite.h:532
void propagateAbort() const
Definition suite.h:560
static Suite * thisSuite()
Returns the "current" running suite.
Definition suite.h:162
void operator()(Runner &r)
Invokes the test using the specified runner.
Definition suite.h:420
Suite & operator=(Suite const &)=delete
virtual ~Suite()=default
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition suite.h:235
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:554
bool except(F &&f)
Definition suite.h:274
bool expect(Condition const &shouldBeTrue, char const *file, int line)
Definition suite.h:246
Runner & runner() const
Lets a suite compose other suites (e.g.
Definition suite.h:305
Suite(Suite const &)=delete
virtual void run()=0
Runs the suite.
static Suite ** pThisSuite()
Definition suite.h:330
LogOs< char > log
Logging output stream.
Definition suite.h:150
bool except(F &&f)
Definition suite.h:265
bool unexpected(Condition shouldBeFalse)
Definition suite.h:321
bool unexcept(F &&f)
Definition suite.h:283
friend class Thread
Definition suite.h:327
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:155
std::string const & arg() const
Return the argument associated with the runner.
Definition suite.h:292
T empty(T... args)
static std::string makeReason(String const &reason, char const *file, int line)
Definition suite.h:24
STL namespace.
char const * what() const noexcept override
Definition suite.h:63
T to_string(T... args)
T what(T... args)