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/filesystem.hpp>
10#include <boost/lexical_cast.hpp>
11#include <boost/throw_exception.hpp>
12
13#include <ostream>
14#include <sstream>
15#include <string>
16
17namespace beast::unit_test {
18
19namespace detail {
20
21template <class String>
22static std::string
23makeReason(String const& reason, char const* file, int line)
24{
25 std::string s(reason);
26 if (!s.empty())
27 s.append(": ");
28 namespace fs = boost::filesystem;
29 s.append(fs::path{file}.filename().string());
30 s.append("(");
31 s.append(boost::lexical_cast<std::string>(line));
32 s.append(")");
33 return s;
34}
35
36} // namespace detail
37
38class Thread;
39
41
49class Suite
50{
51private:
52 bool abort_ = false;
53 bool aborted_ = false;
54 Runner* runner_ = nullptr;
55
56 // This exception is thrown internally to stop the current suite
57 // in the event of a failure, if the option to stop is set.
59 {
60 [[nodiscard]] char const*
61 what() const noexcept override
62 {
63 return "test suite aborted";
64 }
65 };
66
67 template <class CharT, class Traits, class Allocator>
68 class LogBuf : public std::basic_stringbuf<CharT, Traits, Allocator>
69 {
71
72 public:
73 explicit LogBuf(Suite& self) : suite_(self)
74 {
75 }
76
77 ~LogBuf() override
78 {
79 sync();
80 }
81
82 int
83 sync() override
84 {
85 auto const& s = this->str();
86 if (s.size() > 0)
87 suite_.runner_->log(s);
88 this->str("");
89 return 0;
90 }
91 };
92
93 template <
94 class CharT,
95 class Traits = std::char_traits<CharT>,
96 class Allocator = std::allocator<CharT>>
97 class LogOs : public std::basic_ostream<CharT, Traits>
98 {
100
101 public:
102 explicit LogOs(Suite& self) : std::basic_ostream<CharT, Traits>(&buf_), buf_(self)
103 {
104 }
105 };
106
107 class ScopedTestcase;
108
110 {
113
114 public:
115 explicit TestcaseT(Suite& self) : suite_(self)
116 {
117 }
118
129 void
131
133 operator()(AbortT abort);
134
135 template <class T>
137 operator<<(T const& t);
138 };
139
140public:
147
150
154 static Suite*
156 {
157 return *pThisSuite();
158 }
159
160 Suite() : log(*this), testcase(*this)
161 {
162 }
163
164 virtual ~Suite() = default;
165 Suite(Suite const&) = delete;
166 Suite&
167 operator=(Suite const&) = delete;
168
176 template <class = void>
177 void
178 operator()(Runner& r);
179
181 template <class = void>
182 void
183 pass();
184
194 template <class String>
195 void
196 fail(String const& reason, char const* file, int line);
197
198 template <class = void>
199 void
200 fail(std::string const& reason = "");
202
221 template <class Condition>
222 bool
223 expect(Condition const& shouldBeTrue)
224 {
225 return expect(shouldBeTrue, "");
226 }
227
228 template <class Condition, class String>
229 bool
230 expect(Condition const& shouldBeTrue, String const& reason);
231
232 template <class Condition>
233 bool
234 expect(Condition const& shouldBeTrue, char const* file, int line)
235 {
236 return expect(shouldBeTrue, "", file, line);
237 }
238
239 template <class Condition, class String>
240 bool
241 expect(Condition const& shouldBeTrue, String const& reason, char const* file, int line);
243
244 //
245 // DEPRECATED
246 //
247 // Expect an exception from f()
248 template <class F, class String>
249 bool
250 except(F&& f, String const& reason);
251 template <class F>
252 bool
253 except(F&& f)
254 {
255 return except(f, "");
256 }
257 template <class E, class F, class String>
258 bool
259 except(F&& f, String const& reason);
260 template <class E, class F>
261 bool
262 except(F&& f)
263 {
264 return except<E>(f, "");
265 }
266 template <class F, class String>
267 bool
268 unexcept(F&& f, String const& reason);
269 template <class F>
270 bool
271 unexcept(F&& f)
272 {
273 return unexcept(f, "");
274 }
275
277 std::string const&
278 arg() const
279 {
280 return runner_->arg();
281 }
282
283 // DEPRECATED
284 // @return `true` if the test condition indicates success(a false value)
285 template <class Condition, class String>
286 bool
287 unexpected(Condition shouldBeFalse, String const& reason);
288
289 template <class Condition>
290 bool
291 unexpected(Condition shouldBeFalse)
292 {
293 return unexpected(shouldBeFalse, "");
294 }
295
296private:
297 friend class Thread;
298
299 static Suite**
301 {
302 static Suite* kPTs = nullptr; // NOLINT TODO
303 return &kPTs;
304 }
305
307 virtual void
308 run() = 0;
309
310 void
311 propagateAbort() const;
312
313 template <class = void>
314 void
315 run(Runner& r);
316};
317
318//------------------------------------------------------------------------------
319
320// Helper for streaming testcase names
322{
323private:
326
327public:
329 operator=(ScopedTestcase const&) = delete;
330
332 {
333 auto const& name = ss_.str();
334 if (!name.empty())
335 suite_.runner_->testcase(name);
336 }
337
339 {
340 ss_.clear();
341 ss_.str({});
342 }
343
344 template <class T>
345 ScopedTestcase(Suite& self, std::stringstream& ss, T const& t) : suite_(self), ss_(ss)
346 {
347 ss_.clear();
348 ss_.str({});
349 ss_ << t;
350 }
351
352 template <class T>
354 operator<<(T const& t)
355 {
356 ss_ << t;
357 return *this;
358 }
359};
360
361//------------------------------------------------------------------------------
362
363inline void
365{
366 suite_.abort_ = abort == AbortT::AbortOnFail;
367 suite_.runner_->testcase(name);
368}
369
372{
373 suite_.abort_ = abort == AbortT::AbortOnFail;
374 return {suite_, ss_};
375}
376
377template <class T>
380{
381 return {suite_, ss_, t};
382}
383
384//------------------------------------------------------------------------------
385
386template <class>
387void
389{
390 *pThisSuite() = this;
391 try
392 {
393 run(r);
394 *pThisSuite() = nullptr;
395 }
396 catch (...)
397 {
398 *pThisSuite() = nullptr;
399 throw;
400 }
401}
402
403template <class Condition, class String>
404bool
405Suite::expect(Condition const& shouldBeTrue, String const& reason)
406{
407 if (shouldBeTrue)
408 {
409 pass();
410 return true;
411 }
412 fail(reason);
413 return false;
414}
415
416template <class Condition, class String>
417bool
418Suite::expect(Condition const& shouldBeTrue, String const& reason, char const* file, int line)
419{
420 if (shouldBeTrue)
421 {
422 pass();
423 return true;
424 }
425 fail(detail::makeReason(reason, file, line));
426 return false;
427}
428
429// DEPRECATED
430
431template <class F, class String>
432bool
433Suite::except(F&& f, String const& reason)
434{
435 try
436 {
437 f();
438 fail(reason);
439 return false;
440 }
441 catch (...)
442 {
443 pass();
444 }
445 return true;
446}
447
448template <class E, class F, class String>
449bool
450Suite::except(F&& f, String const& reason)
451{
452 try
453 {
454 f();
455 fail(reason);
456 return false;
457 }
458 catch (E const&)
459 {
460 pass();
461 }
462 return true;
463}
464
465template <class F, class String>
466bool
467Suite::unexcept(F&& f, String const& reason)
468{
469 try
470 {
471 f();
472 pass();
473 return true;
474 }
475 catch (...)
476 {
477 fail(reason);
478 }
479 return false;
480}
481
482template <class Condition, class String>
483bool
484Suite::unexpected(Condition shouldBeFalse, String const& reason)
485{
486 bool const b = static_cast<bool>(shouldBeFalse);
487 if (!b)
488 {
489 pass();
490 }
491 else
492 {
493 fail(reason);
494 }
495 return !b;
496}
497
498template <class>
499void
501{
503 runner_->pass();
504}
505
506// ::fail
507template <class>
508void
510{
512 runner_->fail(reason);
513 if (abort_)
514 {
515 aborted_ = true;
516 BOOST_THROW_EXCEPTION(AbortException());
517 }
518}
519
520template <class String>
521void
522Suite::fail(String const& reason, char const* file, int line)
523{
524 fail(detail::makeReason(reason, file, line));
525}
526
527inline void
529{
530 if (abort_ && aborted_)
531 BOOST_THROW_EXCEPTION(AbortException());
532}
533
534template <class>
535void
537{
538 runner_ = &r;
539
540 try
541 {
542 run();
543 }
544 catch (AbortException const&) // NOLINT(bugprone-empty-catch)
545 {
546 // ends the suite
547 }
548 catch (std::exception const& e)
549 {
550 runner_->fail("unhandled exception: " + std::string(e.what()));
551 }
552 catch (...)
553 {
554 runner_->fail("unhandled exception");
555 }
556}
557
558#ifndef BEAST_EXPECT
563#define BEAST_EXPECT(cond) expect(cond, __FILE__, __LINE__)
564#endif
565
566#ifndef BEAST_EXPECTS
571#define BEAST_EXPECTS(cond, reason) \
572 ((cond) ? (pass(), true) : (fail((reason), __FILE__, __LINE__), false))
573#endif
574
575} // namespace beast::unit_test
576
577//------------------------------------------------------------------------------
578
579// detail:
580// This inserts the suite with the given manual flag
581#define BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, manual, priority) \
582 static beast::unit_test::detail::InsertSuite<Class##_test> \
583 Library##Module##Class##_test_instance(#Class, #Module, #Library, manual, priority)
584
585//------------------------------------------------------------------------------
586
587// Preprocessor directives for controlling unit test definitions.
588
589// If this is already defined, don't redefine it. This allows
590// programs to provide custom behavior for testsuite definitions
591//
592#ifndef BEAST_DEFINE_TESTSUITE
593
599#ifndef BEAST_NO_UNIT_TEST_INLINE
600#define BEAST_NO_UNIT_TEST_INLINE 0
601#endif
602
629
630#if BEAST_NO_UNIT_TEST_INLINE
631#define BEAST_DEFINE_TESTSUITE(Class, Module, Library)
632#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library)
633#define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority)
634#define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority)
635
636#else
637#include <xrpl/beast/unit_test/global_suites.h>
638#define BEAST_DEFINE_TESTSUITE(Class, Module, Library) \
639 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, 0)
640#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library) \
641 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, 0)
642#define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority) \
643 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, Priority)
644#define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority) \
645 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, Priority)
646#endif
647
648#endif
649
650//------------------------------------------------------------------------------
T append(T... args)
Unit test runner interface.
Definition runner.h:22
LogBuf< CharT, Traits, Allocator > buf_
Definition suite.h:99
ScopedTestcase & operator=(ScopedTestcase const &)=delete
ScopedTestcase(Suite &self, std::stringstream &ss)
Definition suite.h:338
ScopedTestcase(Suite &self, std::stringstream &ss, T const &t)
Definition suite.h:345
ScopedTestcase & operator<<(T const &t)
Definition suite.h:354
ScopedTestcase operator<<(T const &t)
void operator()(std::string const &name, AbortT abort=AbortT::NoAbortOnFail)
Open a new testcase.
Definition suite.h:364
bool except(F &&f, String const &reason)
Definition suite.h:433
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition suite.h:484
bool unexcept(F &&f, String const &reason)
Definition suite.h:467
void pass()
Record a successful test condition.
Definition suite.h:500
void propagateAbort() const
Definition suite.h:528
static Suite * thisSuite()
Returns the "current" running suite.
Definition suite.h:155
void operator()(Runner &r)
Invokes the test using the specified runner.
Definition suite.h:388
Suite & operator=(Suite const &)=delete
virtual ~Suite()=default
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition suite.h:223
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:522
bool except(F &&f)
Definition suite.h:262
bool expect(Condition const &shouldBeTrue, char const *file, int line)
Definition suite.h:234
Suite(Suite const &)=delete
virtual void run()=0
Runs the suite.
static Suite ** pThisSuite()
Definition suite.h:300
LogOs< char > log
Logging output stream.
Definition suite.h:146
bool except(F &&f)
Definition suite.h:253
bool unexpected(Condition shouldBeFalse)
Definition suite.h:291
bool unexcept(F &&f)
Definition suite.h:271
friend class Thread
Definition suite.h:297
TestcaseT testcase
Memberspace for declaring test cases.
Definition suite.h:149
std::string const & arg() const
Return the argument associated with the runner.
Definition suite.h:278
T empty(T... args)
static std::string makeReason(String const &reason, char const *file, int line)
Definition suite.h:23
STL namespace.
char const * what() const noexcept override
Definition suite.h:61
T what(T... args)