micro-test-plus 4.1.1
µTest++ Testing Framework
Loading...
Searching...
No Matches
test-inlines.h
Go to the documentation of this file.
1/*
2 * This file is part of the µOS++ project (https://micro-os-plus.github.io/).
3 * Copyright (c) 2021-2026 Liviu Ionescu. All rights reserved.
4 *
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose is hereby granted, under the terms of the MIT license.
7 *
8 * If a copy of the license was not distributed with this file, it can be
9 * obtained from https://opensource.org/licenses/mit.
10 *
11 * Major parts of the code are inspired from v1.1.8 of the Boost UT project,
12 * released under the terms of the Boost Version 1.0 Software License,
13 * which can be obtained from https://www.boost.org/LICENSE_1_0.txt.
14 */
15
16// ----------------------------------------------------------------------------
17
45
46#ifndef MICRO_TEST_PLUS_TEST_INLINES_H_
47#define MICRO_TEST_PLUS_TEST_INLINES_H_
48
49// ----------------------------------------------------------------------------
50
51#ifdef __cplusplus
52
53// ----------------------------------------------------------------------------
54
55#include <cstdio>
56#include <cstring>
57
58#if defined(MICRO_OS_PLUS_TRACE)
59#include <micro-os-plus/diag/trace.h>
60#endif // MICRO_OS_PLUS_TRACE
61
64
65// ----------------------------------------------------------------------------
66
67#if defined(__GNUC__)
68#pragma GCC diagnostic push
69#pragma GCC diagnostic ignored "-Waggregate-return"
70#if defined(__clang__)
71#pragma clang diagnostic ignored "-Wunknown-warning-option"
72#pragma clang diagnostic ignored "-Wc++98-compat"
73#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
74#else // GCC only
75#pragma GCC diagnostic ignored "-Wredundant-tags"
76#endif
77#endif
78
79// ============================================================================
80
82{
83 namespace detail
84 {
85 // ========================================================================
86
91 inline const char*
92 test_node::name (void) const noexcept
93 {
94 return name_;
95 }
96
101 inline runner_totals&
103 {
104 return totals_;
105 }
106
111 inline const runner_totals&
112 test_node::totals () const noexcept
113 {
114 return totals_;
115 }
116
117 // ========================================================================
118
123 inline size_t
124 runnable_base::own_index () const noexcept
125 {
126 return own_index_;
127 }
128
133 inline void
134 runnable_base::own_index (size_t index) noexcept
135 {
136 own_index_ = index;
137 }
138
143 inline size_t
145 {
147 }
148
155 inline size_t
160
165 inline size_t
167 {
168 return children_subtests_.size ();
169 }
170
175 inline class runner&
176 runnable_base::runner (void) const noexcept
177 {
178 return runner_;
179 }
180
181 // ========================================================================
182
190 template <typename Self_T>
191 template <typename Callable_T, typename... Args_T>
193 size_t own_index, Callable_T&& callable,
194 Args_T&&... arguments)
196 {
197 // When there are no extra arguments the callable already has the
198 // signature void(Self_T&), so store it directly. Only use std::bind when
199 // additional arguments must be pre-bound, to avoid triggering a GCC ARM
200 // bug in
201 // __is_nothrow_invocable<_Bind<...>, Self_T&> (GCC 15.2.1).
202 if constexpr (sizeof...(arguments) == 0)
203 {
204 callable_ = std::forward<Callable_T> (callable);
206 else
207 {
208 callable_ = std::bind (std::forward<Callable_T> (callable),
209 std::placeholders::_1,
210 std::forward<Args_T> (arguments)...);
211 }
212
213#if defined(MICRO_OS_PLUS_TRACE) \
214 && defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
215#if defined(__GNUC__)
216#pragma GCC diagnostic push
217#if defined(__clang__)
218#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
219#endif
220#endif
221 trace::printf ("%s '%s' %zu\n", __PRETTY_FUNCTION__, name, own_index_);
222#if defined(__GNUC__)
223#pragma GCC diagnostic pop
224#endif
225#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
226 }
227
234 template <typename Self_T>
236 {
237#if defined(MICRO_OS_PLUS_TRACE) \
238 && defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
239#if defined(__GNUC__)
240#pragma GCC diagnostic push
241#if defined(__clang__)
242#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
243#endif
244#endif
245 trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
246#if defined(__GNUC__)
247#pragma GCC diagnostic pop
248#endif
249#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
250 }
251
252 // ------------------------------------------------------------------------
253 } // namespace detail
254
255 // ==========================================================================
256
262 template <typename Callable_T, typename... Args_T>
263 subtest::subtest (const char* name, class runner& runner,
264 suite& parent_suite, size_t own_index,
265 size_t nesting_depth, Callable_T&& callable,
266 Args_T&&... arguments)
268 std::forward<Callable_T> (callable),
269 std::forward<Args_T> (arguments)... },
270 parent_suite_{ parent_suite }, nesting_depth_{ nesting_depth }
271 {
272#if defined(MICRO_OS_PLUS_TRACE) \
273 && defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
274#if defined(__GNUC__)
275#pragma GCC diagnostic push
276#if defined(__clang__)
277#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
278#endif
279#endif
280 trace::printf ("%s '%s' %zu %zu\n", __PRETTY_FUNCTION__, name, own_index_,
281 nesting_depth_);
282#if defined(__GNUC__)
283#pragma GCC diagnostic pop
284#endif
285#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
286 }
287
294 template <typename Callable_T, typename... Args_T>
295 void
296 subtest::test (const char* name, Callable_T&& callable,
297 Args_T&&... arguments)
298 {
299#if defined(MICRO_OS_PLUS_TRACE) \
300 && defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED)
301#if defined(__GNUC__)
302#pragma GCC diagnostic push
303#if defined(__clang__)
304#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
305#endif
306#endif
307 trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name);
308#if defined(__GNUC__)
309#pragma GCC diagnostic pop
310#endif
311#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED
312
314 auto child_subtest = std::make_unique<subtest> (
316 std::forward<Callable_T> (callable),
317 std::forward<Args_T> (arguments)...);
318
319 after_subtest_create_ (std::move (child_subtest), parent_suite_);
320 }
321
328 template <class Expr_T>
330 auto
331 subtest::expect (const Expr_T& expr, const reflection::source_location& sl)
332 {
333 return detail::deferred_reporter{ expr, false, sl, *this,
334 reporter ().expression () };
335 }
336
339 * Constructs and returns a `deferred_reporter<Expr_T>` with `abort = true`.
340 * The reporter evaluates the condition, records a pass or fail when it is
341 * destroyed, and aborts execution if the condition is false.
342 */
343 template <class Expr_T>
345 auto
346 subtest::assume (const Expr_T& expr, const reflection::source_location& sl)
347 {
348 return detail::deferred_reporter{ expr, true, sl, *this,
350 }
351
357 inline size_t
358 subtest::nesting_depth () const noexcept
359 {
360 return nesting_depth_;
361 }
362
363 // ==========================================================================
364
371 template <typename Callable_T, typename... Args_T>
372 suite::suite (const char* name, class runner& runner, Callable_T&& callable,
373 Args_T&&... arguments)
374 : runnable<suite>{ name, runner, 0, std::forward<Callable_T> (callable),
375 std::forward<Args_T> (arguments)... }
376 {
377#if defined(MICRO_OS_PLUS_TRACE) \
378 && defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
379#if defined(__GNUC__)
380#pragma GCC diagnostic push
381#if defined(__clang__)
382#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
383#endif
384#endif
385 trace::printf ("%s '%s' %zu\n", __PRETTY_FUNCTION__, name, own_index_);
386#if defined(__GNUC__)
387#pragma GCC diagnostic pop
388#endif
389#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
390 }
391
392#if defined(__GNUC__)
393#pragma GCC diagnostic push
394#if defined(__clang__)
395#pragma clang diagnostic ignored "-Wdocumentation"
396#endif
397#endif
433#if defined(__GNUC__)
434#pragma GCC diagnostic pop
435#endif
436 template <typename Callable_T, typename... Args_T>
437 void
438 suite::test (const char* name, Callable_T&& callable, Args_T&&... arguments)
439 {
440#if defined(MICRO_OS_PLUS_TRACE) \
441 && defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED)
442#if defined(__GNUC__)
443#pragma GCC diagnostic push
444#if defined(__clang__)
445#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
446#endif
447#endif
448 trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name);
449#if defined(__GNUC__)
450#pragma GCC diagnostic pop
451#endif
452#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED
453
455 auto child_subtest
456 = std::make_unique<subtest> (name, runner (), *this, own_index, 1,
457 std::forward<Callable_T> (callable),
458 std::forward<Args_T> (arguments)...);
459
460 after_subtest_create_ (std::move (child_subtest), *this);
461 }
462
467 inline detail::timestamps&
468 suite::timings () noexcept
469 {
470 return timings_;
471 }
472
477 inline const detail::timestamps&
478 suite::timings () const noexcept
479 {
480 return timings_;
481 }
482
483 // ==========================================================================
484
490 * initialisation.
491 */
492 inline void
493 top_suite::name (const char* new_name) noexcept
494 {
495 name_ = new_name;
496 }
497
498 // ==========================================================================
499
506 template <typename Callable_T, typename... Args_T>
508 Callable_T&& callable, Args_T&&... arguments)
509 // The nullptr passed to the base constructor is an optimisation to save
510 // some space, since this callble is not used by the static runner.
511 : suite{ name, detail::to_runner (runner), nullptr }
512 {
513 if constexpr (sizeof...(arguments) == 0)
514 {
515 static_callable_ = std::forward<Callable_T> (callable);
516 }
517 else
518 {
519 static_callable_ = std::bind (std::forward<Callable_T> (callable),
520 std::placeholders::_1,
521 std::forward<Args_T> (arguments)...);
522 }
523
524#if defined(MICRO_OS_PLUS_TRACE) \
525 && defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
526#if defined(__GNUC__)
527#pragma GCC diagnostic push
528#if defined(__clang__)
529#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
530#endif
531#endif
532 trace::printf ("%s '%s' %zu\n", __PRETTY_FUNCTION__, name, own_index_);
533#if defined(__GNUC__)
534#pragma GCC diagnostic pop
535#endif
536#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
537
539 }
540
541 // --------------------------------------------------------------------------
542} // namespace micro_os_plus::micro_test_plus
543
544#if defined(__GNUC__)
545#pragma GCC diagnostic pop
546#endif
547
548// ----------------------------------------------------------------------------
549
550#endif // __cplusplus
551
552// ----------------------------------------------------------------------------
553
554#endif // MICRO_TEST_PLUS_TEST_INLINES_H_
555
556// ----------------------------------------------------------------------------
Deferred reporter class for a specific expression.
class runner & runner(void) const noexcept
Gets the test runner associated with this test runnable.
size_t current_subtest_index() const noexcept
Returns the index of the most recently created child subtest.
runnable_base(const char *name, runner &runner, size_t own_index)
Constructs a runnable_base with a name, runner, and index.
Definition test.cpp:145
void after_subtest_create_(std::unique_ptr< subtest > child_test, suite &suite)
Definition test.cpp:224
size_t own_index_
The test index, counting from 1.
Definition test.h:406
size_t own_index() const noexcept
Returns the positional index of this object within its parent.
size_t current_subtest_index_
The subtest index, counting from 1.
Definition test.h:417
class reporter & reporter(void) const noexcept
Definition test.cpp:196
size_t children_subtests_count(void) const noexcept
Returns the number of direct child subtests owned by this node.
class runner & runner_
Reference to the test runner that owns this object.
Definition test.h:401
size_t increment_subtest_index() noexcept
Increments and returns the child subtest sequential index.
std::vector< std::unique_ptr< subtest > > children_subtests_
Owning collection of direct child subtests.
Definition test.h:427
runnable(const char *name, class runner &runner, size_t own_index, Callable_T &&callable, Args_T &&... arguments)
Class template constructor.
virtual ~runnable() override
Virtual destructor.
Aggregated pass/fail/subtest counters for a node in the test tree.
const char * name(void) const noexcept
Gets the node name.
runner_totals totals_
Totals for the test node, including nested cases.
Definition test.h:229
runner_totals & totals() noexcept
Gets the totals for the test.
const char * name_
The test node name.
Definition test.h:224
A begin/end timestamp pair used to measure elapsed time.
Definition timings.h:205
Local implementation of source location information for diagnostics.
Definition reflection.h:138
detail::expression_formatter & expression()
Provides access to the expression formatter for this reporter.
The test runner for the µTest++ framework.
Definition runner.h:111
A runner variant that also manages statically-registered test suites.
Definition runner.h:345
std::function< void(static_suite &)> static_callable_
Callable storing the static suite body and any bound arguments. Invoked with a reference to the concr...
Definition test.h:990
static_suite(const char *name, static_runner &runner, Callable_T &&callable, Args_T &&... arguments)
Class template constructor for static_suite.
suite & parent_suite_
Reference to the parent suite that owns this subtest.
Definition test.h:683
void test(const char *name, Callable_T &&callable, Args_T &&... arguments)
Adds a test case to the suite.
subtest(const char *name, class runner &runner, suite &parent_suite, size_t own_index, size_t nesting_depth, Callable_T &&callable, Args_T &&... arguments)
Constructs a subtest with a name, runner, parent suite, index, nesting depth, and callable.
size_t nesting_depth_
The nesting depth of this subtest within the suite.
Definition test.h:688
size_t nesting_depth() const noexcept
Returns the nesting depth of this subtest.
A named, runnable test suite registered with the test runner.
Definition test.h:714
suite(const char *name, class runner &runner, Callable_T &&callable, Args_T &&... arguments)
Constructs a suite with a name, runner, and callable body.
detail::timestamps timings_
Timing measurements for this suite's execution.
Definition test.h:818
detail::timestamps & timings() noexcept
Gets the timings for this suite.
void test(const char *name, Callable_T &&callable, Args_T &&... arguments)
Adds a test case to the suite.
const char * name(void) const noexcept
Gets the node name.
void name(const char *new_name) noexcept
Sets the name of the top-level suite.
C++20 concept satisfied when a type can be used as a test expression in expect() or assume().
C++ header file with declarations for the µTest++ deferred reporter.
auto assume(const Expr_T &expr, const reflection::source_location &sl=reflection::source_location::current())
Check a condition and, if false, abort test execution.
auto expect(const Expr_T &expr, const reflection::source_location &sl=reflection::source_location::current())
Evaluate a generic condition and report the results.
Internal implementation details for the µTest++ framework.
void register_static_suite(static_runner &static_runner_ref, static_suite &static_suite_ref)
Registers a static suite with a static runner.
Definition runner.cpp:102
Primary namespace for the µTest++ testing framework.
C++ header file with declarations for the µTest++ test reporter.