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