rippled
Loading...
Searching...
No Matches
suite.h
1//
2// Copyright (c) 2013-2017 Vinnie Falco (vinnie dot falco at gmail dot com)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7
8#ifndef BEAST_UNIT_TEST_SUITE_HPP
9#define BEAST_UNIT_TEST_SUITE_HPP
10
11#include <xrpl/beast/unit_test/runner.h>
12
13#include <boost/filesystem.hpp>
14#include <boost/lexical_cast.hpp>
15#include <boost/throw_exception.hpp>
16
17#include <ostream>
18#include <sstream>
19#include <string>
20
21namespace beast {
22namespace unit_test {
23
24namespace detail {
25
26template <class String>
27static std::string
28make_reason(String const& reason, char const* file, int line)
29{
30 std::string s(reason);
31 if (!s.empty())
32 s.append(": ");
33 namespace fs = boost::filesystem;
34 s.append(fs::path{file}.filename().string());
35 s.append("(");
36 s.append(boost::lexical_cast<std::string>(line));
37 s.append(")");
38 return s;
39}
40
41} // namespace detail
42
43class thread;
44
46
54class suite
55{
56private:
57 bool abort_ = false;
58 bool aborted_ = false;
59 runner* runner_ = nullptr;
60
61 // This exception is thrown internally to stop the current suite
62 // in the event of a failure, if the option to stop is set.
64 {
65 char const*
66 what() const noexcept override
67 {
68 return "test suite aborted";
69 }
70 };
71
72 template <class CharT, class Traits, class Allocator>
73 class log_buf : public std::basic_stringbuf<CharT, Traits, Allocator>
74 {
76
77 public:
78 explicit log_buf(suite& self) : suite_(self)
79 {
80 }
81
83 {
84 sync();
85 }
86
87 int
88 sync() override
89 {
90 auto const& s = this->str();
91 if (s.size() > 0)
92 suite_.runner_->log(s);
93 this->str("");
94 return 0;
95 }
96 };
97
98 template <
99 class CharT,
100 class Traits = std::char_traits<CharT>,
101 class Allocator = std::allocator<CharT>>
102 class log_os : public std::basic_ostream<CharT, Traits>
103 {
105
106 public:
107 explicit log_os(suite& self)
108 : std::basic_ostream<CharT, Traits>(&buf_), buf_(self)
109 {
110 }
111 };
112
113 class scoped_testcase;
114
116 {
119
120 public:
121 explicit testcase_t(suite& self) : suite_(self)
122 {
123 }
124
135 void
136 operator()(std::string const& name, abort_t abort = no_abort_on_fail);
137
139 operator()(abort_t abort);
140
141 template <class T>
143 operator<<(T const& t);
144 };
145
146public:
153
156
160 static suite*
162 {
163 return *p_this_suite();
164 }
165
166 suite() : log(*this), testcase(*this)
167 {
168 }
169
170 virtual ~suite() = default;
171 suite(suite const&) = delete;
172 suite&
173 operator=(suite const&) = delete;
174
182 template <class = void>
183 void
184 operator()(runner& r);
185
187 template <class = void>
188 void
189 pass();
190
200 template <class String>
201 void
202 fail(String const& reason, char const* file, int line);
203
204 template <class = void>
205 void
206 fail(std::string const& reason = "");
227 template <class Condition>
228 bool
229 expect(Condition const& shouldBeTrue)
230 {
231 return expect(shouldBeTrue, "");
232 }
233
234 template <class Condition, class String>
235 bool
236 expect(Condition const& shouldBeTrue, String const& reason);
237
238 template <class Condition>
239 bool
240 expect(Condition const& shouldBeTrue, char const* file, int line)
241 {
242 return expect(shouldBeTrue, "", file, line);
243 }
244
245 template <class Condition, class String>
246 bool
247 expect(
248 Condition const& shouldBeTrue,
249 String const& reason,
250 char const* file,
251 int line);
254 //
255 // DEPRECATED
256 //
257 // Expect an exception from f()
258 template <class F, class String>
259 bool
260 except(F&& f, String const& reason);
261 template <class F>
262 bool
263 except(F&& f)
264 {
265 return except(f, "");
266 }
267 template <class E, class F, class String>
268 bool
269 except(F&& f, String const& reason);
270 template <class E, class F>
271 bool
272 except(F&& f)
273 {
274 return except<E>(f, "");
275 }
276 template <class F, class String>
277 bool
278 unexcept(F&& f, String const& reason);
279 template <class F>
280 bool
281 unexcept(F&& f)
282 {
283 return unexcept(f, "");
284 }
285
287 std::string const&
288 arg() const
289 {
290 return runner_->arg();
291 }
292
293 // DEPRECATED
294 // @return `true` if the test condition indicates success(a false value)
295 template <class Condition, class String>
296 bool
297 unexpected(Condition shouldBeFalse, String const& reason);
298
299 template <class Condition>
300 bool
301 unexpected(Condition shouldBeFalse)
302 {
303 return unexpected(shouldBeFalse, "");
304 }
305
306private:
307 friend class thread;
308
309 static suite**
311 {
312 static suite* pts = nullptr;
313 return &pts;
314 }
315
317 virtual void
318 run() = 0;
319
320 void
322
323 template <class = void>
324 void
325 run(runner& r);
326};
327
328//------------------------------------------------------------------------------
329
330// Helper for streaming testcase names
332{
333private:
336
337public:
339 operator=(scoped_testcase const&) = delete;
340
342 {
343 auto const& name = ss_.str();
344 if (!name.empty())
345 suite_.runner_->testcase(name);
346 }
347
349 {
350 ss_.clear();
351 ss_.str({});
352 }
353
354 template <class T>
356 : suite_(self), ss_(ss)
357 {
358 ss_.clear();
359 ss_.str({});
360 ss_ << t;
361 }
362
363 template <class T>
365 operator<<(T const& t)
366 {
367 ss_ << t;
368 return *this;
369 }
370};
371
372//------------------------------------------------------------------------------
373
374inline void
376{
377 suite_.abort_ = abort == abort_on_fail;
378 suite_.runner_->testcase(name);
379}
380
383{
384 suite_.abort_ = abort == abort_on_fail;
385 return {suite_, ss_};
386}
387
388template <class T>
391{
392 return {suite_, ss_, t};
393}
394
395//------------------------------------------------------------------------------
396
397template <class>
398void
400{
401 *p_this_suite() = this;
402 try
403 {
404 run(r);
405 *p_this_suite() = nullptr;
406 }
407 catch (...)
408 {
409 *p_this_suite() = nullptr;
410 throw;
411 }
412}
413
414template <class Condition, class String>
415bool
416suite::expect(Condition const& shouldBeTrue, String const& reason)
417{
418 if (shouldBeTrue)
419 {
420 pass();
421 return true;
422 }
423 fail(reason);
424 return false;
425}
426
427template <class Condition, class String>
428bool
430 Condition const& shouldBeTrue,
431 String const& reason,
432 char const* file,
433 int line)
434{
435 if (shouldBeTrue)
436 {
437 pass();
438 return true;
439 }
440 fail(detail::make_reason(reason, file, line));
441 return false;
442}
443
444// DEPRECATED
445
446template <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 (...)
457 {
458 pass();
459 }
460 return true;
461}
462
463template <class E, 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 (E const&)
474 {
475 pass();
476 }
477 return true;
478}
479
480template <class F, class String>
481bool
482suite::unexcept(F&& f, String const& reason)
483{
484 try
485 {
486 f();
487 pass();
488 return true;
489 }
490 catch (...)
491 {
492 fail(reason);
493 }
494 return false;
495}
496
497template <class Condition, class String>
498bool
499suite::unexpected(Condition shouldBeFalse, String const& reason)
500{
501 bool const b = static_cast<bool>(shouldBeFalse);
502 if (!b)
503 pass();
504 else
505 fail(reason);
506 return !b;
507}
508
509template <class>
510void
512{
514 runner_->pass();
515}
516
517// ::fail
518template <class>
519void
521{
523 runner_->fail(reason);
524 if (abort_)
525 {
526 aborted_ = true;
527 BOOST_THROW_EXCEPTION(abort_exception());
528 }
529}
530
531template <class String>
532void
533suite::fail(String const& reason, char const* file, int line)
534{
535 fail(detail::make_reason(reason, file, line));
536}
537
538inline void
540{
541 if (abort_ && aborted_)
542 BOOST_THROW_EXCEPTION(abort_exception());
543}
544
545template <class>
546void
548{
549 runner_ = &r;
550
551 try
552 {
553 run();
554 }
555 catch (abort_exception const&)
556 {
557 // ends the suite
558 }
559 catch (std::exception const& e)
560 {
561 runner_->fail("unhandled exception: " + std::string(e.what()));
562 }
563 catch (...)
564 {
565 runner_->fail("unhandled exception");
566 }
567}
568
569#ifndef BEAST_EXPECT
574#define BEAST_EXPECT(cond) expect(cond, __FILE__, __LINE__)
575#endif
576
577#ifndef BEAST_EXPECTS
582#define BEAST_EXPECTS(cond, reason) \
583 ((cond) ? (pass(), true) : (fail((reason), __FILE__, __LINE__), false))
584#endif
585
586} // namespace unit_test
587} // namespace beast
588
589//------------------------------------------------------------------------------
590
591// detail:
592// This inserts the suite with the given manual flag
593#define BEAST_DEFINE_TESTSUITE_INSERT( \
594 Class, Module, Library, manual, priority) \
595 static beast::unit_test::detail::insert_suite<Class##_test> \
596 Library##Module##Class##_test_instance( \
597 #Class, #Module, #Library, manual, priority)
598
599//------------------------------------------------------------------------------
600
601// Preprocessor directives for controlling unit test definitions.
602
603// If this is already defined, don't redefine it. This allows
604// programs to provide custom behavior for testsuite definitions
605//
606#ifndef BEAST_DEFINE_TESTSUITE
607
613#ifndef BEAST_NO_UNIT_TEST_INLINE
614#define BEAST_NO_UNIT_TEST_INLINE 0
615#endif
616
644#if BEAST_NO_UNIT_TEST_INLINE
645#define BEAST_DEFINE_TESTSUITE(Class, Module, Library)
646#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library)
647#define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority)
648#define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority)
649
650#else
651#include <xrpl/beast/unit_test/global_suites.h>
652#define BEAST_DEFINE_TESTSUITE(Class, Module, Library) \
653 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, 0)
654#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library) \
655 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, 0)
656#define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority) \
657 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, Priority)
658#define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority) \
659 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, Priority)
660#endif
661
662#endif
663
664//------------------------------------------------------------------------------
665
666#endif
T append(T... args)
Unit test runner interface.
Definition runner.h:27
void log(std::string const &s)
Definition runner.h:272
void arg(std::string const &s)
Set the argument string.
Definition runner.h:49
void fail(std::string const &reason)
Definition runner.h:260
void testcase(std::string const &name)
Definition runner.h:233
log_buf< CharT, Traits, Allocator > buf_
Definition suite.h:104
scoped_testcase & operator<<(T const &t)
Definition suite.h:365
scoped_testcase & operator=(scoped_testcase const &)=delete
scoped_testcase(suite &self, std::stringstream &ss, T const &t)
Definition suite.h:355
scoped_testcase(suite &self, std::stringstream &ss)
Definition suite.h:348
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:375
A testsuite class.
Definition suite.h:55
log_os< char > log
Logging output stream.
Definition suite.h:152
bool expect(Condition const &shouldBeTrue, char const *file, int line)
Definition suite.h:240
suite & operator=(suite const &)=delete
bool except(F &&f)
Definition suite.h:272
void pass()
Record a successful test condition.
Definition suite.h:511
static suite * this_suite()
Returns the "current" running suite.
Definition suite.h:161
void operator()(runner &r)
Invokes the test using the specified runner.
Definition suite.h:399
static suite ** p_this_suite()
Definition suite.h:310
bool unexpected(Condition shouldBeFalse)
Definition suite.h:301
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition suite.h:499
testcase_t 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:288
bool unexcept(F &&f, String const &reason)
Definition suite.h:482
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition suite.h:229
suite(suite const &)=delete
bool unexcept(F &&f)
Definition suite.h:281
bool except(F &&f, String const &reason)
Definition suite.h:448
virtual void run()=0
Runs the suite.
bool except(F &&f)
Definition suite.h:263
virtual ~suite()=default
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:533
Replacement for std::thread that handles exceptions in unit tests.
Definition thread.h:22
T clear(T... args)
T empty(T... args)
static std::string make_reason(String const &reason, char const *file, int line)
Definition suite.h:28
STL namespace.
char const * what() const noexcept override
Definition suite.h:66
T what(T... args)