micro-test-plus 6.0.0
µTest++ Testing Framework
Loading...
Searching...
No Matches
micro_os_plus::micro_test_plus::static_suite Class Referencefinal

A test suite designed for static (namespace-scope) registration with a runner. More...

#include "micro-os-plus/micro-test-plus.h"

Inheritance diagram for micro_os_plus::micro_test_plus::static_suite:

Public Member Functions

 static_suite (const static_suite &)=delete
 Deleted copy constructor to prevent copying.
template<typename Callable_T, typename... Args_T>
requires (!detail::static_suite_body<Callable_T, Args_T...> && detail::suite_body<Callable_T, Args_T...>)
 static_suite (located_name name, runner &test_runner, Callable_T &&callable, Args_T &&... arguments)
 Constructs a static suite, and links it into the list of suites.
 static_suite (static_suite &&)=delete
 Deleted move constructor to prevent moving.
 ~static_suite () override
 Virtual destructor.
const char * name (void) const noexcept
 Returns the node name.
static_suite & operator= (const static_suite &)=delete
 Deleted copy assignment operator to prevent copying.
static_suite & operator= (static_suite &&)=delete
 Deleted move assignment operator to prevent moving.
template<typename Callable_T, typename... Args_T>
requires detail::test_body<Callable_T, Args_T...>
void test (const located_name &name, Callable_T &&callable, Args_T &&... arguments)
 Adds a test case to the suite, and runs it.
template<typename T, typename Callable_T>
void test_each (const located_name &name, std::initializer_list< T > values, Callable_T &&callable)
 Adds a test case to the suite for each value of a braced list, and runs them.
template<typename Values_T, typename Callable_T>
requires (detail::test_values_range<Values_T> or detail::test_values_tuple<Values_T>)
void test_each (const located_name &name, Values_T &&values, Callable_T &&callable)
 Adds a test case to the suite for each value of a range or a tuple, and runs them.
const counters & totals (void) const noexcept
 Returns the totals of the node.
Deprecated Functions
template<typename Callable_T, typename... Args_T>
requires (detail::static_suite_body<Callable_T, Args_T...>)
 static_suite (located_name name, runner &test_runner, Callable_T &&callable, Args_T &&... arguments)
 Deprecated constructor, for a body whose first parameter is static_suite&.
Deprecated Functions of suite
const detail::stopwatch & timings (void) const noexcept
 Deprecated access to the timings of the suite.
detail::stopwatch & timings (void) noexcept
 Deprecated access to the timings of the suite, as a non-const reference.
Deprecated Functions of runnable_base
size_t own_index (void) const noexcept
 Deprecated positional index of this node within its parent.
size_t current_subtest_index (void) const noexcept
 Deprecated number of the most recent child test point.
size_t children_subtests_count (void) const noexcept
 Deprecated number of direct child test cases of this node.

Protected Member Functions

bool accepts_test_case (const suite &target, const located_name &name)
 Checks whether a test case can be created on a suite.
void after_test_case_create (class test_case &test_case, suite &suite)
 Counts a newly constructed child test case and executes it immediately.
template<typename Callable_T, typename... Args_T>
void create_test_case (const located_name &name, suite &parent_suite, size_t nesting_depth, Callable_T &&callable, Args_T &&... arguments)
 Creates a child test case, and runs it.
suite * exchange_running_suite (suite *running) noexcept
 Replaces the suite whose body is running in the owning runner, and returns the previous one.
bool has_running_test_case_of (const suite &target) const noexcept
 Checks whether the innermost running test case belongs to a suite.
bool is_aborted (void) const noexcept
 Checks whether the test execution was aborted by the owning runner.
bool is_listing (void) const noexcept
 Checks whether the owning runner lists the test cases instead of running them.
size_t next_test_point_number (void) noexcept
 Advances to the next child test point, and returns its number.
void reject_body_exception (void)
 Reports the exception that escaped the body of a suite while the test cases are listed, and records it.
class test_case * running_test_case (void) const noexcept
 Returns the innermost test case being run by the owning runner, if any.
class reporter & test_reporter (void) const noexcept
 Returns the test reporter associated with this test runnable.
runner & test_runner (void) const noexcept
 Returns the test runner that owns this test runnable.

Protected Attributes

size_t child_test_cases_count_ = 0
 The number of direct child test cases.
const char * name_
 The node name.
size_t own_index_
 The test index, counting from 1.
runner & runner_
 Reference to the test runner that owns this object.
size_t test_point_number_ = 0
 The number of the most recent child test point.
counters totals_
 Totals for the node.

Private Member Functions

void abort (const reflection::source_location &sl=reflection::source_location::current()) const
 Aborts test execution via the owning runner, for a failed requirement.
void fail_unexpected_exception (const char *what)
 Reports an exception that escaped the suite body as a failed check of the suite.
void link (void) noexcept
 Inserts this suite into the list of suites.
void link_or_reject (void) noexcept
 Inserts this suite into the list of suites, or reject it.
void run (void) override
 Executes the suite body by invoking the stored callable.
void unlink (void) noexcept
 Removes this suite from the list of suites.

Private Attributes

std::function< void(suite &)> callable_
 Callable storing the suite body and any bound arguments.
located_name located_name_
 The name of the suite, with the location where it was given.
suite * next_ = nullptr
 The next suite in the list of suites.
detail::stopwatch stopwatch_
 Stopwatch of this suite.

Static Private Attributes

static suite * first_ = nullptr
 The first suite in the list of suites.

Detailed Description

static_suite extends suite to support the pattern where test suites are declared as namespace-scope objects and therefore constructed before or after the runner instance, in unspecified static-initialisation order.

Upon construction, the suite inserts itself into the list of suites, kept sorted by name, which does not depend on the runner object (see suite). The runner is only referred to, not accessed, so it may be constructed later. When runner::run_suites() is called, the runner runs the suites that refer to it, static or registered with runner::add_suite(), in the order of the list; for equal names, in the order of their insertion, so the static suites constructed before main() run first. Upon destruction, the suite removes itself from the list.

The list is shared by all the runners, and each runner runs only the suites that refer to it, so several runners may each have their own static suites. A static suite constructed once its runner's run_suites() has started, for example a local one, is rejected, since it would never run; the error is reported on stderr, and the exit code of the runner is not 0. The runner should outlive the static suites that refer to it; a suite left after its runner was destroyed is never run, but does not affect the other runners.

The body is stored in the callable inherited from suite, and is run by suite::run(); the user callable receives a suite& reference, as for the suites registered with runner::add_suite(), so the same function can serve both kinds of suites. A function written for v5.0.1, with a static_suite& first parameter, is still accepted, by a deprecated constructor.

The class is non-copyable and non-movable to preserve unique ownership and consistent state throughout the test session.

Definition at line 2644 of file test.h.

Constructor & Destructor Documentation

◆ static_suite() [1/4]

template<typename Callable_T, typename... Args_T>
requires (!detail::static_suite_body<Callable_T, Args_T...> && detail::suite_body<Callable_T, Args_T...>)
micro_os_plus::micro_test_plus::static_suite::static_suite ( located_name name,
runner & test_runner,
Callable_T && callable,
Args_T &&... arguments )

The runner is only referred to, not accessed, so it may be a namespace-scope object constructed after this suite.

Template Parameters
Callable_TThe type of a callable object.
Args_TThe types of the callable arguments.
Constraints
The callable is not a body written for v5.0.1, with a static_suite& first parameter, which selects the deprecated constructor.
Parameters
nameThe test suite name or description, used in reports; a string literal, a const char*, a std::string, or a std::string_view, converted implicitly to located_name, which copies it, so the string need not outlive the call; the suite keeps it.
test_runnerThe test runner that runs this suite.
callableA generic callable object, usually a lambda or function, invoked to perform the test suite. Its first parameter must be suite&.
argumentsA possibly empty list of arguments forwarded to the callable after the leading suite& reference.

Delegates to suite, which stores the callable and binds its arguments, if any, and keeps the name, moved; the callable receives a suite& reference, as for the suites registered with runner::add_suite(). After construction, the suite is inserted into the list of suites, to be run by its runner, unless the runner has already started, when the suite is rejected; a runner that has not started is not accessed.

Delegates to suite with a lambda that holds a copy of the callable (decayed, so a function is held as a pointer), and invokes it with the suite& reference converted to static_suite&, followed by the stored arguments, which suite binds as for the other bodies. The conversion is valid, since suite::run() passes this object. The extra call happens once for each run of the suite, not for each test case.

Definition at line 1180 of file test-inlines.h.

1182 : suite{ std::move (name), test_runner,
1183 std::forward<Callable_T> (callable),
1184 std::forward<Args_T> (arguments)... }
1185 {
1186#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
1187 trace::printf ("%s '%s' %" MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE "\n",
1188 __PRETTY_FUNCTION__, name_, own_index_);
1189#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
1190
1191 link_or_reject ();
1192 }
runner & test_runner(void) const noexcept
Returns the test runner that owns this test runnable.
size_t own_index_
The test index, counting from 1.
Definition test.h:859
const char * name(void) const noexcept
Returns the node name.
void link_or_reject(void) noexcept
Inserts this suite into the list of suites, or reject it.
Definition test.cpp:814
suite(located_name &&name, runner &test_runner, Callable_T &&callable, Args_T &&... arguments)
Constructs a suite with a name, runner, and callable body.
#define MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE
Portable printf() conversion for the size_t values.
Definition detail.h:102

References static_suite(), micro_os_plus::micro_test_plus::suite::suite(), micro_os_plus::micro_test_plus::suite::micro_test_plus::runner, micro_os_plus::micro_test_plus::detail::runnable_base::name(), and micro_os_plus::micro_test_plus::detail::runnable_base::test_runner().

Referenced by static_suite(), static_suite(), static_suite(), operator=(), and operator=().

◆ static_suite() [2/4]

template<typename Callable_T, typename... Args_T>
requires (detail::static_suite_body<Callable_T, Args_T...>)
micro_os_plus::micro_test_plus::static_suite::static_suite ( located_name name,
runner & test_runner,
Callable_T && callable,
Args_T &&... arguments )

In v5.0.1, the body of a static suite received a static_suite& reference; it now receives a suite& one, so that the same function can serve the suites registered with runner::add_suite(). To keep the functions written for v5.0.1 working, the body is wrapped in a function object that converts the suite& reference back to static_suite&, which is always valid, since the suite that runs the body is this object.

The deprecation is reported where the suite is declared; to remove it, change the first parameter of the function to suite&.

Template Parameters
Callable_TThe type of a callable object.
Args_TThe types of the callable arguments.
Constraints
The callable cannot be invoked with a suite& first argument, but can with a static_suite& one.
Parameters
nameThe test suite name or description, used in reports; a string literal, a const char*, a std::string, or a std::string_view, converted implicitly to located_name, which copies it, so the string need not outlive the call; the suite keeps it.
test_runnerThe test runner that runs this suite.
callableA function or callable object whose first parameter is static_suite&.
argumentsA possibly empty list of arguments forwarded to the callable after the leading static_suite& reference.
Deprecated
use a suite& first parameter (since 6.0.0)

References micro_os_plus::micro_test_plus::suite::micro_test_plus::runner, micro_os_plus::micro_test_plus::detail::runnable_base::name(), and micro_os_plus::micro_test_plus::detail::runnable_base::test_runner().

◆ static_suite() [3/4]

micro_os_plus::micro_test_plus::static_suite::static_suite ( const static_suite & )
delete

A copy would duplicate the counters and the stored body.

References static_suite().

◆ static_suite() [4/4]

micro_os_plus::micro_test_plus::static_suite::static_suite ( static_suite && )
delete

Nodes are referred to by address (e.g. by their children and by the runner), so they must not be relocated.

References static_suite().

◆ ~static_suite()

micro_os_plus::micro_test_plus::static_suite::~static_suite ( )
override

The suite is removed from the list of suites by the suite destructor; the stored callable is destroyed with the suite members.

The suite is removed from the list of suites by the suite destructor. If tracing is enabled, the suite name is output for diagnostic purposes.

Definition at line 825 of file test.cpp.

826 {
827#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
828 trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
829#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
830 }

References micro_os_plus::micro_test_plus::detail::runnable_base::name_.

Member Function Documentation

◆ abort()

void micro_os_plus::micro_test_plus::detail::runnable_base::abort ( const reflection::source_location & sl = reflection::source_location::current ()) const
privateinherited

Private, since it is used only by the check result, a friend, for a failed requirement without exceptions; the user code calls runner::abort().

Parameters
slThe source location from which the abort is triggered.
Returns
Does not return.

Delegates to the private runner::abort(), as caused by a failed requirement, passing the supplied source location, so that the report identifies it. The runner then calls the abort handler, if any, and terminates the process via ::abort().

Definition at line 306 of file test.cpp.

307 {
308 runner_.abort (sl, true);
309 }
runner & runner_
Reference to the test runner that owns this object.
Definition test.h:848
void abort(const reflection::source_location &sl=reflection::source_location::current())
Aborts test execution immediately.
Definition runner.cpp:1004

References micro_os_plus::micro_test_plus::runner::abort(), and runner_.

Referenced by micro_os_plus::micro_test_plus::detail::check_result::~check_result(), and run().

◆ accepts_test_case()

bool micro_os_plus::micro_test_plus::detail::runnable_base::accepts_test_case ( const suite & target,
const located_name & name )
nodiscardprotectedinherited

Protected, since it is used only by suite::test(). A test case can be created only on the suite whose body is running (the top suite, between runner::add_top_suite() and runner::run_suites(), or the suite being run). A call on any other suite, for example on the top suite from the body of another suite, on a static suite before the runner was initialised, or after runner::run_suites() returned, would run the test case where its results cannot be reported correctly. Such a call is rejected: the failure is reported as a failed check of the running test case, if one runs, otherwise in the running suite, or, when no suite runs, on stderr, and the rejection is remembered by the runner, which makes the exit code non-zero. When the session was declined (option errors, or --help), or aborted, the test cases are ignored silently, as after_test_case_create() ignores them.

Parameters
targetThe suite on which the test case is created.
nameThe name and the location of the test case, for the message.
Return values
trueThe test case can be created.
falseThe test case must not be created.

The suite whose body runs accepts the test case. When the session was declined, or aborted, the test case is ignored, as after_test_case_create() ignores it.

Otherwise the call is rejected. If a test case runs (and the test cases are not only listed), the failure is reported as a check of that test case, so that it stays in its report. Otherwise, if a suite runs, the failure is reported as a check of that suite, with the same numbering and counting as the unexpected exceptions of the suite body. Otherwise (the runner was not initialised, has not started the suites, or has finished them, or the test cases are listed) the failure is given to runner::reject_call(), which writes the message on stderr and, where the reporter can still write it, as a comment line, for example in the list, and runner::mark_rejected() makes the exit code non-zero, as for the suites added too late.

Definition at line 239 of file test.cpp.

241 {
242 if (runner_.running_suite_ == &target)
243 {
244 return true;
245 }
246
249 {
250 return false;
251 }
252
253 std::string message{ "test case '" };
254 message.append (name.name ());
255 message.append ("' started on suite '");
256 message.append (target.name ());
257 message.append ("', which is not running");
258
259 if (runner_.running_test_case_ != nullptr
261 {
263 name.location ());
264 return false;
265 }
266
267 suite* running = runner_.running_suite_;
268 if (running != nullptr && !runner_.options_.list_tests)
269 {
270 running->next_test_point_number ();
271 running->test_reporter ().fail_suite (message, *running);
272 running->totals_.increment_failed_checks ();
273 return false;
274 }
275
276 runner_.reject_call (message, &name.location ());
277 return false;
278 }
bool help
Whether to display the usage and the list of the options, instead of running the tests.
bool list_tests
Whether the test cases are listed instead of run.
class suite * running_suite_
The suite whose body is running, if any.
Definition runner.h:1409
bool has_option_errors(void) const noexcept
Checks whether an option error was found by initialise().
void reject_call(const std::string &message, const reflection::source_location *location=nullptr)
Reports a rejected call, and records it.
Definition runner.cpp:660
runner_options options_
The options of the test session.
Definition runner.h:1306
test_case * running_test_case_
The innermost test case being run, if any.
Definition runner.h:1397
bool aborted_
Whether the test execution was aborted.
Definition runner.h:1386
void report_rejected_test(const std::string &message, const reflection::source_location &location)
Reports a rejected call as a failed check of this test case.
Definition test.cpp:493

References micro_os_plus::micro_test_plus::runner::aborted_, micro_os_plus::micro_test_plus::detail::reporter::fail_suite(), micro_os_plus::micro_test_plus::runner::has_option_errors(), micro_os_plus::micro_test_plus::runner_options::help, micro_os_plus::micro_test_plus::counters::increment_failed_checks(), micro_os_plus::micro_test_plus::runner_options::list_tests, micro_os_plus::micro_test_plus::located_name::location(), name(), micro_os_plus::micro_test_plus::located_name::name(), next_test_point_number(), micro_os_plus::micro_test_plus::runner::options_, micro_os_plus::micro_test_plus::runner::reject_call(), micro_os_plus::micro_test_plus::test_case::report_rejected_test(), runner_, micro_os_plus::micro_test_plus::runner::running_suite_, micro_os_plus::micro_test_plus::runner::running_test_case_, test_reporter(), and totals_.

Referenced by run(), and micro_os_plus::micro_test_plus::suite::test().

◆ after_test_case_create()

void micro_os_plus::micro_test_plus::detail::runnable_base::after_test_case_create ( class test_case & test_case,
suite & suite )
protectedinherited

The child test case is a local object of create_test_case(), and is destroyed when that function returns.

Parameters
test_caseThe newly created test_case.
suiteThe parent suite to which execution results are reported.
Returns
Nothing.

Counts test_case, which is a local object of the calling create_test_case(), and immediately invokes test_case::run() on it. The test case is not kept; only child_test_cases_count_ is needed later, for the TAP plan.

If the filter patterns do not select the test case (its own name at its nesting level, or the name of suite at level 0, which matters only for the top suite, since the other suites run only when selected), its body is not called: the reporter is notified with skip_test_case() and the parent's skipped test cases counter is incremented. The test case keeps its index and its place among the children, so the TAP plan of the parent remains complete.

Otherwise, while the test case runs, the runner keeps it as its innermost running test case (see suite::test()). The parent's executed test cases counter is incremented after the run, and, if the child failed (a failed check, or a failed nested test case), its failed test cases counter too, so that the parent fails as well, as in node-tap. The child's check counters are intentionally not merged into the parent totals; each test case reports only its own counters. The child's totals are, however, accumulated into suite so that the suite summary reflects all checks performed by its test cases.

While the test cases are listed (see runner_options::list_tests), the selected test case is listed by the runner, and neither run nor counted, except in child_test_cases_count_.

After the test execution was aborted (possible only when the abort handler threw an exception, which the application caught), the report is complete, so the test case is neither run nor reported. The same applies when the runner refused to run the tests because of errors in the options, or because the output file could not be opened (see runner::has_option_errors()), or because the options requested the usage (--help).

Definition at line 350 of file test.cpp.

352 {
355 {
356 return;
357 }
358
360
361 // While the test cases are listed, the selected ones are listed and
362 // the others ignored; none is run.
364 {
365 if (runner_.is_selected (suite.name (), 0)
366 && runner_.is_selected (test_case.name (),
367 test_case.nesting_depth ()))
368 {
369 runner_.list_test_case (suite, test_case);
370 }
371 return;
372 }
373
374 // Skip the test cases not selected by the filter; the outer test
375 // cases, if any, were selected, otherwise this one was not created.
376 if (!runner_.is_selected (suite.name (), 0)
377 || !runner_.is_selected (test_case.name (),
378 test_case.nesting_depth ()))
379 {
380 test_reporter ().skip_test_case (test_case);
382 return;
383 }
384
385 // Run the child test case immediately, as the innermost running test
386 // case of the runner. The outer one is restored by the guard, also
387 // when an exception leaves run() (for example thrown by an abort
388 // handler), so that the runner never keeps a destroyed test case.
389 {
390 struct running_guard
391 {
392 class test_case*& running;
393 class test_case* outer;
394
395 ~running_guard ()
396 {
397 running = outer;
398 }
400
401 runner_.running_test_case_ = &test_case;
402 // A non-virtual call, so that run() is inlined here; each nested
403 // test case adds this call chain to the stack.
404 test_case.test_case::run ();
405 }
406
407 // This test executed one more test case.
408#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
409 trace::printf ("%s test case '%s' executed one more test case\n",
410 __PRETTY_FUNCTION__, name ());
411#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
413
414 // Do not accumulate the totals from the child test into the current test
415 // totals, each test case shows only its counters. But a failed child
416 // fails this test too, as in node-tap; the failure reaches all outer
417 // tests, one level at a time, when they end.
418 if (!test_case.totals ().passed ())
419 {
421 }
422
423#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
424 trace::printf ("%s suite '%s' totals\n", __PRETTY_FUNCTION__,
425 suite.name ());
426#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
427
428 // Accumulate the totals from the child test into the suite totals.
429 suite.totals_ += test_case.totals ();
430 }
void increment_skipped_test_cases(size_t count=1) noexcept
Increments the skipped test cases counter.
void increment_executed_test_cases(size_t count=1) noexcept
Increments the executed test cases counter.
void increment_failed_test_cases(size_t count=1) noexcept
Increments the failed test cases counter.
virtual void skip_test_case(const test_case &test_case)=0
Reports a test case skipped by the filter.
class reporter & test_reporter(void) const noexcept
Returns the test reporter associated with this test runnable.
Definition test.cpp:155
size_t child_test_cases_count_
The number of direct child test cases.
Definition test.h:883
void list_test_case(const class suite &suite, const class test_case &test_case)
Lists a test case, instead of running it.
Definition runner.cpp:563
bool is_selected(const char *name, size_t level) const
Checks whether a suite or a test case is selected by the filter pattern of its nesting level.
Definition runner.cpp:530

References micro_os_plus::micro_test_plus::runner::aborted_, child_test_cases_count_, micro_os_plus::micro_test_plus::runner::has_option_errors(), micro_os_plus::micro_test_plus::runner_options::help, micro_os_plus::micro_test_plus::counters::increment_executed_test_cases(), micro_os_plus::micro_test_plus::counters::increment_failed_test_cases(), micro_os_plus::micro_test_plus::counters::increment_skipped_test_cases(), micro_os_plus::micro_test_plus::runner::is_selected(), micro_os_plus::micro_test_plus::runner::list_test_case(), micro_os_plus::micro_test_plus::runner_options::list_tests, name(), micro_os_plus::micro_test_plus::test_case::nesting_depth(), micro_os_plus::micro_test_plus::runner::options_, micro_os_plus::micro_test_plus::counters::passed(), runner_, micro_os_plus::micro_test_plus::runner::running_test_case_, micro_os_plus::micro_test_plus::detail::reporter::skip_test_case(), test_reporter(), totals(), and totals_.

Referenced by create_test_case(), and run().

◆ children_subtests_count()

size_t micro_os_plus::micro_test_plus::detail::runnable_base::children_subtests_count ( void ) const
inlinenodiscardnoexceptinherited

Used only for the TAP plan, by the reporters, which access it directly. The test cases skipped by the filter are included.

Parameters
None.
Returns
The number of child test cases.
Deprecated
internal to the framework (since 6.0.0)

Returns the number of direct child test cases, including those skipped by the filter.

Definition at line 241 of file test-inlines.h.

242 {
244 }

References child_test_cases_count_.

Referenced by operator=().

◆ create_test_case()

template<typename Callable_T, typename... Args_T>
void micro_os_plus::micro_test_plus::detail::runnable_base::create_test_case ( const located_name & name,
suite & parent_suite,
size_t nesting_depth,
Callable_T && callable,
Args_T &&... arguments )
inlineprotectedinherited

The common body of suite::test() and test_case::test(), which differ only in the parent suite and the nesting depth of the test cases they create.

Always inlined into them, even without optimisations, since each nested test case adds one call chain to the stack, and a separate frame for this function would make it longer.

The test case runs and ends within the call, so, without additional arguments, it refers to the callable of the caller, which is neither copied nor moved, and is called in place, so a callable that cannot be copied is accepted, and an lvalue callable keeps the changes of its state. With additional arguments, the callable and the arguments are bound into a body of copies, by bind_callable().

Template Parameters
Callable_TThe type of a callable object.
Args_TThe types of the callable arguments.
Parameters
nameThe test case name or description, used in reports, and the location of the call to test().
parent_suiteThe suite to which the test case belongs.
nesting_depthThe depth of nesting of the test case; 1 for the direct children of a suite.
callableA generic callable object, usually a lambda, invoked to perform the test.
argumentsA possibly empty list of arguments to be passed to the callable.
Returns
Nothing.

Without additional arguments, the child test_case is a local object that refers to the callable of the caller, which is neither copied nor moved, and is called in place (an lvalue callable keeps the changes of its state). A function is referred to through its pointer, and the callable and the additional arguments are bound into a local body, as copies, when there are arguments. The child is constructed with the next test point number of this node as its index, then passed to after_test_case_create(), which counts and runs it.

The child test case and its body, with the copies of the arguments, are destroyed when this function returns, so the memory used by a test session does not grow with the number of test cases; the stack holds one test case and one body for each level of nesting being run. Since the body is not stored in a std::function, it is never allocated, whatever the size of the lambda captures and of the arguments.

Definition at line 292 of file test-inlines.h.

296 {
298
299 if constexpr (sizeof...(arguments) == 0
300 && !std::is_function_v<
301 std::remove_reference_t<Callable_T>>)
302 {
303 // The test case runs and ends within this call, so it refers
304 // to the callable of the caller, which is not copied, and is
305 // called in place.
306 class test_case child_test_case{
307 name, runner_, parent_suite,
308 own_index, nesting_depth, callable_ref<class test_case>{ callable }
309 };
310
311 after_test_case_create (child_test_case, parent_suite);
312 }
313 else
314 {
316 std::forward<Callable_T> (callable),
317 std::forward<Args_T> (arguments)...);
318 class test_case child_test_case{
319 name, runner_, parent_suite,
320 own_index, nesting_depth, callable_ref<class test_case>{ body }
321 };
322
323 after_test_case_create (child_test_case, parent_suite);
324 }
325 }
size_t next_test_point_number(void) noexcept
Advances to the next child test point, and returns its number.
void after_test_case_create(class test_case &test_case, suite &suite)
Counts a newly constructed child test case and executes it immediately.
Definition test.cpp:350
size_t own_index(void) const noexcept
Deprecated positional index of this node within its parent.
auto bind_callable(Callable_T &&callable, Args_T &&... arguments)
Creates the function object that holds the body of a test case or suite.

References after_test_case_create(), micro_os_plus::micro_test_plus::detail::bind_callable(), name(), next_test_point_number(), own_index(), and runner_.

Referenced by run(), micro_os_plus::micro_test_plus::suite::test(), and micro_os_plus::micro_test_plus::test_case::test().

◆ current_subtest_index()

size_t micro_os_plus::micro_test_plus::detail::runnable_base::current_subtest_index ( void ) const
inlinenodiscardnoexceptinherited

Used only for the TAP output, by the reporters, which access it directly.

Parameters
None.
Returns
The one-based test point number, or 0 before the first test point.
Deprecated
internal to the framework (since 6.0.0)

Returns the number of the most recent child test point.

Definition at line 229 of file test-inlines.h.

230 {
231 return test_point_number_;
232 }
size_t test_point_number_
The number of the most recent child test point.
Definition test.h:871

References test_point_number_.

Referenced by operator=().

◆ exchange_running_suite()

suite * micro_os_plus::micro_test_plus::detail::runnable_base::exchange_running_suite ( suite * running)
protectednoexceptinherited

Protected, since it is used only by suite::run(), to mark the suite whose body is being called, and to restore the previous value when the body returns.

Parameters
runningThe suite that starts to run, or the previous one, to restore it.
Returns
The suite that was marked as running before the call, or nullptr when none was.

Sets the pointer of the runner, a friend, and returns the previous value, so that the caller can restore it when the body returns.

Definition at line 212 of file test.cpp.

213 {
214 suite* previous = runner_.running_suite_;
215 runner_.running_suite_ = running;
216 return previous;
217 }

References runner_.

Referenced by run(), and micro_os_plus::micro_test_plus::suite::run().

◆ fail_unexpected_exception()

void micro_os_plus::micro_test_plus::suite::fail_unexpected_exception ( const char * what)
privateinherited

The suite body may throw outside its test cases, for example in a set-up step; the test cases catch their own exceptions. The failure is reported without a source location, since the suites do not record one, and the location of the throw is not known.

Parameters
whatThe explanatory string of a std::exception, or nullptr for an exception of another type.
Returns
Nothing.

The failure is reported as a check of the suite: the test point number is incremented first, so that the TAP output numbers it after the test cases already run, and counts it in the plan of the suite, and the failed checks counter is incremented, so that the suite, and through it the session, fail.

The message is unexpected exception in the suite body: followed by what, or unexpected exception of unknown type in the suite body when what is nullptr; as for the test cases, the type of a std::exception is not shown.

Definition at line 701 of file test.cpp.

702 {
704
705 std::string message{ "unexpected exception" };
706 if (what != nullptr)
707 {
708 message.append (" in the suite body: ");
709 message.append (what);
710 }
711 else
712 {
713 message.append (" of unknown type in the suite body");
714 }
715
716 test_reporter ().fail_suite (message, *this);
718 }
void increment_failed_checks(size_t count=1) noexcept
Increments the failed-checks counter.
virtual void fail_suite(const std::string &message, const suite &suite)=0
Reports a failure of a test suite outside its test cases.

References micro_os_plus::micro_test_plus::detail::reporter::fail_suite(), micro_os_plus::micro_test_plus::counters::increment_failed_checks(), micro_os_plus::micro_test_plus::detail::runnable_base::next_test_point_number(), micro_os_plus::micro_test_plus::detail::runnable_base::test_reporter(), and micro_os_plus::micro_test_plus::detail::runnable_base::totals_.

Referenced by operator=(), and run().

◆ has_running_test_case_of()

bool micro_os_plus::micro_test_plus::detail::runnable_base::has_running_test_case_of ( const suite & target) const
nodiscardprotectednoexceptinherited

Protected, since it is used only by suite::test(), to forward a test case started on the suite to the running test case only when that is a test case of the same suite; the test cases started on another suite are rejected.

Parameters
targetThe suite to check.
Return values
trueA test case is running, and its parent suite is target.
falseNo test case is running, or it belongs to another suite.

Reads the pointer of the runner, a friend, and the parent suite of the test case, which runnable_base may access.

Definition at line 199 of file test.cpp.

201 {
202 const test_case* running = runner_.running_test_case_;
203 return running != nullptr && &running->parent_suite_ == &target;
204 }
suite & parent_suite_
Reference to the parent suite that owns this test case.
Definition test.h:2007

References micro_os_plus::micro_test_plus::test_case::parent_suite_, and runner_.

Referenced by run(), and micro_os_plus::micro_test_plus::suite::test().

◆ is_aborted()

bool micro_os_plus::micro_test_plus::detail::runnable_base::is_aborted ( void ) const
nodiscardprotectednoexceptinherited

Protected, since it is used only by test_case::run() and suite::run(), to pass on an exception thrown by the abort handler, instead of reporting it as unexpected.

Parameters
None.
Returns
true once runner::abort() was called.

Returns the flag kept by the owning runner, set by runner::abort() and never cleared.

Definition at line 177 of file test.cpp.

178 {
179 return runner_.aborted_;
180 }

References runner_.

Referenced by run(), micro_os_plus::micro_test_plus::suite::run(), and micro_os_plus::micro_test_plus::test_case::run().

◆ is_listing()

bool micro_os_plus::micro_test_plus::detail::runnable_base::is_listing ( void ) const
nodiscardprotectednoexceptinherited

Protected, since it is used only by suite::run(), which then calls the suite body without reporting the suite, so that its test cases are created, and listed instead of run.

Parameters
None.
Returns
true if runner_options::list_tests was set.

Returns runner_options::list_tests of the session options kept by the owning runner.

Definition at line 188 of file test.cpp.

189 {
191 }

References runner_.

Referenced by run(), and micro_os_plus::micro_test_plus::suite::run().

◆ link()

void micro_os_plus::micro_test_plus::suite::link ( void )
privatenoexceptinherited

Called by runner::register_suite() and by the static_suite constructor, after the name was copied. The suite is inserted after the suites with names less than or equal to its own, so the list remains sorted by name, and the suites with the same name remain in the order of their insertion. The top suite is not inserted, since the runner runs it separately.

Parameters
None.
Returns
Nothing.

Inserts the suite after the suites with names less than or equal to its own, so the list remains sorted by name, and the suites with the same name remain in the order of their insertion. No memory is allocated. This is the only place where the names of the suites are compared; the runners run the suites in the order of the list.

Definition at line 738 of file test.cpp.

739 {
740#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED)
741 trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
742#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED
743
744 // std::strcmp() compares as unsigned char, like std::string_view,
745 // without a temporary object (which triggers -Waggregate-return).
746 suite** slot = &first_;
747 while (*slot != nullptr && std::strcmp ((*slot)->name_, name_) <= 0)
748 {
749 slot = &(*slot)->next_;
750 }
751 next_ = *slot;
752 *slot = this;
753 }
static suite * first_
The first suite in the list of suites.
Definition test.h:2475
suite * next_
The next suite in the list of suites.
Definition test.h:2463

References suite(), first_, micro_os_plus::micro_test_plus::detail::runnable_base::name_, and next_.

Referenced by operator=().

◆ link_or_reject()

void micro_os_plus::micro_test_plus::static_suite::link_or_reject ( void )
privatenoexcept

Called by the constructors, after the base was constructed. The suite is rejected if its runner has already started, since it would never run; see runner::link_static_suite(). Defined in src/test.cpp, where the runner is a complete type.

Parameters
None.
Returns
Nothing.

Delegates to the runner, which knows whether its session has started.

Definition at line 814 of file test.cpp.

815 {
817 }
static void link_static_suite(runner &test_runner, class suite &suite) noexcept
Inserts a static suite into the list of suites, or reject it.
Definition runner.cpp:728

References micro_os_plus::micro_test_plus::runner::link_static_suite(), and micro_os_plus::micro_test_plus::detail::runnable_base::test_runner().

Referenced by operator=().

◆ name()

const char * micro_os_plus::micro_test_plus::detail::runnable_base::name ( void ) const
inlinenodiscardnoexceptinherited
Parameters
None.
Returns
A pointer to the null-terminated node name.

Returns a pointer to the null-terminated name stored in name_.

Definition at line 195 of file test-inlines.h.

196 {
197 return name_;
198 }

References name_.

Referenced by runnable_base(), micro_os_plus::micro_test_plus::runner::runner(), micro_os_plus::micro_test_plus::runner::runner(), micro_os_plus::micro_test_plus::static_suite::static_suite(), micro_os_plus::micro_test_plus::suite::suite(), micro_os_plus::micro_test_plus::test_case::test_case(), micro_os_plus::micro_test_plus::top_suite::top_suite(), accepts_test_case(), micro_os_plus::micro_test_plus::runner::add_top_suite(), after_test_case_create(), micro_os_plus::micro_test_plus::detail::reporter_human::begin_suite(), micro_os_plus::micro_test_plus::detail::reporter_tap::begin_suite(), micro_os_plus::micro_test_plus::detail::reporter_human::begin_test_case(), micro_os_plus::micro_test_plus::detail::reporter_tap::begin_test_case(), create_test_case(), micro_os_plus::micro_test_plus::test_case::detail::runnable_base, micro_os_plus::micro_test_plus::detail::reporter_human::display_open_heading(), micro_os_plus::micro_test_plus::detail::reporter_tap::display_open_heading(), micro_os_plus::micro_test_plus::detail::reporter_human::display_open_names(), micro_os_plus::micro_test_plus::detail::reporter_human::end_suite(), micro_os_plus::micro_test_plus::detail::reporter_tap::end_suite(), micro_os_plus::micro_test_plus::detail::reporter_human::end_test_case(), micro_os_plus::micro_test_plus::detail::reporter_tap::end_test_case(), micro_os_plus::micro_test_plus::detail::reporter_human::fail_suite(), micro_os_plus::micro_test_plus::detail::reporter_tap::fail_suite(), micro_os_plus::micro_test_plus::runner::list_test_case(), micro_os_plus::micro_test_plus::top_suite::micro_test_plus::runner, operator=(), micro_os_plus::micro_test_plus::suite::operator=(), micro_os_plus::micro_test_plus::test_case::operator=(), micro_os_plus::micro_test_plus::test_case::report_misdirected(), micro_os_plus::micro_test_plus::test_case::report_misdirected_test(), reporter_tap, run(), micro_os_plus::micro_test_plus::detail::reporter_human::skip_suite(), micro_os_plus::micro_test_plus::detail::reporter_tap::skip_suite(), micro_os_plus::micro_test_plus::detail::reporter_human::skip_test_case(), micro_os_plus::micro_test_plus::detail::reporter_tap::skip_test_case(), micro_os_plus::micro_test_plus::suite::static_suite, micro_os_plus::micro_test_plus::suite::test(), micro_os_plus::micro_test_plus::test_case::test(), micro_os_plus::micro_test_plus::suite::test_each(), micro_os_plus::micro_test_plus::suite::test_each(), micro_os_plus::micro_test_plus::test_case::test_each(), micro_os_plus::micro_test_plus::test_case::test_each(), and micro_os_plus::micro_test_plus::detail::reporter_tap::write_quiet_failures().

◆ next_test_point_number()

size_t micro_os_plus::micro_test_plus::detail::runnable_base::next_test_point_number ( void )
inlineprotectednoexceptinherited

Called for each check (by the check result, when the check is reported) and for each nested test case created.

Parameters
None.
Returns
The one-based number of the new test point.

Each call to test() invokes this member function before constructing the new test_case, and each check invokes it from the check result destructor, when the check is reported, so the numbers form a strictly increasing, one-based sequence of TAP test points, in output order.

Definition at line 255 of file test-inlines.h.

256 {
257 return ++test_point_number_;
258 }

References test_point_number_.

Referenced by micro_os_plus::micro_test_plus::detail::check_result::~check_result(), accepts_test_case(), create_test_case(), micro_os_plus::micro_test_plus::suite::fail_unexpected_exception(), micro_os_plus::micro_test_plus::test_case::fail_unexpected_exception(), micro_os_plus::micro_test_plus::runner::reject_call(), and run().

◆ operator=() [1/2]

static_suite & micro_os_plus::micro_test_plus::static_suite::operator= ( const static_suite & )
delete

A copy would duplicate the counters and the stored body.

References static_suite().

◆ operator=() [2/2]

static_suite & micro_os_plus::micro_test_plus::static_suite::operator= ( static_suite && )
delete

Nodes are referred to by address (e.g. by their children and by the runner), so they must not be relocated.

References static_suite(), and link_or_reject().

◆ own_index()

size_t micro_os_plus::micro_test_plus::detail::runnable_base::own_index ( void ) const
inlinenodiscardnoexceptinherited

Used only for the TAP output, by the reporters, which access it directly. The setter of v5.0.1, and increment_subtest_index(), were removed, since they allowed the application code to corrupt the numbering of the reports.

Parameters
None.
Returns
The one-based own index.
Deprecated
internal to the framework (since 6.0.0)

Returns the one-based positional index of this node within its parent.

Definition at line 218 of file test-inlines.h.

219 {
220 return own_index_;
221 }

References own_index_.

Referenced by runnable_base(), micro_os_plus::micro_test_plus::test_case::test_case(), create_test_case(), micro_os_plus::micro_test_plus::test_case::detail::runnable_base, operator=(), and reporter_tap.

◆ reject_body_exception()

void micro_os_plus::micro_test_plus::detail::runnable_base::reject_body_exception ( void )
protectedinherited

Protected, since it is used only by suite::run(), when there is no test point to fail. It gives the message, which names the suite, to runner::reject_call(), which writes it on stderr and in the listing, and makes the exit code non-zero.

Parameters
None.
Returns
Nothing.

Builds the message here, and not in suite::run(), to keep the frame of that function, which is on the stack of every session, unchanged. Delegates to the private runner::reject_call(), which writes the message on stderr and in the listing, and marks the runner, so that the exit code of runner::run_suites() is not 0.

Definition at line 289 of file test.cpp.

290 {
291 std::string message{ "unexpected exception in the body of suite '" };
292 message.append (name_);
293 message.append ("'");
294
295 runner_.reject_call (message);
296 }

References name_, micro_os_plus::micro_test_plus::runner::reject_call(), and runner_.

Referenced by run(), and micro_os_plus::micro_test_plus::suite::run().

◆ run()

void micro_os_plus::micro_test_plus::suite::run ( void )
overrideprivatevirtualinherited

Private, since the suites are run only once, by the runner, which is a friend.

Parameters
None.
Returns
Nothing.

Invokes the stored callable with this suite, surrounded by reporter calls to begin and end the suite. While the body runs, this suite is marked, in the runner, as the one that accepts new test cases (see accepts_test_case()); the previous one is restored when the body returns, also when it throws.

While the test cases are listed (see runner_options::list_tests), the body is called only to create its test cases, which are listed; the suite is neither reported nor timed, and an exception that escapes the body is reported by reject_body_exception(), on stderr and in the listing, the exit code is not 0, and the listing continues with the next suite.

When exceptions are enabled, an exception that escapes the callable, which can be thrown only outside the test cases, since they catch their own exceptions, is caught and reported as a failed check of this suite, and the suite ends normally, so that the run continues with the next suite; the test cases run before the exception remain reported, and the following ones are not run. A body declared noexcept cannot pass the exception on; the program is then terminated before it reaches this function.

As for the test cases, an exception thrown by the abort handler is passed on, without reporting it, and without ending the suite.

Implements micro_os_plus::micro_test_plus::detail::runnable_base.

Definition at line 604 of file test.cpp.

605 {
606#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED)
607 trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
608#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED
609
610 // Marks this suite as the one that accepts new test cases, until the
611 // body returns.
612 struct running_guard
613 {
614 suite& self;
615 suite* outer;
616
617 ~running_guard ()
618 {
619 self.exchange_running_suite (outer);
620 }
621 } guard{ *this, exchange_running_suite (this) };
622
623 // While the test cases are listed, the body only creates them, so
624 // that they are listed; the suite is not reported. An exception
625 // thrown by the body is reported on stderr and in the listing, and
626 // the listing continues with the next suite.
627 if (is_listing ())
628 {
629#if defined(__cpp_exceptions)
630 try
631 {
632 callable_ (*this);
633 }
634 catch (...)
635 {
636 if (is_aborted ())
637 {
638 throw;
639 }
641 }
642#else
643 callable_ (*this);
644#endif // defined(__cpp_exceptions)
645 return;
646 }
647
648 detail::reporter& reporter = this->test_reporter ();
649
650 this->stopwatch_.start ();
651 reporter.begin_suite (*this);
652
653#if defined(__cpp_exceptions)
654 try
655 {
656 // Invoke the callable, passing the self reference.
657 callable_ (*this);
658 }
659 catch (const std::exception& e)
660 {
661 if (is_aborted ())
662 {
663 // Thrown by the abort handler; the report is complete.
664 throw;
665 }
666 fail_unexpected_exception (e.what ());
667 }
668 catch (...)
669 {
670 if (is_aborted ())
671 {
672 // Thrown by the abort handler; the report is complete.
673 throw;
674 }
676 }
677#else
678 // Invoke the callable, passing the self reference.
679 callable_ (*this);
680#endif // defined(__cpp_exceptions)
681
682 this->stopwatch_.stop ();
683 reporter.end_suite (*this);
684 }
void reject_body_exception(void)
Reports the exception that escaped the body of a suite while the test cases are listed,...
Definition test.cpp:289
bool is_listing(void) const noexcept
Checks whether the owning runner lists the test cases instead of running them.
Definition test.cpp:188
suite * exchange_running_suite(suite *running) noexcept
Replaces the suite whose body is running in the owning runner, and returns the previous one.
Definition test.cpp:212
bool is_aborted(void) const noexcept
Checks whether the test execution was aborted by the owning runner.
Definition test.cpp:177
void stop(void) noexcept
Records the stop time, from the system clock.
void start(void) noexcept
Records the start time, from the system clock.
Definition stopwatch.cpp:87
void fail_unexpected_exception(const char *what)
Reports an exception that escaped the suite body as a failed check of the suite.
Definition test.cpp:701
detail::stopwatch stopwatch_
Stopwatch of this suite.
Definition test.h:2441
std::function< void(suite &)> callable_
Callable storing the suite body and any bound arguments.
Definition test.h:2431

References suite(), micro_os_plus::micro_test_plus::detail::reporter::begin_suite(), callable_, micro_os_plus::micro_test_plus::detail::reporter::end_suite(), micro_os_plus::micro_test_plus::detail::runnable_base::exchange_running_suite(), fail_unexpected_exception(), micro_os_plus::micro_test_plus::detail::runnable_base::is_aborted(), micro_os_plus::micro_test_plus::detail::runnable_base::is_listing(), micro_os_plus::micro_test_plus::detail::runnable_base::name_, micro_os_plus::micro_test_plus::detail::runnable_base::reject_body_exception(), micro_os_plus::micro_test_plus::detail::stopwatch::start(), micro_os_plus::micro_test_plus::detail::stopwatch::stop(), stopwatch_, and micro_os_plus::micro_test_plus::detail::runnable_base::test_reporter().

Referenced by operator=().

◆ running_test_case()

test_case * micro_os_plus::micro_test_plus::detail::runnable_base::running_test_case ( void ) const
nodiscardprotectednoexceptinherited

Protected, since it is used only by suite::test(), to run a test case started on the suite from inside a running test case as a nested test case of it.

Parameters
None.
Returns
A pointer to the running test case, or nullptr when no test case is running.

Returns the pointer kept by the owning runner, set by after_test_case_create() while a test case runs.

Definition at line 166 of file test.cpp.

167 {
169 }

References runner_.

Referenced by micro_os_plus::micro_test_plus::test_case::is_misdirected(), micro_os_plus::micro_test_plus::test_case::report_misdirected(), micro_os_plus::micro_test_plus::test_case::report_misdirected_test(), run(), and micro_os_plus::micro_test_plus::suite::test().

◆ test()

template<typename Callable_T, typename... Args_T>
requires detail::test_body<Callable_T, Args_T...>
void micro_os_plus::micro_test_plus::suite::test ( const located_name & name,
Callable_T && callable,
Args_T &&... arguments )
inherited
Template Parameters
Callable_TThe type of a callable object.
Args_TThe types of the callable arguments.
Parameters
nameThe test case name or description, used in reports; a string literal, a const char*, a std::string, or a std::string_view, converted implicitly to located_name, which copies it and also captures the location of the call.
callableA generic callable object, usually a lambda, invoked to perform the test.
argumentsA possibly empty list of arguments to be passed to the callable.
Returns
Nothing.

The test function template creates a test case (a test_case with nesting depth 1) and runs it immediately. It accepts a descriptive name, a callable object (such as a lambda or function pointer), and an optional list of arguments to be passed to the callable, after the leading test_case& reference. The test case is reported using the provided name.

The test case is created and run by create_test_case(), as a local object destroyed when it returns, together with its stored body and bound arguments; only the number of test cases is kept, for the TAP plan.

Each test case typically involves evaluating logical expressions, such as comparing a computed result to an expected value, with expect() or require(). When exceptions are enabled, it is also possible to verify whether evaluating an expression throws exceptions. Each check either passes or fails, and the suite totals count the passed and failed checks.

It is typically invoked within the body of a suite. When invoked from the body of a running test case of this suite (for example via a captured suite reference), the new test case could not be reported as a sibling of the running one, which has not ended; it is therefore created by the innermost running test case, with test_case::test(), and runs nested in it, as if test() had been called on that test case.

The test case can be created only on the suite whose body is running. A call on another suite (for example on the top suite, captured by reference, from the body of a suite added with runner::add_suite(), or on any suite after runner::run_suites() returned) is rejected: the test case is not run, a failure is reported in the running suite, or, when none runs, an error is written to stderr, and the later calls of runner::run_suites() return a non-zero exit code.

Example
ts.test ("Check answer with comparator", [] (auto& t) {
t.expect (mt::eq (compute_answer (), 42)) << "answer is 42";
});
Primary namespace for the µTest++ testing framework.

Definition at line 968 of file test-inlines.h.

970 {
971#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED)
972 trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name.name ());
973#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED
974
975 // Called from inside a running test case of this suite; run nested in
976 // it. A running test case of another suite does not qualify; the call
977 // is then rejected below, as for any suite that is not running.
978 if (class test_case* running = running_test_case ();
979 running != nullptr && has_running_test_case_of (*this))
980 {
981 running->test (name, std::forward<Callable_T> (callable),
982 std::forward<Args_T> (arguments)...);
983 return;
984 }
985
986 if (!accepts_test_case (*this, name))
987 {
988 return;
989 }
990
991 create_test_case (name, *this, 1, std::forward<Callable_T> (callable),
992 std::forward<Args_T> (arguments)...);
993 }
class test_case * running_test_case(void) const noexcept
Returns the innermost test case being run by the owning runner, if any.
Definition test.cpp:166
bool accepts_test_case(const suite &target, const located_name &name)
Checks whether a test case can be created on a suite.
Definition test.cpp:239
void create_test_case(const located_name &name, suite &parent_suite, size_t nesting_depth, Callable_T &&callable, Args_T &&... arguments)
Creates a child test case, and runs it.
bool has_running_test_case_of(const suite &target) const noexcept
Checks whether the innermost running test case belongs to a suite.
Definition test.cpp:199

References micro_os_plus::micro_test_plus::detail::runnable_base::accepts_test_case(), micro_os_plus::micro_test_plus::detail::runnable_base::create_test_case(), micro_os_plus::micro_test_plus::detail::runnable_base::has_running_test_case_of(), micro_os_plus::micro_test_plus::detail::runnable_base::name(), micro_os_plus::micro_test_plus::located_name::name(), and micro_os_plus::micro_test_plus::detail::runnable_base::running_test_case().

Referenced by operator=().

◆ test_each() [1/2]

template<typename T, typename Callable_T>
void micro_os_plus::micro_test_plus::suite::test_each ( const located_name & name,
std::initializer_list< T > values,
Callable_T && callable )
inherited

As the overload for the ranges, for a list written in place, like ts.test_each ("Sizes", { 1, 16, 512 }, ...), whose type cannot be deduced otherwise.

Template Parameters
TThe type of the values.
Callable_TThe type of a callable object.
Parameters
nameThe common name of the test cases.
valuesThe list of values.
callableA generic callable object, usually a lambda, invoked with the test case and each value.
Returns
Nothing.
Since
6.0.0

The list is iterated as a range.

Definition at line 1135 of file test-inlines.h.

1137 {
1138 detail::test_each_value (*this, name, values, callable);
1139 }
void test_each_value(Self_T &self, const located_name &name, Values_T &&values, Callable_T &callable)
Adds and runs a test case for each value.

References micro_os_plus::micro_test_plus::detail::runnable_base::name(), and micro_os_plus::micro_test_plus::detail::test_each_value().

◆ test_each() [2/2]

template<typename Values_T, typename Callable_T>
requires (detail::test_values_range<Values_T> or detail::test_values_tuple<Values_T>)
void micro_os_plus::micro_test_plus::suite::test_each ( const located_name & name,
Values_T && values,
Callable_T && callable )
inherited

For each value, in order, a test case is added and run, as by test(), with the value as the argument of the callable, which is called as callable (test_case, value). The values may be a range (a container, an array, a span, or a view), or a tuple, whose values may have different types, for a generic callable:

ts.test_each ("Sizes", std::vector<int>{ 1, 16, 512 },
[] (auto& t, int size) { t.expect (mt::gt (size, 0)); });
ts.test_each ("Types", std::tuple{ 42, 1.5, "text" },
[] (auto& t, const auto& value) {
t.expect (mt::eq (value, value));
});

Each test case is named after the common name, followed by the value in parentheses, written as in the messages of the checks (Sizes (16)); a value that cannot be written (see extension::printable), such as an application type without an operator<<, is replaced by its position, starting at 1 (Records (#2)). The location of all the test cases is that of the call.

Template Parameters
Values_TThe type of the range or tuple of values.
Callable_TThe type of a callable object.
Parameters
nameThe common name of the test cases; a string literal, a const char*, a std::string, or a std::string_view, converted implicitly to located_name, which also captures the location of the call.
valuesThe range or tuple of values.
callableA generic callable object, usually a lambda, invoked with the test case and each value.
Returns
Nothing.
Since
6.0.0

Forwards to detail::test_each_value(), which adds the test cases with test(), so they are nested in the running test case, if any.

Definition at line 1122 of file test-inlines.h.

1124 {
1125 detail::test_each_value (*this, name, std::forward<Values_T> (values),
1126 callable);
1127 }

References micro_os_plus::micro_test_plus::detail::runnable_base::name(), test_each(), and micro_os_plus::micro_test_plus::detail::test_each_value().

Referenced by operator=(), and test_each().

◆ test_reporter()

reporter & micro_os_plus::micro_test_plus::detail::runnable_base::test_reporter ( void ) const
nodiscardprotectednoexceptinherited

Protected, since the reporter is internal to the framework; it is used by the suites and the test cases, which derive from this class, and by the check result, which is a friend.

Not named reporter(), which would hide the class detail::reporter in the derived classes.

Parameters
None.
Returns
A reference to the test reporter.

Returns the reporter owned by the runner, through its reporter_ pointer, which is valid after runner::initialise().

Definition at line 155 of file test.cpp.

156 {
157 return *runner_.reporter_;
158 }
std::unique_ptr< detail::reporter > reporter_
Owning pointer to the test reporter used for outputting test results.
Definition runner.h:1275

References runner_.

Referenced by micro_os_plus::micro_test_plus::detail::check_result::~check_result(), accepts_test_case(), after_test_case_create(), micro_os_plus::micro_test_plus::test_case::expect(), micro_os_plus::micro_test_plus::suite::fail_unexpected_exception(), micro_os_plus::micro_test_plus::test_case::fail_unexpected_exception(), micro_os_plus::micro_test_plus::test_case::report_misdirected(), micro_os_plus::micro_test_plus::test_case::report_rejected_test(), micro_os_plus::micro_test_plus::test_case::require(), run(), micro_os_plus::micro_test_plus::suite::run(), and micro_os_plus::micro_test_plus::test_case::run().

◆ test_runner()

runner & micro_os_plus::micro_test_plus::detail::runnable_base::test_runner ( void ) const
inlinenodiscardprotectednoexceptinherited

Protected, since the runner is internal to the framework; it is used by the suites and the test cases, which derive from this class and pass it to their nested test cases, and by the runner, which is a friend and selects the static suites it runs.

Not named runner(), which would hide the class runner in the derived classes.

Parameters
None.
Returns
A reference to the test runner.

Returns a reference to the owning test runner.

Definition at line 265 of file test-inlines.h.

266 {
267 return runner_;
268 }

References runner_.

Referenced by runnable_base(), micro_os_plus::micro_test_plus::static_suite::static_suite(), micro_os_plus::micro_test_plus::suite::suite(), micro_os_plus::micro_test_plus::test_case::test_case(), micro_os_plus::micro_test_plus::top_suite::top_suite(), micro_os_plus::micro_test_plus::test_case::detail::runnable_base, micro_os_plus::micro_test_plus::static_suite::link_or_reject(), micro_os_plus::micro_test_plus::top_suite::micro_test_plus::runner, reporter_tap, run(), and micro_os_plus::micro_test_plus::suite::static_suite.

◆ timings() [1/2]

const detail::stopwatch & micro_os_plus::micro_test_plus::suite::timings ( void ) const
inlinenodiscardnoexceptinherited

Returns the internal stopwatch of the suite, started before its body runs and stopped after it; for the top suite, it is started by runner::add_top_suite() and stopped by runner::run_suites(). In v5.0.1, the returned class was detail::timestamps, now a deprecated alias; only its read-only members are kept. The timings are internal; the elapsed times are shown by the reporters.

Parameters
None.
Returns
A const reference to the stopwatch of the suite.
Deprecated
the timings are internal (since 6.0.0)

Returns a const reference to the stopwatch member.

Definition at line 1148 of file test-inlines.h.

1149 {
1150 return stopwatch_;
1151 }

References stopwatch_.

Referenced by operator=().

◆ timings() [2/2]

detail::stopwatch & micro_os_plus::micro_test_plus::suite::timings ( void )
inlinenodiscardnoexceptinherited

Kept for the v5.0.1 code that binds a non-const reference (detail::timestamps& t = ts.timings ();). The test code must not start or stop the stopwatch through it, since the reporters show its elapsed time.

Parameters
None.
Returns
A reference to the stopwatch of the suite.
Deprecated
the timings are internal (since 6.0.0)

Returns a reference to the stopwatch member.

Definition at line 1159 of file test-inlines.h.

1160 {
1161 return stopwatch_;
1162 }

References stopwatch_.

◆ totals()

const counters & micro_os_plus::micro_test_plus::detail::runnable_base::totals ( void ) const
inlinenodiscardnoexceptinherited

The reference is read-only, for the const and the non-const nodes alike, so that a test case or a suite cannot modify its own counters, which decide the exit code. The counters are updated only by the framework, which accesses the protected member directly.

Parameters
None.
Returns
A const reference to the counters instance.

Returns a const reference to the counters member.

Definition at line 205 of file test-inlines.h.

206 {
207 return totals_;
208 }

References totals_.

Referenced by after_test_case_create(), micro_os_plus::micro_test_plus::detail::reporter_human::end_suite(), micro_os_plus::micro_test_plus::detail::reporter_tap::end_suite(), micro_os_plus::micro_test_plus::detail::reporter_human::end_test_case(), micro_os_plus::micro_test_plus::detail::reporter_tap::end_test_case(), micro_os_plus::micro_test_plus::detail::reporter::format_suite_totals(), micro_os_plus::micro_test_plus::detail::reporter::format_test_case_totals(), operator=(), and micro_os_plus::micro_test_plus::runner::run_suites().

◆ unlink()

void micro_os_plus::micro_test_plus::suite::unlink ( void )
privatenoexceptinherited

Called by the destructor; a suite that is not in the list, such as the top suite or a suite rejected by the runner, is left unchanged.

Parameters
None.
Returns
Nothing.

Searches the list for the suite and, if found, bypasses it.

Definition at line 760 of file test.cpp.

761 {
762 for (suite** slot = &first_; *slot != nullptr; slot = &(*slot)->next_)
763 {
764 if (*slot == this)
765 {
766 *slot = next_;
767 next_ = nullptr;
768 return;
769 }
770 }
771 }

References suite(), first_, and next_.

Referenced by ~suite(), and operator=().

Member Data Documentation

◆ callable_

std::function<void (suite&)> micro_os_plus::micro_test_plus::suite::callable_
privateinherited

Invoked by run() with a reference to this suite; a static_suite also stores its body here, so all suite callables receive a suite& reference.

Definition at line 2431 of file test.h.

Referenced by suite(), and run().

◆ child_test_cases_count_

size_t micro_os_plus::micro_test_plus::detail::runnable_base::child_test_cases_count_ = 0
protectedinherited

Incremented for each call to test(), which creates a child test_case and runs it immediately. The child test cases are not kept after they run, so that the memory does not grow with the number of test cases; only their number is needed later, for the TAP plan.

Definition at line 883 of file test.h.

Referenced by after_test_case_create(), children_subtests_count(), micro_os_plus::micro_test_plus::detail::reporter_tap::end_suite(), and micro_os_plus::micro_test_plus::detail::reporter_tap::end_test_case().

◆ first_

suite * micro_os_plus::micro_test_plus::suite::first_ = nullptr
staticconstinitprivateinherited

The list includes the registered and the static suites of all runners, sorted by name; each runner selects its own. The pointer is constant-initialised (constinit, in src/test.cpp), so it is null before any constructor runs, whatever the order of the static initialisation across translation units.

Constant-initialised, so it is null before any static constructor runs; the static suites constructed before the runner are therefore not lost.

Definition at line 2475 of file test.h.

Referenced by link(), micro_os_plus::micro_test_plus::runner::run_child_suites(), micro_os_plus::micro_test_plus::runner::static_suites_count(), and unlink().

◆ located_name_

located_name micro_os_plus::micro_test_plus::suite::located_name_
privateinherited

The suites registered with runner::add_suite(), and the static suites, run later, when the argument passed by the caller no longer exists; it is therefore moved here, and the name of the node points into it. The test cases, which run immediately, refer to the argument of test() instead.

Definition at line 2453 of file test.h.

Referenced by suite(), and micro_os_plus::micro_test_plus::runner::add_top_suite().

◆ name_

◆ next_

suite* micro_os_plus::micro_test_plus::suite::next_ = nullptr
privateinherited

Null for the last suite, and for the suites not in the list. Set by link() and unlink(), and read by the runner, which is a friend.

Definition at line 2463 of file test.h.

Referenced by link(), micro_os_plus::micro_test_plus::runner::run_child_suites(), micro_os_plus::micro_test_plus::runner::static_suites_count(), and unlink().

◆ own_index_

size_t micro_os_plus::micro_test_plus::detail::runnable_base::own_index_
protectedinherited

The position of this object within its parent, displayed by the TAP reporter in the ok/not ok lines. Set directly by the runner, which numbers the suites when it runs them, and by the top suite, which, when added, is always the first one.

Definition at line 859 of file test.h.

Referenced by runnable_base(), micro_os_plus::micro_test_plus::suite::suite(), micro_os_plus::micro_test_plus::test_case::test_case(), micro_os_plus::micro_test_plus::top_suite::top_suite(), micro_os_plus::micro_test_plus::detail::reporter_tap::end_suite(), micro_os_plus::micro_test_plus::detail::reporter_tap::end_test_case(), own_index(), micro_os_plus::micro_test_plus::detail::reporter_tap::skip_suite(), and micro_os_plus::micro_test_plus::detail::reporter_tap::skip_test_case().

◆ runner_

runner& micro_os_plus::micro_test_plus::detail::runnable_base::runner_
protectedinherited

Provides access to the reporter, to the filter, and to the state of the session (the running test case, and the abort and listing flags), and is used when aborting.

Definition at line 848 of file test.h.

Referenced by runnable_base(), abort(), accepts_test_case(), after_test_case_create(), create_test_case(), exchange_running_suite(), has_running_test_case_of(), is_aborted(), is_listing(), reject_body_exception(), running_test_case(), test_reporter(), and test_runner().

◆ stopwatch_

detail::stopwatch micro_os_plus::micro_test_plus::suite::stopwatch_
privateinherited

Measures the duration of the suite; started and stopped by run() (by the runner, for the top suite), and read by the reporters, which are friends.

Definition at line 2441 of file test.h.

Referenced by micro_os_plus::micro_test_plus::runner::add_top_suite(), micro_os_plus::micro_test_plus::detail::reporter_human::end_suite(), micro_os_plus::micro_test_plus::detail::reporter_tap::end_suite(), run(), micro_os_plus::micro_test_plus::runner::run_suites(), timings(), and timings().

◆ test_point_number_

size_t micro_os_plus::micro_test_plus::detail::runnable_base::test_point_number_ = 0
protectedinherited

Test points are numbered from 1; the value is 0 before the first one. This number counts the checks and the nested test cases of this object, in execution order, as required by the TAP ok/not ok lines. It is incremented for each check (by the check result) and for each nested test case created.

Definition at line 871 of file test.h.

Referenced by current_subtest_index(), micro_os_plus::micro_test_plus::detail::reporter_tap::end_suite(), micro_os_plus::micro_test_plus::detail::reporter_tap::fail_suite(), next_test_point_number(), micro_os_plus::micro_test_plus::detail::reporter_tap::output_fail_prefix(), micro_os_plus::micro_test_plus::detail::reporter_tap::output_pass_prefix(), and micro_os_plus::micro_test_plus::detail::reporter_tap::pass_without_text().

◆ totals_

counters micro_os_plus::micro_test_plus::detail::runnable_base::totals_
protectedinherited

For the suites, the totals include the checks of all their test cases; for a test case, they include only its own checks, plus the counts of its direct nested test cases.

The check counters are updated by the check result, which is a friend; the test case counters by after_test_case_create(), when a nested test case ends. For a suite, the totals of each of its test cases are also added, by the same function.

Definition at line 838 of file test.h.

Referenced by micro_os_plus::micro_test_plus::detail::check_result::~check_result(), accepts_test_case(), after_test_case_create(), micro_os_plus::micro_test_plus::suite::fail_unexpected_exception(), micro_os_plus::micro_test_plus::test_case::fail_unexpected_exception(), micro_os_plus::micro_test_plus::runner::reject_call(), and totals().


The documentation for this class was generated from the following files: