micro-test-plus 6.0.0
µ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
43
44#ifndef MICRO_OS_PLUS_MICRO_TEST_PLUS_INLINES_TEST_INLINES_H_
45#define MICRO_OS_PLUS_MICRO_TEST_PLUS_INLINES_TEST_INLINES_H_
46
47// ----------------------------------------------------------------------------
48
49#if defined(__cplusplus)
50
51// ----------------------------------------------------------------------------
52
56
57#if __has_include("micro-os-plus/diag/trace.h")
58#include "micro-os-plus/diag/trace.h"
59#endif // __has_include("micro-os-plus/diag/trace.h")
60
61#include <cstdio>
62#include <cstring>
63#include <exception>
64
65// ----------------------------------------------------------------------------
66
67#if defined(__GNUC__)
68#pragma GCC diagnostic push
69
70#pragma GCC diagnostic ignored "-Waggregate-return"
71#pragma GCC diagnostic ignored "-Wformat"
72#pragma GCC diagnostic ignored "-Wformat-extra-args"
73#pragma GCC diagnostic ignored "-Wpadded"
74#if defined(__clang__)
75#pragma clang diagnostic ignored "-Wunknown-warning-option"
76#pragma clang diagnostic ignored "-Wc++98-compat"
77#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
78#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
79#else // GCC only
80#pragma GCC diagnostic ignored "-Wredundant-tags"
81#endif // defined(__clang__)
82#endif // defined(__GNUC__)
83
84// ============================================================================
85
87{
88 // ==========================================================================
89
97 template <typename Pointer_T>
98 requires (std::is_same_v<Pointer_T, const char*>
99 or std::is_same_v<Pointer_T, char*>
100 or std::is_null_pointer_v<Pointer_T>)
103 : name_{ name != nullptr ? name : "" }, location_{ location }
104 {
106 }
107
115 template <std::size_t N>
118 : name_{ std::string_view{ name, N }.substr (
119 0, std::string_view{ name, N }.find ('\0')) },
121 {
123 }
124
137
145 std::string&& name, const reflection::source_location& location)
146 : name_{ std::move (name) }, location_{ location }
147 {
149 }
150
163
168 inline const char*
169 located_name::name (void) const noexcept
170 {
171 return name_.c_str ();
172 }
173
178 inline const reflection::source_location&
179 located_name::location (void) const noexcept
180 {
181 return location_;
182 }
183
184 // --------------------------------------------------------------------------
185
186 namespace detail
187 {
188 // ========================================================================
189
194 inline const char*
195 runnable_base::name (void) const noexcept
196 {
197 return name_;
198 }
199
204 inline const counters&
205 runnable_base::totals (void) const noexcept
206 {
207 return totals_;
208 }
209
210#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
216 // Deprecated since 6.0.0; internal to the framework.
217 inline size_t
218 runnable_base::own_index (void) const noexcept
219 {
220 return own_index_;
221 }
222
227 // Deprecated since 6.0.0; internal to the framework.
228 inline size_t
230 {
231 return test_point_number_;
232 }
233
239 // Deprecated since 6.0.0; internal to the framework.
240 inline size_t
242 {
244 }
245#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
246
254 inline size_t
256 {
257 return ++test_point_number_;
258 }
259
264 inline runner&
265 runnable_base::test_runner (void) const noexcept
266 {
267 return runner_;
268 }
269
290 template <typename Callable_T, typename... Args_T>
291 inline void
293 suite& parent_suite, size_t nesting_depth,
294 Callable_T&& callable,
295 Args_T&&... arguments)
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 }
326
327 // ========================================================================
328
342 template <typename Self_T, typename Callable_T, typename... Args_T>
343 auto
344 bind_callable (Callable_T&& callable, Args_T&&... arguments)
345 {
346 if constexpr (sizeof...(arguments) == 0)
347 {
348 return std::forward<Callable_T> (callable);
349 }
350 else
351 {
353 std::decay_t<Args_T>...>{
354 std::forward<Callable_T> (callable),
355 std::forward<Args_T> (arguments)...
356 };
357 }
358 }
359
360 // ========================================================================
361
367 template <typename Self_T, typename Callable_T, typename... Args_T>
368 template <typename C, typename... A>
369 requires (sizeof...(A) > 0)
371 C&& callable, A&&... arguments)
372 : callable_ (std::forward<C> (callable)),
373 arguments_ (std::forward<A> (arguments)...)
374 {
375 }
376
381 template <typename Self_T, typename Callable_T, typename... Args_T>
382 inline void
384 {
385 invoke (self, std::index_sequence_for<Args_T...>{});
386 }
387
396 template <typename Self_T, typename Callable_T, typename... Args_T>
397 template <std::size_t... Is>
398 inline void
400 Self_T& self, std::index_sequence<Is...>)
401 {
402 if constexpr (std::is_member_pointer_v<Callable_T>)
403 {
404 std::invoke (callable_, self, std::get<Is> (arguments_)...);
405 }
406 else
407 {
408 callable_ (self, std::get<Is> (arguments_)...);
409 }
410 }
411
412 // ========================================================================
413
420 template <typename Callable_T, typename... Args_T>
421 constexpr void
422 reject_test_body (void) noexcept
423 {
424 if constexpr (std::is_invocable_v<std::decay_t<Callable_T>&, suite&,
425 std::decay_t<Args_T>&...>)
426 {
427 static_assert (dependent_false_v<Callable_T, Args_T...>,
428 "the body of a test case takes a test_case& as its "
429 "first parameter, not a suite&");
430 }
431 else
432 {
433 static_assert (dependent_false_v<Callable_T, Args_T...>,
434 "the body of a test case takes a test_case& as its "
435 "first parameter, followed by the additional "
436 "arguments passed to test ()");
437 }
438 }
439
446 template <typename Callable_T, typename... Args_T>
447 constexpr void
448 reject_suite_body (void) noexcept
449 {
450 if constexpr (not std::is_copy_constructible_v<std::decay_t<Callable_T>>
451 or not(std::is_copy_constructible_v<std::decay_t<Args_T>>
452 and ...))
453 {
454 static_assert (dependent_false_v<Callable_T, Args_T...>,
455 "the body of a suite and its additional arguments "
456 "must be copyable, since the suite runs later");
457 }
458 else if constexpr (std::is_invocable_v<std::decay_t<Callable_T>&,
459 test_case&,
460 std::decay_t<Args_T>&...>)
461 {
462 static_assert (dependent_false_v<Callable_T, Args_T...>,
463 "the body of a suite takes a suite& as its first "
464 "parameter, not a test_case&");
465 }
466 else
467 {
468 static_assert (dependent_false_v<Callable_T, Args_T...>,
469 "the body of a suite takes a suite& as its first "
470 "parameter, followed by the additional arguments");
471 }
472 }
473
479 template <typename Self_T>
480 template <typename Callable_T>
481 requires (!std::is_same_v<std::remove_cv_t<Callable_T>,
482 callable_ref<Self_T>>)
483 callable_ref<Self_T>::callable_ref (Callable_T& callable) noexcept
484 : callable_{ const_cast<void*> (
485 static_cast<const volatile void*> (std::addressof (callable))) },
486 invoke_{ &invoke_callable<Callable_T> }
487 {
488 }
489
494 template <typename Self_T>
495 inline void
497 {
498 invoke_ (callable_, self);
499 }
500
512 template <typename Self_T>
513 template <typename Callable_T>
514 void
515 callable_ref<Self_T>::invoke_callable (void* callable, Self_T& self)
516 {
517 if constexpr (std::is_member_pointer_v<Callable_T>)
518 {
519 std::invoke (*static_cast<Callable_T*> (callable), self);
520 }
521 else
522 {
523 (*static_cast<Callable_T*> (callable)) (self);
524 }
525 }
526
527 // ------------------------------------------------------------------------
528 } // namespace detail
529
530 // ==========================================================================
531
540 suite& parent_suite, size_t own_index,
541 size_t nesting_depth,
544 callable_{ body }, located_name_{ name },
545 parent_suite_{ parent_suite }, nesting_depth_{ nesting_depth }
546 {
547#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
548 trace::printf ("%s '%s' %" MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE
550 __PRETTY_FUNCTION__, name_, own_index_, nesting_depth_);
551#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
552 }
553
561 template <typename Callable_T, typename... Args_T>
562 requires detail::test_body<Callable_T, Args_T...>
563 void
564 test_case::test (const located_name& name, Callable_T&& callable,
565 Args_T&&... arguments)
566 {
567#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED)
568 trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name.name ());
569#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED
570
571 if (is_misdirected ()) [[unlikely]]
572 {
574 return;
575 }
576
578 std::forward<Callable_T> (callable),
579 std::forward<Args_T> (arguments)...);
580 }
581
582#if !defined(__DOXYGEN__)
588 template <typename Callable_T, typename... Args_T>
589 requires (!detail::test_body<Callable_T, Args_T...>)
590 void
591 test_case::test ([[maybe_unused]] const located_name& name,
592 [[maybe_unused]] Callable_T&& callable,
593 [[maybe_unused]] Args_T&&... arguments)
594 {
595 detail::reject_test_body<Callable_T, Args_T...> ();
596 }
597#endif // !defined(__DOXYGEN__)
598
604 inline bool
605 test_case::is_misdirected (void) const noexcept
606 {
607 const test_case* running = running_test_case ();
608 return running != nullptr && running != this;
609 }
610
620 template <class Expr_T>
623 test_case::expect (const Expr_T& expr, const reflection::source_location& sl,
624 detail::check_result&& result)
625 {
626 if (is_misdirected ()) [[unlikely]]
627 {
629 std::move (result));
630 }
631
632 result.init (expr, detail::check_kind::expectation, sl, *this,
633 test_reporter ().expression_,
634 test_reporter ().writes_passed_checks ());
635 return std::move (result);
636 }
637
638#if !defined(__DOXYGEN__)
645 template <class Expr_T>
648 test_case::expect ([[maybe_unused]] const Expr_T& expr,
649 [[maybe_unused]] const reflection::source_location& sl,
650 detail::check_result&& result)
651 {
653 {
654 static_assert (not detail::ambiguous_condition<Expr_T>,
655 "expect() does not take a wrapper of a bool, whose "
656 "condition tests the wrapper, not the value; write "
657 "has_value () or != nullptr, or use eq ()");
658 }
659 else
660 {
661 static_assert (extension::checkable<Expr_T>,
662 "expect() takes a Boolean condition or a comparison, "
663 "such as eq (); a value of this type is neither");
664 }
665 return std::move (result);
666 }
667#endif // !defined(__DOXYGEN__)
668
680 template <class Expr_T>
683 test_case::require (const Expr_T& expr,
685 detail::check_result&& result)
686 {
687 if (is_misdirected ()) [[unlikely]]
688 {
690 std::move (result));
691 }
692
693 result.init (expr, detail::check_kind::requirement, sl, *this,
694 test_reporter ().expression_,
695 test_reporter ().writes_passed_checks ());
696 return std::move (result);
697 }
698
699#if !defined(__DOXYGEN__)
707 template <class Expr_T>
710 test_case::require ([[maybe_unused]] const Expr_T& expr,
711 [[maybe_unused]] const reflection::source_location& sl,
712 detail::check_result&& result)
713 {
715 {
716 static_assert (not detail::ambiguous_condition<Expr_T>,
717 "require() does not take a wrapper of a bool, whose "
718 "condition tests the wrapper, not the value; write "
719 "has_value () or != nullptr, or use eq ()");
720 }
721 else
722 {
723 static_assert (extension::checkable<Expr_T>,
724 "require() takes a Boolean condition or a comparison, "
725 "such as eq (); a value of this type is neither");
726 }
727 return std::move (result);
728 }
729#endif // !defined(__DOXYGEN__)
730
731#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
732#if !defined(__DOXYGEN__)
733 // Hidden from Doxygen: the comments of these definitions would be
734 // merged into the documentation of `expect()` and `require()`, which
735 // differ only in their `requires` clause; the comments of the
736 // declarations are the documentation.
742 template <class Expr_T>
745 test_case::expect (const Expr_T& expr, const reflection::source_location& sl,
746 detail::check_result&& result)
747 {
748 result.init (expr, detail::check_kind::expectation, sl, *this,
749 test_reporter ().expression_,
750 test_reporter ().writes_passed_checks ());
751 return std::move (result);
752 }
753
759 template <class Expr_T>
762 test_case::require (const Expr_T& expr,
764 detail::check_result&& result)
765 {
766 result.init (expr, detail::check_kind::requirement, sl, *this,
767 test_reporter ().expression_,
768 test_reporter ().writes_passed_checks ());
769 return std::move (result);
770 }
771#endif // !defined(__DOXYGEN__)
772
779 // Deprecated since 6.0.0; use require().
780 template <class Expr_T>
783 test_case::assume (const Expr_T& expr, const reflection::source_location& sl,
784 detail::check_result&& result)
785 {
786 return require (expr, sl, std::move (result));
787 }
788#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
789
795 inline size_t
796 test_case::nesting_depth (void) const noexcept
797 {
798 return nesting_depth_;
799 }
800
826 inline void
828 {
829#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED)
830 trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name_);
831#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_ENABLED
832
833 detail::reporter& reporter = this->test_reporter ();
834
835 // For now, test cases do not record the time.
836 // this->stopwatch_.start ();
837 reporter.begin_test_case (*this);
838
839#if defined(__cpp_exceptions)
840 try
841 {
842 // Invoke the callable, passing the self reference; the arguments
843 // of test() are bound to it, by bind_callable().
844 callable_ (*this);
845 }
846 catch (const detail::failed_requirement&)
847 {
848 // A failed require() stopped the test case; already reported.
849 }
850 catch (const std::exception& e)
851 {
852 if (is_aborted ())
853 {
854 // Thrown by the abort handler; the report is complete.
855 throw;
856 }
857 fail_unexpected_exception (e.what ());
858 }
859 catch (...)
860 {
861 if (is_aborted ())
862 {
863 // Thrown by the abort handler; the report is complete.
864 throw;
865 }
867 }
868#else
869 // Invoke the callable, passing the self reference; the arguments of
870 // test() are bound to it, by bind_callable().
871 callable_ (*this);
872#endif // defined(__cpp_exceptions)
873
874 // this->stopwatch_.stop ();
875 reporter.end_test_case (*this);
876 }
877
878 // ==========================================================================
879
891 template <typename Callable_T, typename... Args_T>
893 Callable_T&& callable, Args_T&&... arguments)
894 : runnable_base{ "", test_runner, 0 },
895 callable_{ detail::bind_callable<suite> (
896 std::forward<Callable_T> (callable),
897 std::forward<Args_T> (arguments)...) },
898 located_name_{ std::move (name) }
899 {
901
902#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
903 trace::printf ("%s '%s' %" MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE "\n",
904 __PRETTY_FUNCTION__, name_, own_index_);
905#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
906 }
907
908#if defined(__GNUC__)
909#pragma GCC diagnostic push
910
911#if defined(__clang__)
912#pragma clang diagnostic ignored "-Wdocumentation"
913#endif // defined(__clang__)
914#endif // defined(__GNUC__)
915
964
965 template <typename Callable_T, typename... Args_T>
966 requires detail::test_body<Callable_T, Args_T...>
967 void
968 suite::test (const located_name& name, Callable_T&& callable,
969 Args_T&&... arguments)
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 }
994
995#if !defined(__DOXYGEN__)
1001 template <typename Callable_T, typename... Args_T>
1002 requires (!detail::test_body<Callable_T, Args_T...>)
1003 void
1004 suite::test ([[maybe_unused]] const located_name& name,
1005 [[maybe_unused]] Callable_T&& callable,
1006 [[maybe_unused]] Args_T&&... arguments)
1007 {
1008 detail::reject_test_body<Callable_T, Args_T...> ();
1009 }
1010#endif // !defined(__DOXYGEN__)
1011
1012 // --------------------------------------------------------------------------
1013
1014 namespace detail
1015 {
1027 template <class Self_T, class Values_T, class Callable_T>
1028 void
1029 test_each_value (Self_T& self, const located_name& name, Values_T&& values,
1030 Callable_T& callable)
1031 {
1032 std::size_t position = 0;
1033
1034 const auto run_one
1035 = [&self, &name, &callable, &position] (const auto& value)
1036 {
1037 ++position;
1038
1039 std::string text{ name.name () };
1040 text += " (";
1041 if constexpr (extension::printable<
1042 std::remove_cvref_t<decltype (value)>>)
1043 {
1044 plain_text::append (text, value);
1045 }
1046 else
1047 {
1048 text += '#';
1049 plain_text::append (text, position);
1050 }
1051 text += ')';
1052
1053 // The test case runs within this call, so the value and the
1054 // callable are captured by reference, not copied.
1055 self.test (located_name{ std::move (text), name.location () },
1056 [&callable, &value] (auto& test_self)
1057 {
1058 if constexpr (std::is_member_pointer_v<
1059 std::remove_cvref_t<Callable_T>>)
1060 {
1061 std::invoke (callable, test_self, value);
1062 }
1063 else
1064 {
1065 callable (test_self, value);
1066 }
1067 });
1069
1070 if constexpr (test_values_range<Values_T>)
1071 {
1072 for (const auto& value : values)
1073 {
1074 run_one (value);
1075 }
1076 }
1077 else
1078 {
1079 std::apply ([&run_one] (const auto&... elements)
1080 { (run_one (elements), ...); }, values);
1081 }
1082 }
1083 } // namespace detail
1084
1085 /**
1086 * @details
1087 * Forwards to `detail::test_each_value()`, which adds the test cases
1088 * with `test()`.
1089 */
1090 template <typename Values_T, typename Callable_T>
1093 void
1094 test_case::test_each (const located_name& name, Values_T&& values,
1095 Callable_T&& callable)
1096 {
1097 detail::test_each_value (*this, name, std::forward<Values_T> (values),
1098 callable);
1099 }
1100
1105 template <typename T, typename Callable_T>
1106 void
1108 std::initializer_list<T> values, Callable_T&& callable)
1109 {
1110 detail::test_each_value (*this, name, values, callable);
1111 }
1112
1118 template <typename Values_T, typename Callable_T>
1121 void
1122 suite::test_each (const located_name& name, Values_T&& values,
1123 Callable_T&& callable)
1124 {
1125 detail::test_each_value (*this, name, std::forward<Values_T> (values),
1126 callable);
1127 }
1128
1133 template <typename T, typename Callable_T>
1134 void
1135 suite::test_each (const located_name& name, std::initializer_list<T> values,
1136 Callable_T&& callable)
1137 {
1138 detail::test_each_value (*this, name, values, callable);
1139 }
1140
1141#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
1146 // Deprecated since 6.0.0; the timings are internal.
1147 inline const detail::stopwatch&
1148 suite::timings (void) const noexcept
1149 {
1150 return stopwatch_;
1151 }
1152
1157 // Deprecated since 6.0.0; the timings are internal.
1158 inline detail::stopwatch&
1159 suite::timings (void) noexcept
1160 {
1161 return stopwatch_;
1162 }
1163#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
1164
1165 // ==========================================================================
1166
1177 template <typename Callable_T, typename... Args_T>
1178 requires (!detail::static_suite_body<Callable_T, Args_T...>
1179 && detail::suite_body<Callable_T, Args_T...>)
1181 Callable_T&& callable, Args_T&&... arguments)
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 }
1193
1194#if !defined(__DOXYGEN__)
1202 template <typename Callable_T, typename... Args_T>
1203 requires (!detail::static_suite_body<Callable_T, Args_T...>
1204 && !detail::suite_body<Callable_T, Args_T...>)
1205 static_suite::static_suite (located_name name, runner& test_runner,
1206 [[maybe_unused]] Callable_T&& callable,
1207 [[maybe_unused]] Args_T&&... arguments)
1208 : suite{ std::move (name), test_runner, [] (suite&) noexcept {} }
1209 {
1210 detail::reject_suite_body<Callable_T, Args_T...> ();
1211 }
1212#endif // !defined(__DOXYGEN__)
1213
1214#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
1225 // Deprecated since 6.0.0; use a suite& first parameter.
1226 template <typename Callable_T, typename... Args_T>
1227 requires (detail::static_suite_body<Callable_T, Args_T...>)
1229 Callable_T&& callable, Args_T&&... arguments)
1230 : suite{ std::move (name), test_runner,
1231 [stored_callable = std::forward<Callable_T> (callable)] (
1232 suite& self, auto&... stored_arguments) mutable
1233 {
1234 stored_callable (static_cast<static_suite&> (self), stored_arguments...);
1235 },
1236 std::forward<Args_T> (arguments)... }
1237 {
1238#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED)
1239 trace::printf ("%s '%s' %" MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE "\n",
1240 __PRETTY_FUNCTION__, name_, own_index_);
1241#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_TRACE_CONSTRUCTORS_ENABLED
1242
1243 link_or_reject ();
1244 }
1245#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
1246
1247 // --------------------------------------------------------------------------
1248} // namespace micro_os_plus::micro_test_plus
1249
1250// ----------------------------------------------------------------------------
1251
1252#if defined(__GNUC__)
1253#pragma GCC diagnostic pop
1254#pragma GCC diagnostic pop
1255#endif // defined(__GNUC__)
1256
1257// ----------------------------------------------------------------------------
1258
1259#endif // defined(__cplusplus)
1260
1261// ----------------------------------------------------------------------------
1262
1263#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_INLINES_TEST_INLINES_H_
1264
1265// ----------------------------------------------------------------------------
C++ header file with declarations for the µTest++ check result.
Aggregated check and test case counters for a node in the test tree.
Definition counters.h:123
Function object that holds a callable and the additional arguments it is invoked with.
Definition test.h:944
constexpr bound_callable(C &&callable, A &&... arguments)
Constructs the function object from a callable and the arguments.
void operator()(Self_T &self)
Invokes the stored callable.
std::tuple< Args_T... > arguments_
The stored arguments.
Definition test.h:1020
void invoke(Self_T &self, std::index_sequence< Is... >)
Invokes the stored callable with the stored arguments, unpacked by their indices.
Callable_T callable_
The stored callable.
Definition test.h:1011
Non-owning reference to a callable invoked with a Self_T& argument.
Definition test.h:1047
void operator()(Self_T &self) const
Invokes the referred callable.
callable_ref(Callable_T &callable) noexcept
Constructs a reference to a callable.
void * callable_
The address of the referred callable.
Definition test.h:1112
void(*) invoke_(void *callable, Self_T &self)
The function that invokes the referred callable.
Definition test.h:1121
static void invoke_callable(void *callable, Self_T &self)
Invokes a callable of a given type, from its address.
The result of one check, reported when destroyed.
void init(const Expr_T &expr, check_kind kind, const reflection::source_location &location, test_case &test_case, expression_formatter &expression, bool writes_passed)
Initialises the result with the check of an expression.
Abstract base class for the reporters that display test results, including operand values for failure...
Definition reporter.h:276
virtual void end_test_case(const test_case &test_case)=0
Marks the end of a test case.
virtual void begin_test_case(const test_case &test_case)=0
Marks the beginning of a test case.
runner & test_runner(void) const noexcept
Returns the test runner that owns this test runnable.
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
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
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 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.
size_t current_subtest_index(void) const noexcept
Deprecated number of the most recent child test point.
class reporter & test_reporter(void) const noexcept
Returns the test reporter associated with this test runnable.
Definition test.cpp:155
size_t own_index(void) const noexcept
Deprecated positional index of this node within its parent.
runnable_base(const char *name, runner &test_runner, size_t own_index)
Constructs a runnable_base with a name, runner, and index.
Definition test.cpp:126
const counters & totals(void) const noexcept
Returns the totals of the node.
bool is_aborted(void) const noexcept
Checks whether the test execution was aborted by the owning runner.
Definition test.cpp:177
size_t children_subtests_count(void) const noexcept
Deprecated number of direct child test cases of this node.
runner & runner_
Reference to the test runner that owns this object.
Definition test.h:848
size_t test_point_number_
The number of the most recent child test point.
Definition test.h:871
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
size_t child_test_cases_count_
The number of direct child test cases.
Definition test.h:883
Measures the elapsed time of an operation.
Definition stopwatch.h:138
A name of a suite or of a test case, with the location where it was given.
Definition test.h:177
reflection::source_location location_
The location where the name was given.
Definition test.h:298
std::string name_
The copy of the name.
Definition test.h:289
const char * name(void) const noexcept
Returns the name.
located_name(Pointer_T name, const reflection::source_location &location=reflection::source_location::current())
Constructs the name from a C string, capturing the location of the caller.
const reflection::source_location & location(void) const noexcept
Returns the location where the name was given.
Local implementation of source location information for diagnostics.
Definition reflection.h:143
The test runner for the µTest++ framework.
Definition runner.h:187
A test suite designed for static (namespace-scope) registration with a runner.
Definition test.h:2645
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.
A named, runnable test suite registered with the test runner.
Definition test.h:2059
const detail::stopwatch & timings(void) const noexcept
Deprecated access to the timings of the suite.
void test(const located_name &name, Callable_T &&callable, Args_T &&... arguments)
Adds a test case to the suite, and runs it.
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.
friend class micro_test_plus::runner
The runner, which creates and runs the suites.
Definition test.h:2067
located_name located_name_
The name of the suite, with the location where it was given.
Definition test.h:2453
detail::stopwatch stopwatch_
Stopwatch of this suite.
Definition test.h:2441
suite(located_name &&name, runner &test_runner, Callable_T &&callable, Args_T &&... arguments)
Constructs a suite with a name, runner, and callable body.
std::function< void(suite &)> callable_
Callable storing the suite body and any bound arguments.
Definition test.h:2431
friend class static_suite
The static suite, which registers itself.
Definition test.h:2099
A named, runnable test case that lives inside a suite.
Definition test.h:1362
void fail_unexpected_exception(const char *what)
Reports an exception that escaped the test case body as a failed check.
Definition test.cpp:535
size_t nesting_depth_
The nesting depth of this test case within the suite.
Definition test.h:2015
suite & parent_suite_
Reference to the parent suite that owns this test case.
Definition test.h:2007
void test_each(const located_name &name, Values_T &&values, Callable_T &&callable)
Adds a nested test case for each value of a range or a tuple, and runs them.
friend class detail::runnable_base
The base of the nodes, which creates the test cases.
Definition test.h:1382
test_case(const located_name &name, runner &test_runner, suite &parent_suite, size_t own_index, size_t nesting_depth, detail::callable_ref< test_case > body)
Constructs a test case with a name, runner, parent suite, index, nesting depth, and body.
friend class micro_test_plus::runner
The runner, which reports the rejected calls as failed checks of the running test case.
Definition test.h:1373
bool is_misdirected(void) const noexcept
Tells whether another test case is running.
const located_name & located_name_
The name and the location of the call to test() that created this test case.
Definition test.h:1998
detail::check_result && report_misdirected(detail::check_kind kind, const reflection::source_location &sl, detail::check_result &&result)
Reports a check on this test case as a failure of the running one.
Definition test.cpp:444
void test(const located_name &name, Callable_T &&callable, Args_T &&... arguments)
Adds a nested test case to this test case, and runs it.
detail::callable_ref< test_case > callable_
Reference to the test case body, with any bound arguments.
Definition test.h:1985
void report_misdirected_test(const located_name &name)
Reports a nested test case started on this test case as a failure of the running one.
Definition test.cpp:472
void run(void) override
Executes the test case body by invoking the referred callable.
detail::check_result && assume(const Expr_T &expr, const reflection::source_location &sl=reflection::source_location::current(), detail::check_result &&result=detail::check_result{})
Deprecated name of require().
size_t nesting_depth(void) const noexcept
Returns the nesting depth of this test case.
Concept satisfied by the wrappers of a bool, whose condition is ambiguous.
Definition extension.h:216
Concept satisfied when a type was accepted by expect() and require() before the exclusion of the susp...
Definition extension.h:506
The body of a static suite written for v5.0.1, whose first parameter is a static_suite& reference.
Definition test.h:2594
Concept satisfied by a callable object that can be the body of a suite.
Definition test.h:1217
Concept satisfied by a callable object that can be the body of a test case.
Definition test.h:1198
Concept satisfied when T is a range of values for test_each().
Definition test.h:1139
Concept satisfied when T is a tuple of values for test_each().
Definition test.h:1155
Concept satisfied by a value that expect() and require() do not accept.
Definition test.h:1240
Concept satisfied when a type can be used as a test expression in expect() or require().
Definition extension.h:403
Concept satisfied when a type can be appended to the message of a check result via operator<<.
Definition extension.h:433
C++ header file with declarations for the µTest++ internals.
#define MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE
Portable printf() conversion for the size_t values.
Definition detail.h:102
detail::check_result && expect(const Expr_T &expr, const reflection::source_location &sl=reflection::source_location::current(), detail::check_result &&result=detail::check_result{})
Evaluates a condition and reports the result.
detail::check_result && require(const Expr_T &expr, const reflection::source_location &sl=reflection::source_location::current(), detail::check_result &&result=detail::check_result{})
Checks a condition and, if false, stops the test case.
Internal implementation details for the µTest++ framework.
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.
constexpr bool dependent_false_v
A value that is always false, but depends on the template arguments.
Definition test.h:1258
auto bind_callable(Callable_T &&callable, Args_T &&... arguments)
Creates the function object that holds the body of a test case or suite.
constexpr void reject_test_body(void) noexcept
Stops the compilation with a message that tells what the body of a test case takes.
constexpr void reject_suite_body(void) noexcept
Stops the compilation with a message that tells what the body of a suite takes.
void escape_control_characters(std::string &name)
Escapes the control characters of a name.
Definition test.cpp:80
Primary namespace for the µTest++ testing framework.
C++ header file with declarations for the µTest++ test reporter.
The exception thrown to stop a test case after a failed require().
Definition detail.h:1322
static void append(std::string &text, const T &value)
Appends a value to a text, in the plain mode of the formatter.
Struct template representing a generic value, accessible via a getter.
Definition deprecated.h:629