@micro-os-plus/micro-test-plus 3.3.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +339 -2
  2. package/CMakeLists.txt +79 -23
  3. package/README.md +1 -1
  4. package/config/xcdl-build.json +11 -4
  5. package/include/micro-os-plus/micro-test-plus/deferred-reporter.h +292 -0
  6. package/include/micro-os-plus/micro-test-plus/detail.h +462 -1076
  7. package/include/micro-os-plus/micro-test-plus/exceptions.h +126 -0
  8. package/include/micro-os-plus/micro-test-plus/function-comparators.h +10 -7
  9. package/include/micro-os-plus/micro-test-plus/inlines/{details-inlines.h → deferred-reporter-inlines.h} +49 -22
  10. package/include/micro-os-plus/micro-test-plus/inlines/function-comparators-inlines.h +67 -4
  11. package/include/micro-os-plus/micro-test-plus/inlines/literals-inlines.h +3 -6
  12. package/include/micro-os-plus/micro-test-plus/inlines/math-inlines.h +21 -15
  13. package/include/micro-os-plus/micro-test-plus/inlines/reflection-inlines.h +35 -17
  14. package/include/micro-os-plus/micro-test-plus/inlines/{test-reporter-inlines.h → reporter-inlines.h} +176 -106
  15. package/include/micro-os-plus/micro-test-plus/inlines/{test-suite-inlines.h → runner-inlines.h} +41 -43
  16. package/include/micro-os-plus/micro-test-plus/inlines/test-inlines.h +369 -0
  17. package/include/micro-os-plus/micro-test-plus/inlines/utility-inlines.h +126 -0
  18. package/include/micro-os-plus/micro-test-plus/literals.h +4 -3
  19. package/include/micro-os-plus/micro-test-plus/math.h +9 -6
  20. package/include/micro-os-plus/micro-test-plus/operators.h +38 -44
  21. package/include/micro-os-plus/micro-test-plus/reflection.h +15 -4
  22. package/include/micro-os-plus/micro-test-plus/{test-reporter-basic.h → reporter-human.h} +72 -72
  23. package/include/micro-os-plus/micro-test-plus/{test-reporter-tap.h → reporter-tap.h} +69 -69
  24. package/include/micro-os-plus/micro-test-plus/{test-reporter.h → reporter.h} +296 -200
  25. package/include/micro-os-plus/micro-test-plus/runner-totals.h +264 -0
  26. package/include/micro-os-plus/micro-test-plus/runner.h +453 -0
  27. package/include/micro-os-plus/micro-test-plus/test.h +1069 -0
  28. package/include/micro-os-plus/micro-test-plus/timings.h +366 -0
  29. package/include/micro-os-plus/micro-test-plus/type-traits.h +239 -545
  30. package/include/micro-os-plus/micro-test-plus/utility.h +135 -0
  31. package/include/micro-os-plus/micro-test-plus.h +25 -228
  32. package/meson.build +10 -6
  33. package/package.json +1 -1
  34. package/src/deferred-reporter.cpp +118 -0
  35. package/src/reflection.cpp +95 -0
  36. package/src/reporter-human.cpp +822 -0
  37. package/src/reporter-tap.cpp +782 -0
  38. package/src/reporter.cpp +676 -0
  39. package/src/runner-totals.cpp +95 -0
  40. package/src/runner.cpp +563 -0
  41. package/src/test.cpp +496 -0
  42. package/src/timings.cpp +209 -0
  43. package/src/utility.cpp +163 -0
  44. package/.cmake-format.yaml +0 -11
  45. package/include/micro-os-plus/micro-test-plus/inlines/micro-test-plus-inlines.h +0 -313
  46. package/include/micro-os-plus/micro-test-plus/test-runner.h +0 -281
  47. package/include/micro-os-plus/micro-test-plus/test-suite.h +0 -492
  48. package/src/micro-test-plus.cpp +0 -316
  49. package/src/test-reporter-basic.cpp +0 -466
  50. package/src/test-reporter-tap.cpp +0 -530
  51. package/src/test-reporter.cpp +0 -399
  52. package/src/test-runner.cpp +0 -311
  53. package/src/test-suite.cpp +0 -304
@@ -0,0 +1,95 @@
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
+
18
+ /**
19
+ * @file
20
+ * @brief C++ source file with implementations for the µTest++ runner
21
+ * totals methods.
22
+ *
23
+ * @details
24
+ * This source file contains the implementation of the
25
+ * `runner_totals::operator+=` method, which aggregates test result
26
+ * counters from one `runner_totals` instance into another. It
27
+ * accumulates successful checks, failed checks, and executed subtests.
28
+ *
29
+ * All definitions reside within the
30
+ * `micro_os_plus::micro_test_plus` namespace.
31
+ *
32
+ * This file must be included when building the µTest++ library.
33
+ */
34
+
35
+ // ----------------------------------------------------------------------------
36
+
37
+ #if defined(MICRO_OS_PLUS_INCLUDE_CONFIG_H)
38
+ #include <micro-os-plus/config.h>
39
+ #endif // MICRO_OS_PLUS_INCLUDE_CONFIG_H
40
+
41
+ #include <micro-os-plus/micro-test-plus.h>
42
+ #include <micro-os-plus/diag/trace.h>
43
+
44
+ // ----------------------------------------------------------------------------
45
+
46
+ #if defined(__GNUC__)
47
+ #if defined(__clang__)
48
+ #pragma clang diagnostic ignored "-Wc++98-compat"
49
+ #pragma clang diagnostic ignored "-Wpre-c++17-compat"
50
+ #endif
51
+ #endif
52
+
53
+ // ============================================================================
54
+
55
+ namespace micro_os_plus::micro_test_plus
56
+ {
57
+ // ===========================================================================
58
+
59
+ /**
60
+ * @details
61
+ * Adds the successful check count, failed check count, and executed
62
+ * subtest count of @p other to the corresponding members of this
63
+ * instance. Returns a reference to `*this` to support chaining.
64
+ * When tracing is enabled, the updated totals are output for
65
+ * diagnostic purposes.
66
+ */
67
+ runner_totals&
68
+ runner_totals::operator+= (const runner_totals& other) noexcept
69
+ {
70
+ successful_checks_ += other.successful_checks ();
71
+ failed_checks_ += other.failed_checks ();
72
+ executed_subtests_ += other.executed_subtests ();
73
+
74
+ #if defined(MICRO_OS_PLUS_TRACE) \
75
+ && defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
76
+ #if defined(__GNUC__)
77
+ #pragma GCC diagnostic push
78
+ #if defined(__clang__)
79
+ #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
80
+ #endif
81
+ #endif
82
+ trace::printf ("%s -> +%zu -%zu in xs%zu\n", __PRETTY_FUNCTION__,
83
+ successful_checks_, failed_checks_, executed_subtests_);
84
+ #if defined(__GNUC__)
85
+ #pragma GCC diagnostic pop
86
+ #endif
87
+ #endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
88
+
89
+ return *this;
90
+ }
91
+
92
+ // --------------------------------------------------------------------------
93
+ } // namespace micro_os_plus::micro_test_plus
94
+
95
+ // ----------------------------------------------------------------------------
package/src/runner.cpp ADDED
@@ -0,0 +1,563 @@
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
+
18
+ /**
19
+ * @file
20
+ * @brief C++ source file with implementations for the µTest++ test runner
21
+ * methods.
22
+ *
23
+ * @details
24
+ * This source file contains the core implementations for the test runner
25
+ * facilities of the µTest++ framework. It provides the logic for initialising
26
+ * the test environment, registering and managing test suites, handling
27
+ * command-line arguments, orchestrating test execution, and determining the
28
+ * overall test result. The implementation supports automated discovery and
29
+ * execution of test suites, flexible verbosity control, and robust mechanisms
30
+ * for aborting test execution in critical scenarios.
31
+ *
32
+ * All definitions reside within the `micro_os_plus::micro_test_plus`
33
+ * namespace, ensuring clear separation from user code and minimising the risk
34
+ * of naming conflicts.
35
+ *
36
+ * This file must be included when building the µTest++ library.
37
+ */
38
+
39
+ // ----------------------------------------------------------------------------
40
+
41
+ #if defined(MICRO_OS_PLUS_INCLUDE_CONFIG_H)
42
+ #include <micro-os-plus/config.h>
43
+ #endif // MICRO_OS_PLUS_INCLUDE_CONFIG_H
44
+
45
+ #include <micro-os-plus/micro-test-plus.h>
46
+ #include <micro-os-plus/diag/trace.h>
47
+ #include <algorithm>
48
+
49
+ // ----------------------------------------------------------------------------
50
+
51
+ #if defined(__GNUC__)
52
+ #pragma GCC diagnostic ignored "-Waggregate-return"
53
+ #if defined(__clang__)
54
+ #pragma clang diagnostic ignored "-Wc++98-compat"
55
+ #pragma clang diagnostic ignored "-Wc++98-c++11-c++14-compat"
56
+ #pragma clang diagnostic ignored "-Wpre-c++17-compat"
57
+ #endif
58
+ #endif
59
+
60
+ // ============================================================================
61
+
62
+ namespace micro_os_plus::micro_test_plus
63
+ {
64
+ // --------------------------------------------------------------------------
65
+
66
+ /**
67
+ * @details
68
+ * The constructor initialises a new instance of the `test_runner` class,
69
+ * preparing the test runner for managing test suites and cases within the
70
+ * µTest++ framework. If tracing is enabled, it outputs the function
71
+ * signature for diagnostic purposes. This setup ensures the test runner is
72
+ * ready to coordinate the registration, execution, and reporting of tests
73
+ * across all test cases and folders.
74
+ */
75
+ runner::runner (const char* top_suite_name)
76
+ : test_node{ "runner" }, top_suite_{ top_suite_name, *this }
77
+ {
78
+ #if defined(MICRO_OS_PLUS_TRACE) \
79
+ && defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
80
+ #if defined(__GNUC__)
81
+ #pragma GCC diagnostic push
82
+ #if defined(__clang__)
83
+ #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
84
+ #endif
85
+ #endif
86
+ trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name ());
87
+ #if defined(__GNUC__)
88
+ #pragma GCC diagnostic pop
89
+ #endif
90
+ #endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
91
+ }
92
+
93
+ /**
94
+ * @details
95
+ * The `reporter_` unique pointer is released automatically. If tracing
96
+ * is enabled, the function signature is output for diagnostic purposes.
97
+ */
98
+ runner::~runner ()
99
+ {
100
+ #if defined(MICRO_OS_PLUS_TRACE) \
101
+ && defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
102
+ trace::printf ("%s\n", __PRETTY_FUNCTION__);
103
+ #endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
104
+
105
+ // reporter_ is a unique_ptr; destroyed automatically.
106
+ }
107
+
108
+ #if defined(__GNUC__)
109
+ #pragma GCC diagnostic push
110
+ #if defined(__clang__)
111
+ #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
112
+ #endif
113
+ #endif
114
+ /**
115
+ * @details
116
+ * This method initialises the test runner by capturing the command-line
117
+ * arguments and the default test suite name, configuring the framework for
118
+ * subsequent test execution. It parses the arguments to determine the
119
+ * desired verbosity level (normal, verbose, quiet, or silent) and applies
120
+ * this setting to the test reporter. The method also outputs build and
121
+ * environment information when appropriate, aiding diagnostics and
122
+ * transparency. Finally, it creates and registers the default test suite,
123
+ * preparing the framework to manage and execute all test cases and suites
124
+ * across the project’s folders.
125
+ */
126
+ suite&
127
+ runner::initialise (int argc, char* argv[])
128
+ {
129
+ #if defined(MICRO_OS_PLUS_TRACE) \
130
+ && defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
131
+ trace::printf ("%s\n", __PRETTY_FUNCTION__);
132
+ #endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
133
+
134
+ #if !(defined(MICRO_OS_PLUS_INCLUDE_STARTUP) && defined(MICRO_OS_PLUS_TRACE))
135
+ #if defined(MICRO_OS_PLUS_DEBUG)
136
+ trace::printf ("argv[");
137
+ for (int i = 0; i < argc; ++i)
138
+ {
139
+ if (i > 0)
140
+ {
141
+ trace::printf (", ");
142
+ }
143
+ trace::printf ("'%s'", argv[i]);
144
+ }
145
+ trace::puts ("]");
146
+ #endif // defined(MICRO_OS_PLUS_DEBUG)
147
+ #endif // !defined(MICRO_OS_PLUS_INCLUDE_STARTUP)
148
+
149
+ std::vector<std::string_view> argvs (argv, argv + argc);
150
+
151
+ std::string_view reporter_name{ "tap" };
152
+ static constexpr std::string_view reporter_prefix{ "--reporter=" };
153
+ for (size_t i = 0; i < argvs.size (); ++i)
154
+ {
155
+ if (argvs[i].starts_with (reporter_prefix))
156
+ {
157
+ reporter_name = argvs[i].substr (reporter_prefix.size ());
158
+ }
159
+ else if (argvs[i]
160
+ == reporter_prefix.substr (0, reporter_prefix.size () - 1))
161
+ {
162
+ if (i + 1 < argvs.size ())
163
+ {
164
+ reporter_name = argvs[++i];
165
+ }
166
+ else
167
+ {
168
+ fprintf (stderr, "error: --reporter option requires a "
169
+ "reporter name argument\n");
170
+ exit (1);
171
+ }
172
+ }
173
+ }
174
+
175
+ // Initialise and configure the reporter.
176
+ if (reporter_name == "human")
177
+ {
178
+ reporter_ = std::make_unique<reporter_human> (
179
+ std::make_unique<std::vector<std::string_view>> (
180
+ std::move (argvs)));
181
+ }
182
+ else if (reporter_name == "tap")
183
+ {
184
+ reporter_ = std::make_unique<reporter_tap> (
185
+ std::make_unique<std::vector<std::string_view>> (
186
+ std::move (argvs)));
187
+ }
188
+ else
189
+ {
190
+ fprintf (stderr, "error: unknown reporter '%.*s'\n",
191
+ static_cast<int> (reporter_name.size ()),
192
+ reporter_name.data ());
193
+ exit (1);
194
+ }
195
+
196
+ // ------------------------------------------------------------------------
197
+
198
+ timings_.timestamp_begin ();
199
+ reporter_->begin_session (*this);
200
+
201
+ top_suite_.timings ().timestamp_begin ();
202
+ reporter_->begin_suite (top_suite_);
203
+
204
+ return top_suite_;
205
+ }
206
+ #if defined(__GNUC__)
207
+ #pragma GCC diagnostic pop
208
+ #endif
209
+
210
+ // --------------------------------------------------------------------------
211
+
212
+ /**
213
+ * @details
214
+ * Takes ownership of the supplied `suite` unique pointer and appends
215
+ * it to the internal `children_suites_` vector, deferring execution
216
+ * until `run_suites_()` is called. If tracing is enabled, the suite
217
+ * name is logged for diagnostic purposes.
218
+ */
219
+ void
220
+ runner::register_suite_ (std::unique_ptr<class suite> suite)
221
+ {
222
+ #if defined(MICRO_OS_PLUS_TRACE) \
223
+ && defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
224
+ #if defined(__GNUC__)
225
+ #pragma GCC diagnostic push
226
+ #if defined(__clang__)
227
+ #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
228
+ #endif
229
+ #endif
230
+ trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, suite->name ());
231
+ #if defined(__GNUC__)
232
+ #pragma GCC diagnostic pop
233
+ #endif
234
+ #endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
235
+
236
+ children_suites_.push_back (std::move (suite));
237
+ }
238
+
239
+ /**
240
+ * @details
241
+ * Sorts `children_suites_` alphabetically by suite name using a
242
+ * selection sort on `unique_ptr::swap`, avoiding the
243
+ * `-Waggregate-return` diagnostic that `std::sort` would trigger on
244
+ * unique-pointer iterators. Each suite is assigned a 1-based index
245
+ * offset by the top-suite index, executed via `suite::run()`, and its
246
+ * totals are accumulated into the runner totals. The executed-subtest
247
+ * counter is not incremented; suites are not counted as subtests.
248
+ */
249
+ void
250
+ runner::run_suites_ (void)
251
+ {
252
+ // Use selection sort with unique_ptr::swap (returns void) to avoid
253
+ // std::sort triggering -Waggregate-return via std::move_backward,
254
+ // which returns a class-type iterator when operating on unique_ptr
255
+ // elements.
256
+ const size_t n = children_suites_.size ();
257
+ for (size_t i = 0; i < n; ++i)
258
+ {
259
+ size_t min_idx = i;
260
+ for (size_t j = i + 1; j < n; ++j)
261
+ {
262
+ if (std::string_view{ children_suites_[j]->name () }
263
+ < std::string_view{ children_suites_[min_idx]->name () })
264
+ min_idx = j;
265
+ }
266
+ if (min_idx != i)
267
+ children_suites_[i].swap (children_suites_[min_idx]);
268
+ }
269
+
270
+ for (size_t i = 0; i < n; ++i)
271
+ {
272
+ auto* suite_ptr = children_suites_[i].get ();
273
+
274
+ // +1 for 1-based index, +1 for top suite
275
+ suite_ptr->own_index (i + 1 + 1);
276
+
277
+ // Run the child suite immediately.
278
+ suite_ptr->run ();
279
+
280
+ // Accumulate the totals from the static suite into the runner
281
+ // totals.
282
+ // DO NOT increment executed_subtests here.
283
+ totals_ += suite_ptr->totals ();
284
+ }
285
+ }
286
+
287
+ /**
288
+ * @details
289
+ * Finalises the top suite by recording its end timestamp and notifying
290
+ * the reporter, then accumulates its totals into the runner totals.
291
+ * Subsequently invokes `run_suites_()` to sort, execute, and
292
+ * accumulate all registered child suites. Finally, records the session
293
+ * end timestamp, notifies the reporter, and returns `0` if all checks
294
+ * passed or `1` otherwise.
295
+ */
296
+ int
297
+ runner::exit_code (void)
298
+ {
299
+ #if defined(MICRO_OS_PLUS_TRACE) \
300
+ && defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
301
+ trace::printf ("%s\n", __PRETTY_FUNCTION__);
302
+ #endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
303
+
304
+ if (reporter_ == nullptr)
305
+ {
306
+ fprintf (stderr, "error: test runner not initialised\n");
307
+ return 1;
308
+ }
309
+
310
+ top_suite_.timings ().timestamp_end ();
311
+ reporter_->end_suite (top_suite_);
312
+ totals_ += top_suite_.totals ();
313
+
314
+ run_suites_ ();
315
+
316
+ timings_.timestamp_end ();
317
+ reporter_->end_session (*this);
318
+
319
+ const int result = totals_.was_successful () ? 0 : 1;
320
+
321
+ #if defined(MICRO_OS_PLUS_TRACE) \
322
+ && defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
323
+ #if defined(__GNUC__)
324
+ #pragma GCC diagnostic push
325
+ #if defined(__clang__)
326
+ #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
327
+ #endif
328
+ #endif
329
+ trace::printf ("%s -> %d\n", __PRETTY_FUNCTION__, result);
330
+ #if defined(__GNUC__)
331
+ #pragma GCC diagnostic pop
332
+ #endif
333
+ #endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
334
+
335
+ return result;
336
+ }
337
+
338
+ /**
339
+ * @details
340
+ * This method immediately terminates the process by invoking the standard C
341
+ * library `abort()` function. It is used to halt test execution in critical
342
+ * failure scenarios, ensuring that no further tests are run and that the
343
+ * cause of the failure can be promptly investigated. This approach provides
344
+ * a robust mechanism for enforcing strict test outcomes across all test
345
+ * cases and folders.
346
+ */
347
+ void
348
+ runner::abort (const reflection::source_location& sl)
349
+ {
350
+ #if defined(MICRO_OS_PLUS_TRACE) \
351
+ && defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
352
+ trace::printf ("%s\n", __PRETTY_FUNCTION__);
353
+ #endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
354
+
355
+ #if defined(__GNUC__)
356
+ #pragma GCC diagnostic push
357
+ #if defined(__clang__)
358
+ #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
359
+ #endif
360
+ #endif
361
+ fprintf (stderr, "\nerror: test execution aborted at %s:%u\n",
362
+ reflection::short_name (sl.file_name ()), sl.line ());
363
+ #if defined(__GNUC__)
364
+ #pragma GCC diagnostic pop
365
+ #endif
366
+
367
+ ::abort ();
368
+ }
369
+
370
+ /**
371
+ * @details
372
+ * Returns the number of registered child suites plus one, accounting
373
+ * for the top suite.
374
+ */
375
+ size_t
376
+ runner::suites_count (void) const noexcept
377
+ {
378
+ return children_suites_.size () + 1;
379
+ }
380
+
381
+ /**
382
+ * @details
383
+ * For the base `runner`, the total suite count equals `suites_count()`,
384
+ * as there are no additional static suites.
385
+ */
386
+ size_t
387
+ runner::total_suites_count (void) const noexcept
388
+ {
389
+ return suites_count ();
390
+ }
391
+
392
+ // ==========================================================================
393
+
394
+ /**
395
+ * @details
396
+ * Delegates construction to the `runner` base class with the given
397
+ * @p top_suite_name. If tracing is enabled, the function signature
398
+ * and suite name are output for diagnostic purposes.
399
+ */
400
+ static_runner::static_runner (const char* top_suite_name)
401
+ : runner{ top_suite_name }
402
+ {
403
+ #if defined(MICRO_OS_PLUS_TRACE) \
404
+ && defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
405
+ #if defined(__GNUC__)
406
+ #pragma GCC diagnostic push
407
+ #if defined(__clang__)
408
+ #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
409
+ #endif
410
+ #endif
411
+ trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, name ());
412
+ #if defined(__GNUC__)
413
+ #pragma GCC diagnostic pop
414
+ #endif
415
+ #endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
416
+ }
417
+
418
+ /**
419
+ * @details
420
+ * If `static_children_suites_` is non-null, the dynamically allocated
421
+ * vector of raw pointers is deleted and the pointer is reset to
422
+ * `nullptr`. The pointed-to `static_suite` objects are not deleted,
423
+ * as they are static storage-duration objects. If tracing is enabled,
424
+ * the function signature is output for diagnostic purposes.
425
+ */
426
+ static_runner::~static_runner ()
427
+ {
428
+ #if defined(MICRO_OS_PLUS_TRACE) \
429
+ && defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS)
430
+ trace::printf ("%s\n", __PRETTY_FUNCTION__);
431
+ #endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS_CONSTRUCTORS
432
+
433
+ if (static_children_suites_ != nullptr)
434
+ {
435
+ // The tests are static, so we do not delete them, but we need to
436
+ // delete the array of pointers.
437
+ delete static_children_suites_;
438
+ static_children_suites_ = nullptr;
439
+ }
440
+ }
441
+
442
+ /**
443
+ * @details
444
+ * Returns the number of elements in `static_children_suites_`, or
445
+ * zero if the vector has not been allocated yet.
446
+ */
447
+ size_t
448
+ static_runner::static_suites_count (void) const noexcept
449
+ {
450
+ return static_children_suites_ != nullptr
451
+ ? static_children_suites_->size ()
452
+ : 0;
453
+ }
454
+
455
+ /**
456
+ * @details
457
+ * Returns the combined count of dynamically registered suites (from
458
+ * the base `runner`) and statically registered suites.
459
+ */
460
+ size_t
461
+ static_runner::total_suites_count (void) const noexcept
462
+ {
463
+ return suites_count () + static_suites_count ();
464
+ }
465
+
466
+ /**
467
+ * @details
468
+ * First invokes `runner::run_suites_()` to execute all dynamically
469
+ * registered child suites. If `static_children_suites_` is non-null,
470
+ * its contents are sorted alphabetically by suite name using selection
471
+ * sort on raw pointers, each suite is assigned a 1-based index offset
472
+ * by the dynamic suite count, executed via `suite::run()`, and its
473
+ * totals are accumulated into the runner totals.
474
+ */
475
+ void
476
+ static_runner::run_suites_ (void)
477
+ {
478
+ #if defined(MICRO_OS_PLUS_TRACE) \
479
+ && defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
480
+ trace::printf ("%s\n", __PRETTY_FUNCTION__);
481
+ #endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
482
+
483
+ runner::run_suites_ ();
484
+
485
+ if (static_children_suites_ != nullptr)
486
+ {
487
+ // Use selection sort with std::swap on raw pointers (returns void)
488
+ // to avoid std::sort triggering -Waggregate-return via
489
+ // std::move_backward returning a class-type iterator.
490
+ const size_t n = static_children_suites_->size ();
491
+ auto& suites = *static_children_suites_;
492
+ for (size_t i = 0; i < n; ++i)
493
+ {
494
+ size_t min_idx = i;
495
+ for (size_t j = i + 1; j < n; ++j)
496
+ {
497
+ if (std::string_view{ suites[j]->name () }
498
+ < std::string_view{ suites[min_idx]->name () })
499
+ min_idx = j;
500
+ }
501
+ if (min_idx != i)
502
+ std::swap (suites[i], suites[min_idx]);
503
+ }
504
+
505
+ for (size_t i = 0; i < n; ++i)
506
+ {
507
+ auto* suite_ptr = suites[i];
508
+
509
+ suite_ptr->own_index (i + 1 + suites_count ());
510
+
511
+ // Run the child suite immediately.
512
+ suite_ptr->run ();
513
+
514
+ // Accumulate the totals from the static suite into the runner
515
+ // totals.
516
+ // DO NOT increment executed_subtests here.
517
+ totals_ += suite_ptr->totals ();
518
+ }
519
+ }
520
+ }
521
+
522
+ /**
523
+ * @details
524
+ * If `runner.static_children_suites_` is null, a new
525
+ * `std::vector<static_suite*>` is heap-allocated and assigned to it.
526
+ * The address of @p suite is then appended to the vector. This method
527
+ * is intended to be called from the constructor of `static_suite`,
528
+ * before test execution begins.
529
+ */
530
+ void
531
+ static_runner::register_static_suite (static_runner& runner,
532
+ static_suite& suite)
533
+ {
534
+ #if defined(MICRO_OS_PLUS_TRACE) \
535
+ && defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
536
+ #if defined(__GNUC__)
537
+ #pragma GCC diagnostic push
538
+ #if defined(__clang__)
539
+ #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
540
+ #endif
541
+ #endif
542
+ trace::printf ("%s '%s'\n", __PRETTY_FUNCTION__, suite.name ());
543
+ #if defined(__GNUC__)
544
+ #pragma GCC diagnostic pop
545
+ #endif
546
+ #endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
547
+
548
+ if (runner.static_children_suites_ == nullptr)
549
+ {
550
+ #if defined(MICRO_OS_PLUS_TRACE) \
551
+ && defined(MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS)
552
+ trace::printf ("%s new static_children_suites_ array\n",
553
+ __PRETTY_FUNCTION__);
554
+ #endif // MICRO_OS_PLUS_TRACE_MICRO_TEST_PLUS
555
+ runner.static_children_suites_ = new std::vector<static_suite*>;
556
+ }
557
+ runner.static_children_suites_->push_back (&suite);
558
+ }
559
+
560
+ // --------------------------------------------------------------------------
561
+ } // namespace micro_os_plus::micro_test_plus
562
+
563
+ // ----------------------------------------------------------------------------