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 <
95 class CharT,
96 class Traits = std::char_traits<CharT>,
97 class Allocator = std::allocator<CharT>>
98 class log_os : public std::basic_ostream<CharT, Traits>
99 {
101
102 public:
103 explicit log_os(suite& self) : std::basic_ostream<CharT, Traits>(&buf_), buf_(self)
104 {
105 }
106 };
107
108 class scoped_testcase;
109
111 {
114
115 public:
116 explicit testcase_t(suite& self) : suite_(self)
117 {
118 }
119
130 void
131 operator()(std::string const& name, abort_t abort = no_abort_on_fail);
132
134 operator()(abort_t abort);
135
136 template <class T>
138 operator<<(T const& t);
139 };
140
141public:
148
151
155 static suite*
157 {
158 return *p_this_suite();
159 }
160
161 suite() : log(*this), testcase(*this)
162 {
163 }
164
165 virtual ~suite() = default;
166 suite(suite const&) = delete;
167 suite&
168 operator=(suite const&) = delete;
169
177 template <class = void>
178 void
179 operator()(runner& r);
180
182 template <class = void>
183 void
184 pass();
185
195 template <class String>
196 void
197 fail(String const& reason, char const* file, int line);
198
199 template <class = void>
200 void
201 fail(std::string const& reason = "");
222 template <class Condition>
223 bool
224 expect(Condition const& shouldBeTrue)
225 {
226 return expect(shouldBeTrue, "");
227 }
228
229 template <class Condition, class String>
230 bool
231 expect(Condition const& shouldBeTrue, String const& reason);
232
233 template <class Condition>
234 bool
235 expect(Condition const& shouldBeTrue, char const* file, int line)
236 {
237 return expect(shouldBeTrue, "", file, line);
238 }
239
240 template <class Condition, class String>
241 bool
242 expect(Condition const& shouldBeTrue, String const& reason, char const* file, int line);
245 //
246 // DEPRECATED
247 //
248 // Expect an exception from f()
249 template <class F, class String>
250 bool
251 except(F&& f, String const& reason);
252 template <class F>
253 bool
254 except(F&& f)
255 {
256 return except(f, "");
257 }
258 template <class E, class F, class String>
259 bool
260 except(F&& f, String const& reason);
261 template <class E, class F>
262 bool
263 except(F&& f)
264 {
265 return except<E>(f, "");
266 }
267 template <class F, class String>
268 bool
269 unexcept(F&& f, String const& reason);
270 template <class F>
271 bool
272 unexcept(F&& f)
273 {
274 return unexcept(f, "");
275 }
276
278 std::string const&
279 arg() const
280 {
281 return runner_->arg();
282 }
283
284 // DEPRECATED
285 // @return `true` if the test condition indicates success(a false value)
286 template <class Condition, class String>
287 bool
288 unexpected(Condition shouldBeFalse, String const& reason);
289
290 template <class Condition>
291 bool
292 unexpected(Condition shouldBeFalse)
293 {
294 return unexpected(shouldBeFalse, "");
295 }
296
297private:
298 friend class thread;
299
300 static suite**
302 {
303 static suite* pts = nullptr; // NOLINT(misc-const-correctness)
304 return &pts;
305 }
306
308 virtual void
309 run() = 0;
310
311 void
313
314 template <class = void>
315 void
316 run(runner& r);
317};
318
319//------------------------------------------------------------------------------
320
321// Helper for streaming testcase names
323{
324private:
327
328public:
330 operator=(scoped_testcase const&) = delete;
331
333 {
334 auto const& name = ss_.str();
335 if (!name.empty())
336 suite_.runner_->testcase(name);
337 }
338
340 {
341 ss_.clear();
342 ss_.str({});
343 }
344
345 template <class T>
346 scoped_testcase(suite& self, std::stringstream& ss, T const& t) : suite_(self), ss_(ss)
347 {
348 ss_.clear();
349 ss_.str({});
350 ss_ << t;
351 }
352
353 template <class T>
355 operator<<(T const& t)
356 {
357 ss_ << t;
358 return *this;
359 }
360};
361
362//------------------------------------------------------------------------------
363
364inline void
366{
367 suite_.abort_ = abort == abort_on_fail;
368 suite_.runner_->testcase(name);
369}
370
373{
374 suite_.abort_ = abort == abort_on_fail;
375 return {suite_, ss_};
376}
377
378template <class T>
381{
382 return {suite_, ss_, t};
383}
384
385//------------------------------------------------------------------------------
386
387template <class>
388void
390{
391 *p_this_suite() = this;
392 try
393 {
394 run(r);
395 *p_this_suite() = nullptr;
396 }
397 catch (...)
398 {
399 *p_this_suite() = nullptr;
400 throw;
401 }
402}
403
404template <class Condition, class String>
405bool
406suite::expect(Condition const& shouldBeTrue, String const& reason)
407{
408 if (shouldBeTrue)
409 {
410 pass();
411 return true;
412 }
413 fail(reason);
414 return false;
415}
416
417template <class Condition, class String>
418bool
419suite::expect(Condition const& shouldBeTrue, String const& reason, char const* file, int line)
420{
421 if (shouldBeTrue)
422 {
423 pass();
424 return true;
425 }
426 fail(detail::make_reason(reason, file, line));
427 return false;
428}
429
430// DEPRECATED
431
432template <class F, class String>
433bool
434suite::except(F&& f, String const& reason)
435{
436 try
437 {
438 f();
439 fail(reason);
440 return false;
441 }
442 catch (...)
443 {
444 pass();
445 }
446 return true;
447}
448
449template <class E, class F, class String>
450bool
451suite::except(F&& f, String const& reason)
452{
453 try
454 {
455 f();
456 fail(reason);
457 return false;
458 }
459 catch (E const&)
460 {
461 pass();
462 }
463 return true;
464}
465
466template <class F, class String>
467bool
468suite::unexcept(F&& f, String const& reason)
469{
470 try
471 {
472 f();
473 pass();
474 return true;
475 }
476 catch (...)
477 {
478 fail(reason);
479 }
480 return false;
481}
482
483template <class Condition, class String>
484bool
485suite::unexpected(Condition shouldBeFalse, String const& reason)
486{
487 bool const b = static_cast<bool>(shouldBeFalse);
488 if (!b)
489 pass();
490 else
491 fail(reason);
492 return !b;
493}
494
495template <class>
496void
498{
500 runner_->pass();
501}
502
503// ::fail
504template <class>
505void
507{
509 runner_->fail(reason);
510 if (abort_)
511 {
512 aborted_ = true;
513 BOOST_THROW_EXCEPTION(abort_exception());
514 }
515}
516
517template <class String>
518void
519suite::fail(String const& reason, char const* file, int line)
520{
521 fail(detail::make_reason(reason, file, line));
522}
523
524inline void
526{
527 if (abort_ && aborted_)
528 BOOST_THROW_EXCEPTION(abort_exception());
529}
530
531template <class>
532void
534{
535 runner_ = &r;
536
537 try
538 {
539 run();
540 }
541 catch (abort_exception const&)
542 {
543 // ends the suite
544 }
545 catch (std::exception const& e)
546 {
547 runner_->fail("unhandled exception: " + std::string(e.what()));
548 }
549 catch (...)
550 {
551 runner_->fail("unhandled exception");
552 }
553}
554
555#ifndef BEAST_EXPECT
560#define BEAST_EXPECT(cond) expect(cond, __FILE__, __LINE__)
561#endif
562
563#ifndef BEAST_EXPECTS
568#define BEAST_EXPECTS(cond, reason) \
569 ((cond) ? (pass(), true) : (fail((reason), __FILE__, __LINE__), false))
570#endif
571
572} // namespace unit_test
573} // namespace beast
574
575//------------------------------------------------------------------------------
576
577// detail:
578// This inserts the suite with the given manual flag
579#define BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, manual, priority) \
580 static beast::unit_test::detail::insert_suite<Class##_test> \
581 Library##Module##Class##_test_instance(#Class, #Module, #Library, manual, priority)
582
583//------------------------------------------------------------------------------
584
585// Preprocessor directives for controlling unit test definitions.
586
587// If this is already defined, don't redefine it. This allows
588// programs to provide custom behavior for testsuite definitions
589//
590#ifndef BEAST_DEFINE_TESTSUITE
591
597#ifndef BEAST_NO_UNIT_TEST_INLINE
598#define BEAST_NO_UNIT_TEST_INLINE 0
599#endif
600
628#if BEAST_NO_UNIT_TEST_INLINE
629#define BEAST_DEFINE_TESTSUITE(Class, Module, Library)
630#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library)
631#define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority)
632#define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority)
633
634#else
635#include <xrpl/beast/unit_test/global_suites.h>
636#define BEAST_DEFINE_TESTSUITE(Class, Module, Library) \
637 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, 0)
638#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library) \
639 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, 0)
640#define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority) \
641 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, Priority)
642#define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority) \
643 BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, Priority)
644#endif
645
646#endif
647
648//------------------------------------------------------------------------------
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:100
scoped_testcase & operator<<(T const &t)
Definition suite.h:355
scoped_testcase & operator=(scoped_testcase const &)=delete
scoped_testcase(suite &self, std::stringstream &ss, T const &t)
Definition suite.h:346
scoped_testcase(suite &self, std::stringstream &ss)
Definition suite.h:339
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:365
A testsuite class.
Definition suite.h:51
log_os< char > log
Logging output stream.
Definition suite.h:147
bool expect(Condition const &shouldBeTrue, char const *file, int line)
Definition suite.h:235
suite & operator=(suite const &)=delete
bool except(F &&f)
Definition suite.h:263
void pass()
Record a successful test condition.
Definition suite.h:497
static suite * this_suite()
Returns the "current" running suite.
Definition suite.h:156
void operator()(runner &r)
Invokes the test using the specified runner.
Definition suite.h:389
static suite ** p_this_suite()
Definition suite.h:301
bool unexpected(Condition shouldBeFalse)
Definition suite.h:292
bool unexpected(Condition shouldBeFalse, String const &reason)
Definition suite.h:485
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:150
std::string const & arg() const
Return the argument associated with the runner.
Definition suite.h:279
bool unexcept(F &&f, String const &reason)
Definition suite.h:468
bool expect(Condition const &shouldBeTrue)
Evaluate a test condition.
Definition suite.h:224
suite(suite const &)=delete
bool unexcept(F &&f)
Definition suite.h:272
bool except(F &&f, String const &reason)
Definition suite.h:434
virtual void run()=0
Runs the suite.
bool except(F &&f)
Definition suite.h:254
virtual ~suite()=default
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition suite.h:519
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)