rippled
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 {
18namespace unit_test {
19
20namespace detail {
21
22template <class String>
23static std::string
24make_reason(String const& reason, char const* file, int line)
25{
26 std::string s(reason);
27 if (!s.empty())
28 s.append(": ");
29 namespace fs = boost::filesystem;
30 s.append(fs::path{file}.filename().string());
31 s.append("(");
32 s.append(boost::lexical_cast<std::string>(line));
33 s.append(")");
34 return s;
35}
36
37} // namespace detail
38
39class thread;
40
42
50class suite
51{
52private:
53 bool abort_ = false;
54 bool aborted_ = false;
55 runner* runner_ = nullptr;
56
57 // This exception is thrown internally to stop the current suite
58 // in the event of a failure, if the option to stop is set.
60 {
61 char const*
62 what() const noexcept override
63 {
64 return "test suite aborted";
65 }
66 };
67
68 template <class CharT, class Traits, class Allocator>
69 class log_buf : public std::basic_stringbuf<CharT, Traits, Allocator>
70 {
72
73 public:
74 explicit log_buf(suite& self) : suite_(self)
75 {
76 }
77
79 {
80 sync();
81 }
82
83 int
84 sync() override
85 {
86 auto const& s = this->str();
87 if (s.size() > 0)
88 suite_.runner_->log(s);
89 this->str("");
90 return 0;
91 }
92 };
93
94 template <class CharT, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT>>
95 class log_os : public std::basic_ostream<CharT, Traits>
96 {
98
99 public:
100 explicit log_os(suite& self) : std::basic_ostream<CharT, Traits>(&buf_), buf_(self)
101 {
102 }
103 };
104
105 class scoped_testcase;
106
108 {
111
112 public:
113 explicit testcase_t(suite& self) : suite_(self)
114 {
115 }
116
127 void
128 operator()(std::string const& name, abort_t abort = no_abort_on_fail);
129
131 operator()(abort_t abort);
132
133 template <class T>
135 operator<<(T const& t);
136 };
137
138public:
145
148
152 static suite*
154 {
155 return *p_this_suite();
156 }
157
158 suite() : log(*this), testcase(*this)
159 {
160 }
161
162 virtual ~suite() = default;
163 suite(suite const&) = delete;
164 suite&
165 operator=(suite const&) = delete;
166
174 template <class = void>
175 void
176 operator()(runner& r);
177
179 template <class = void>
180 void
181 pass();
182
192 template <class String>
193 void
194 fail(String const& reason, char const* file, int line);
195
196 template <class = void>
197 void
198 fail(std::string const& reason = "");
219 template <class Condition>
220 bool
221 expect(Condition const& shouldBeTrue)
222 {
223 return expect(shouldBeTrue, "");
224 }
225
226 template <class Condition, class String>
227 bool
228 expect(Condition const& shouldBeTrue, String const& reason);
229
230 template <class Condition>
231 bool
232 expect(Condition const& shouldBeTrue, char const* file, int line)
233 {
234 return expect(shouldBeTrue, "", file, line);
235 }
236
237 template <class Condition, class String>
238 bool
239 expect(Condition const& shouldBeTrue, String const& reason, char const* file, int line);
242 //
243 // DEPRECATED
244 //
245 // Expect an exception from f()
246 template <class F, class String>
247 bool
248 except(F&& f, String const& reason);
249 template <class F>
250 bool
251 except(F&& f)
252 {
253 return except(f, "");
254 }
255 template <class E, class F, class String>
256 bool
257 except(F&& f, String const& reason);
258 template <class E, class F>
259 bool
260 except(F&& f)
261 {
262 return except<E>(f, "");
263 }
264 template <class F, class String>
265 bool
266 unexcept(F&& f, String const& reason);
267 template <class F>
268 bool
269 unexcept(F&& f)
270 {
271 return unexcept(f, "");
272 }
273
275 std::string const&
276 arg() const
277 {
278 return runner_->arg();
279 }
280
281 // DEPRECATED
282 // @return `true` if the test condition indicates success(a false value)
283 template <class Condition, class String>
284 bool
285 unexpected(Condition shouldBeFalse, String const& reason);
286
287 template <class Condition>
288 bool
289 unexpected(Condition shouldBeFalse)
290 {
291 return unexpected(shouldBeFalse, "");
292 }
293
294private:
295 friend class thread;
296
297 static suite**
299 {
300 static suite* pts = nullptr;
301 return &pts;
302 }
303
305 virtual void
306 run() = 0;
307
308 void
310
311 template <class = void>
312 void
313 run(runner& r);
314};
315
316//------------------------------------------------------------------------------
317
318// Helper for streaming testcase names
320{
321private:
324
325public:
327 operator=(scoped_testcase const&) = delete;
328
330 {
331 auto const& name = ss_.str();
332 if (!name.empty())
333 suite_.runner_->testcase(name);
334 }
335
337 {
338 ss_.clear();
339 ss_.str({});
340 }
341
342 template <class T>
343 scoped_testcase(suite& self, std::stringstream& ss, T const& t) : suite_(self), ss_(ss)
344 {
345 ss_.clear();
346 ss_.str({});
347 ss_ << t;
348 }
349
350 template <class T>
352 operator<<(T const& t)
353 {
354 ss_ << t;
355 return *this;
356 }
357};
358
359//------------------------------------------------------------------------------
360
361inline void
363{
364 suite_.abort_ = abort == abort_on_fail;
365 suite_.runner_->testcase(name);
366}
367
370{
371 suite_.abort_ = abort == abort_on_fail;
372 return {suite_, ss_};
373}
374
375template <class T>
378{
379 return {suite_, ss_, t};
380}
381
382//------------------------------------------------------------------------------
383
384template <class>
385void
387{
388 *p_this_suite() = this;
389 try
390 {
391 run(r);
392 *p_this_suite() = nullptr;
393 }
394 catch (...)
395 {
396 *p_this_suite() = nullptr;
397 throw;
398 }
399}
400
401template <class Condition, class String>
402bool
403suite::expect(Condition const& shouldBeTrue, String const& reason)
404{
405 if (shouldBeTrue)
406 {
407 pass();
408 return true;
409 }
410 fail(reason);
411 return false;
412}
413
414template <class Condition, class String>
415bool
416suite::expect(Condition const& shouldBeTrue, String const& reason, char const* file, int line)
417{
418 if (shouldBeTrue)
419 {
420 pass();
421 return true;
422 }
423 fail(detail::make_reason(reason, file, line));
424 return false;
425}
426
427// DEPRECATED
428
429template <class F, class String>
430bool
431suite::except(F&& f, String const& reason)
432{
433 try
434 {
435 f();
436 fail(reason);
437 return false;
438 }
439 catch (...)
440 {
441 pass();
442 }
443 return true;
444}
445
446template <class E, class F, class String>
447bool
448suite::except(F&& f, String const& reason)
449{
450 try
451 {
452 f();
453 fail(reason);
454 return false;
455 }
456 catch (E const&)
457 {
458 pass();
459 }
460 return true;
461}
462
463template <class F, class String>
464bool
465suite::unexcept(F&& f, String const& reason)
466{
467 try
468 {
469 f();
470 pass();
471 return true;
472 }
473 catch (...)
474 {
475 fail(reason);
476 }
477 return false;
478}
479
480template <class Condition, class String>
481bool
482suite::unexpected(Condition shouldBeFalse, String const& reason)
483{
484 bool const b = static_cast<bool>(shouldBeFalse);
485 if (!b)
486 pass();
487 else
488 fail(reason);
489 return !b;
490}
491
492template <class>
493void
495{
497 runner_->pass();
498}
499
500// ::fail
501template <class>
502void
504{
506 runner_->fail(reason);
507 if (abort_)
508 {
509 aborted_ = true;
510 BOOST_THROW_EXCEPTION(abort_exception());
511 }
512}
513
514template <class String>
515void
516suite::fail(String const& reason, char const* file, int line)
517{
518 fail(detail::make_reason(reason, file, line));
519}
520
521inline void
523{
524 if (abort_ && aborted_)
525 BOOST_THROW_EXCEPTION(abort_exception());
526}
527
528template <class>
529void
531{
532 runner_ = &r;
533
534 try
535 {
536 run();
537 }
538 catch (abort_exception const&)
539 {
540 // ends the suite
541 }
542 catch (std::exception const& e)
543 {
544 runner_->fail("unhandled exception: " + std::string(e.what()));
545 }
546 catch (...)
547 {
548 runner_->fail("unhandled exception");
549 }
550}
551
552#ifndef BEAST_EXPECT
557#define BEAST_EXPECT(cond) expect(cond, __FILE__, __LINE__)
558#endif
559
560#ifndef BEAST_EXPECTS
565#define BEAST_EXPECTS(cond, reason) ((cond) ? (pass(), true) : (fail((reason), __FILE__, __LINE__), false))
566#endif
567
568} // namespace unit_test
569} // namespace beast
570
571//------------------------------------------------------------------------------
572
573// detail:
574// This inserts the suite with the given manual flag
575#define BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, manual, priority) \
576 static beast::unit_test::detail::insert_suite<Class##_test> Library##Module##Class##_test_instance( \
577 #Class, #Module, #Library, manual, priority)
578
579//------------------------------------------------------------------------------
580
581// Preprocessor directives for controlling unit test definitions.
582
583// If this is already defined, don't redefine it. This allows
584// programs to provide custom behavior for testsuite definitions
585//
586#ifndef BEAST_DEFINE_TESTSUITE
587
593#ifndef BEAST_NO_UNIT_TEST_INLINE
594#define BEAST_NO_UNIT_TEST_INLINE 0
595#endif
596
624#if BEAST_NO_UNIT_TEST_INLINE
625#define BEAST_DEFINE_TESTSUITE(Class, Module, Library)
626#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library)
627#define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority)
628#define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority)
629
630#else
631#include <xrpl/beast/unit_test/global_suites.h>
632#define BEAST_DEFINE_TESTSUITE(Class, Module, Library) BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, 0)
633#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library) \
634 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, 0)
635#define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority) \
636 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, Priority)
637#define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority) \
638 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, Priority)
639#endif
640
641#endif
642
643//------------------------------------------------------------------------------
T append(T... args)
Unit test runner interface.
Definition runner.h:23
void log(std::string const &s)
Definition runner.h:268
void arg(std::string const &s)
Set the argument string.
Definition runner.h:45
void fail(std::string const &reason)
Definition runner.h:256
void testcase(std::string const &name)
Definition runner.h:229
log_buf< CharT, Traits, Allocator > buf_
Definition suite.h:97
scoped_testcase & operator<<(T const &t)
Definition suite.h:352
scoped_testcase & operator=(scoped_testcase const &)=delete
scoped_testcase(suite &self, std::stringstream &ss, T const &t)
Definition suite.h:343
scoped_testcase(suite &self, std::stringstream &ss)
Definition suite.h:336
scoped_testcase operator<<(T const &t)
void operator()(std::string const &name, abort_t abort=no_abort_on_fail)
Open a new testcase.
Definition suite.h:362
A testsuite class.
Definition suite.h:51
log_os< char > log
Logging output stream.
Definition suite.h:144
bool expect(Condition const &shouldBeTrue, char const *file, int line)
Definition suite.h:232
suite & operator=(suite const &)=delete
bool except(F &&f)
Definition suite.h:260
void pass()
Record a successful test condition.
Definition suite.h:494
static suite * this_suite()
Returns the "current" running suite.
Definition suite.h:153
void operator()(runner &r)
Invokes the test using the specified runner.
Definition suite.h:386
static suite ** p_this_suite()
Definition suite.h:298
bool unexpected(Condition shouldBeFalse)
Definition suite.h:289
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition suite.h:482
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:147
std::string const & arg() const
Return the argument associated with the runner.
Definition suite.h:276
bool unexcept(F &&f, String const &reason)
Definition suite.h:465
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition suite.h:221
suite(suite const &)=delete
bool unexcept(F &&f)
Definition suite.h:269
bool except(F &&f, String const &reason)
Definition suite.h:431
virtual void run()=0
Runs the suite.
bool except(F &&f)
Definition suite.h:251
virtual ~suite()=default
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:516
Replacement for std::thread that handles exceptions in unit tests.
Definition thread.h:18
T clear(T... args)
T empty(T... args)
static std::string make_reason(String const &reason, char const *file, int line)
Definition suite.h:24
STL namespace.
char const * what() const noexcept override
Definition suite.h:62
T what(T... args)