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