@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,1069 @@
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++ header file with declarations for the µTest++ test suite.
21
+ *
22
+ * @details
23
+ * This header provides the declarations for the test suite facilities used
24
+ * within the µTest++ framework. It defines the interfaces for constructing,
25
+ * registering, and managing test suites and their associated test cases. The
26
+ * core classes, `test_node` and `suite`, offer mechanisms for
27
+ * tracking test case execution, managing counters for successful and failed
28
+ * checks, and supporting automated registration and discovery of test suites.
29
+ *
30
+ * The design ensures that test suites are non-copyable and non-movable,
31
+ * maintaining unique ownership and consistent state. Flexible support for
32
+ * callable objects enables a wide range of test suite definitions,
33
+ * facilitating expressive and maintainable test organisation across embedded
34
+ * and general C++ projects.
35
+ *
36
+ * All definitions reside within the `micro_os_plus::micro_test_plus`
37
+ * namespace, ensuring clear separation from user code and minimising the risk
38
+ * of naming conflicts.
39
+ *
40
+ * The header files are organised within the
41
+ * `include/micro-os-plus/micro-test-plus` folder to maintain a structured and
42
+ * modular codebase.
43
+ *
44
+ * This file is intended solely for internal use within the framework and
45
+ * should not be included directly by user code.
46
+ */
47
+
48
+ #ifndef MICRO_TEST_PLUS_TEST_H_
49
+ #define MICRO_TEST_PLUS_TEST_H_
50
+
51
+ // ----------------------------------------------------------------------------
52
+
53
+ #ifdef __cplusplus
54
+
55
+ // ----------------------------------------------------------------------------
56
+
57
+ #include "runner-totals.h"
58
+ #include "timings.h"
59
+
60
+ #include <functional>
61
+ #include <memory>
62
+
63
+ // ----------------------------------------------------------------------------
64
+
65
+ #if defined(__GNUC__)
66
+ #pragma GCC diagnostic push
67
+ #pragma GCC diagnostic ignored "-Wpadded"
68
+ #if defined(__clang__)
69
+ #pragma clang diagnostic ignored "-Wc++98-compat"
70
+ #else // GCC only
71
+ #pragma GCC diagnostic ignored "-Wsuggest-final-types"
72
+ #pragma GCC diagnostic ignored "-Wsuggest-final-methods"
73
+ #pragma GCC diagnostic ignored "-Wredundant-tags"
74
+ #endif
75
+ #endif
76
+
77
+ // =============================================================================
78
+
79
+ namespace micro_os_plus::micro_test_plus
80
+ {
81
+ class runner;
82
+ class static_runner;
83
+ class reporter;
84
+ class runner_totals;
85
+ class suite;
86
+
87
+ // --------------------------------------------------------------------------
88
+
89
+ /**
90
+ * @brief Base class for all test suites.
91
+ *
92
+ * @details
93
+ * The `test_node` class provides the foundational interface for
94
+ * managing test suites within the µTest++ framework. It maintains counters
95
+ * for successful and failed checks, tracks test cases, and offers methods
96
+ * for marking the commencement and completion of test cases and suites.
97
+ *
98
+ * This class ensures consistent state management and reporting for all
99
+ * derived test suites. It also provides utility methods for querying the
100
+ * suite's name, the number of successful and failed checks, the number of
101
+ * test cases, and the overall result of the suite.
102
+ *
103
+ * All members and methods are defined within the
104
+ * `micro_os_plus::micro_test_plus` namespace, ensuring clear separation from
105
+ * user code and minimising the risk of naming conflicts.
106
+ *
107
+ * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
108
+ */
109
+ class test_node
110
+ {
111
+ public:
112
+ /**
113
+ * @brief Constructs a test suite.
114
+ *
115
+ * @param [in] name The test suite name.
116
+ *
117
+ * @details
118
+ * The rule of five is enforced to prevent accidental copying or moving.
119
+ */
120
+ test_node (const char* name);
121
+
122
+ /**
123
+ * @brief Deleted copy constructor to prevent copying.
124
+ */
125
+ test_node (const test_node&) = delete;
126
+
127
+ /**
128
+ * @brief Deleted move constructor to prevent moving.
129
+ */
130
+ test_node (test_node&&) = delete;
131
+
132
+ /**
133
+ * @brief Deleted copy assignment operator to prevent copying.
134
+ */
135
+ test_node&
136
+ operator= (const test_node&) = delete;
137
+
138
+ /**
139
+ * @brief Deleted move assignment operator to prevent moving.
140
+ */
141
+ test_node&
142
+ operator= (test_node&&) = delete;
143
+
144
+ /**
145
+ * @brief Virtual destructor for the test_node class.
146
+ */
147
+ virtual ~test_node ();
148
+
149
+ // ------------------------------------------------------------------------
150
+
151
+ /**
152
+ * @brief Gets the suite name.
153
+ *
154
+ * @par Parameters
155
+ * None.
156
+ * @return A pointer to the null-terminated test suite name.
157
+ */
158
+ [[nodiscard]] const char*
159
+ name (void) const noexcept
160
+ {
161
+ return name_;
162
+ }
163
+
164
+ public:
165
+ /**
166
+ * @brief Gets the totals for the test suite.
167
+ *
168
+ * @par Parameters
169
+ * None.
170
+ * @return A reference to the runner_totals instance.
171
+ */
172
+ [[nodiscard]] runner_totals&
173
+ totals () noexcept
174
+ {
175
+ return totals_;
176
+ }
177
+
178
+ /**
179
+ * @brief Gets the totals for the test suite (const overload).
180
+ *
181
+ * @par Parameters
182
+ * None.
183
+ * @return A const reference to the runner_totals instance.
184
+ */
185
+ [[nodiscard]] const runner_totals&
186
+ totals () const noexcept
187
+ {
188
+ return totals_;
189
+ }
190
+
191
+ protected:
192
+ /**
193
+ * @brief The test suite name.
194
+ *
195
+ * @note Derived classes may access this member directly in
196
+ * addition to the public `name()` getter.
197
+ */
198
+ const char* name_;
199
+
200
+ /**
201
+ * @brief Totals for the test suite, including nested cases.
202
+ */
203
+ runner_totals totals_;
204
+ };
205
+
206
+ // ==========================================================================
207
+
208
+ /**
209
+ * @brief Non-template base for all runnable objects (suites and subtests).
210
+ *
211
+ * @details
212
+ * `runnable_base` extends `test_node` with the state that is shared by
213
+ * every runnable object but does not depend on the CRTP self-type:
214
+ * - a reference to the owning `runner`,
215
+ * - the object's own index within its parent container,
216
+ * - a sequential subtest index used when creating nested subtests, and
217
+ * - an owning vector of child `subtest` instances.
218
+ *
219
+ * Concrete runnable classes (`suite`, `subtest`) derive from
220
+ * `runnable<Self_T>` which in turn derives from `runnable_base`.
221
+ *
222
+ * The class is non-copyable and non-movable to preserve unique ownership
223
+ * and consistent state throughout the test session.
224
+ *
225
+ * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
226
+ */
227
+ class runnable_base : public test_node
228
+ {
229
+ public:
230
+ /**
231
+ * @brief Constructs a `runnable_base` with a name, runner, and index.
232
+ *
233
+ * @param name The name used in reports.
234
+ * @param runner The test runner managing this object.
235
+ * @param own_index The positional index of this object within its parent.
236
+ */
237
+ runnable_base (const char* name, runner& runner, size_t own_index);
238
+
239
+ /**
240
+ * @brief Deleted copy constructor to prevent copying.
241
+ */
242
+ runnable_base (const runnable_base&) = delete;
243
+
244
+ /**
245
+ * @brief Deleted move constructor to prevent moving.
246
+ */
247
+ runnable_base (runnable_base&&) = delete;
248
+
249
+ /**
250
+ * @brief Deleted copy assignment operator to prevent copying.
251
+ */
252
+ runnable_base&
253
+ operator= (const runnable_base&) = delete;
254
+
255
+ /**
256
+ * @brief Deleted move assignment operator to prevent moving.
257
+ */
258
+ runnable_base&
259
+ operator= (runnable_base&&) = delete;
260
+
261
+ /**
262
+ * @brief Virtual destructor.
263
+ */
264
+ virtual ~runnable_base () override;
265
+
266
+ // ------------------------------------------------------------------------
267
+
268
+ /**
269
+ * @brief Returns the positional index of this object within its parent.
270
+ *
271
+ * @par Parameters
272
+ * None.
273
+ * @return The one-based own index.
274
+ */
275
+ [[nodiscard]] size_t
276
+ own_index () const noexcept
277
+ {
278
+ return own_index_;
279
+ }
280
+
281
+ /**
282
+ * @brief Sets the positional index of this object within its parent.
283
+ *
284
+ * @note This overload follows the same-name getter/setter pattern
285
+ * used throughout the framework: the getter is the `const` overload
286
+ * and the setter is the non-`const` single-argument overload.
287
+ *
288
+ * @param index The new index value.
289
+ * @par Returns
290
+ * Nothing.
291
+ */
292
+ void
293
+ own_index (size_t index) noexcept
294
+ {
295
+ own_index_ = index;
296
+ }
297
+
298
+ /**
299
+ * @brief Returns the index of the most recently created child subtest.
300
+ *
301
+ * @par Parameters
302
+ * None.
303
+ * @return The current child subtest sequential index.
304
+ */
305
+ [[nodiscard]] size_t
306
+ current_subtest_index () const noexcept
307
+ {
308
+ return current_subtest_index_;
309
+ }
310
+
311
+ /**
312
+ * @brief Increments and returns the child subtest sequential index.
313
+ *
314
+ * @details
315
+ * Each call to `test()` invokes this method before constructing the new
316
+ * `subtest`, so the index values form a strictly increasing, one-based
317
+ * sequence.
318
+ *
319
+ * @par Parameters
320
+ * None.
321
+ * @return The new index value after incrementing.
322
+ */
323
+ size_t
324
+ increment_subtest_index () noexcept
325
+ {
326
+ return ++current_subtest_index_;
327
+ }
328
+
329
+ /**
330
+ * @brief Returns the number of direct child subtests owned by this node.
331
+ *
332
+ * @par Parameters
333
+ * None.
334
+ * @return The number of child subtests.
335
+ */
336
+ [[nodiscard]] size_t
337
+ children_subtests_count (void) const noexcept
338
+ {
339
+ return children_subtests_.size ();
340
+ }
341
+
342
+ /**
343
+ * @brief Gets the test reporter associated with this test suite.
344
+ *
345
+ * @par Parameters
346
+ * None.
347
+ * @return A reference to the test reporter.
348
+ */
349
+ [[nodiscard]] class reporter&
350
+ reporter (void) const noexcept;
351
+
352
+ /**
353
+ * @brief Aborts test execution via the owning runner.
354
+ *
355
+ * @param sl The source location from which the abort is triggered.
356
+ * @par Returns
357
+ * Does not return.
358
+ */
359
+ [[noreturn]] void
360
+ abort (const reflection::source_location& sl
361
+ = reflection::source_location::current ());
362
+
363
+ /**
364
+ * @brief Gets the test runner associated with this test suite.
365
+ *
366
+ * @par Parameters
367
+ * None.
368
+ * @return A reference to the test runner.
369
+ */
370
+ [[nodiscard]] class runner&
371
+ runner (void) const noexcept
372
+ {
373
+ return runner_;
374
+ }
375
+
376
+ protected:
377
+ /**
378
+ * @brief Registers a newly constructed child subtest and executes it
379
+ * immediately.
380
+ *
381
+ * @param child_test Owning pointer to the newly created `subtest`.
382
+ * @param suite The parent `suite` to which execution results are reported.
383
+ * @par Returns
384
+ * Nothing.
385
+ */
386
+ void
387
+ after_subtest_create_ (std::unique_ptr<class subtest> child_test,
388
+ suite& suite);
389
+
390
+ protected:
391
+ /**
392
+ * @brief Reference to the test runner that owns this object.
393
+ */
394
+ class runner& runner_;
395
+
396
+ /**
397
+ * @brief The test suite index, counting from 1.
398
+ */
399
+ size_t own_index_;
400
+
401
+ /**
402
+ * @brief The subtest index, counting from 1.
403
+ *
404
+ * @details
405
+ * This index is used for reporting and tracking the execution order of
406
+ * subtests within a suite, especially when nested subtests are
407
+ * involved. It is incremented for each subtest created, allowing for
408
+ * clear identification of subtests in reports and diagnostics.
409
+ */
410
+ size_t current_subtest_index_ = 0;
411
+
412
+ /**
413
+ * @brief Owning collection of direct child subtests.
414
+ *
415
+ * @details
416
+ * Each call to `test()` appends a new `subtest` to this vector and
417
+ * runs it immediately. The vector retains ownership for the lifetime of
418
+ * the parent runnable.
419
+ */
420
+ std::vector<std::unique_ptr<subtest>> children_subtests_;
421
+ };
422
+
423
+ // ==========================================================================
424
+
425
+ /**
426
+ * @brief CRTP base class factoring out callable storage, rule-of-five, and
427
+ * `run()` logic shared by `test` and `static_suite`.
428
+ *
429
+ * @tparam Self_T The concrete derived class type (CRTP pattern). The stored
430
+ * callable receives a `Self_T&` reference when the suite is executed.
431
+ *
432
+ * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
433
+ */
434
+ template <typename Self_T>
435
+ class runnable : public runnable_base
436
+ {
437
+ public:
438
+ /**
439
+ * @brief Class template constructor.
440
+ *
441
+ * @tparam Callable_T The callable type.
442
+ * @tparam Args_T The additional argument types.
443
+ *
444
+ * @param [in] name The test suite name, used in reports.
445
+ * @param [in] runner The test runner managing this suite.
446
+ * @param [in] own_index The suite index within the runner.
447
+ * @param [in] callable The callable invoked when the suite runs.
448
+ * @param [in] arguments Additional arguments forwarded to the callable
449
+ * after the leading `Self_T&` reference.
450
+ *
451
+ * @details
452
+ * The rule of five is enforced to prevent accidental copying or moving.
453
+ */
454
+ template <typename Callable_T, typename... Args_T>
455
+ runnable (const char* name, class runner& runner, size_t own_index,
456
+ Callable_T&& callable, Args_T&&... arguments);
457
+
458
+ /**
459
+ * @brief Deleted copy constructor to prevent copying.
460
+ */
461
+ runnable (const runnable&) = delete;
462
+
463
+ /**
464
+ * @brief Deleted move constructor to prevent moving.
465
+ */
466
+ runnable (runnable&&) = delete;
467
+
468
+ /**
469
+ * @brief Deleted copy assignment operator to prevent copying.
470
+ */
471
+ runnable&
472
+ operator= (const runnable&) = delete;
473
+
474
+ /**
475
+ * @brief Deleted move assignment operator to prevent moving.
476
+ */
477
+ runnable&
478
+ operator= (runnable&&) = delete;
479
+
480
+ /**
481
+ * @brief Virtual destructor.
482
+ */
483
+ virtual ~runnable () override;
484
+
485
+ // ------------------------------------------------------------------------
486
+
487
+ /**
488
+ * @brief Runs the test function by invoking the stored callable with the
489
+ * derived self instance.
490
+ *
491
+ * @par Parameters
492
+ * None.
493
+ * @par Returns
494
+ * Nothing.
495
+ */
496
+ virtual void
497
+ run (void) = 0;
498
+
499
+ protected:
500
+ /**
501
+ * @brief Callable storing the test suite body and any bound arguments.
502
+ * Invoked with a reference to the derived `Self_T` instance.
503
+ */
504
+ std::function<void (Self_T&)> callable_;
505
+ };
506
+
507
+ // ==========================================================================
508
+
509
+ /**
510
+ * @ingroup micro-test-plus-test-case
511
+ * @brief A named, runnable test case that lives inside a `suite`.
512
+ *
513
+ * @details
514
+ * `subtest` represents a single, named test case or a nested group of
515
+ * checks within a parent `suite`. It is constructed by calling
516
+ * `suite::test()` or `subtest::test()`, both of which create the object,
517
+ * immediately execute its callable body via `run()`, and register the
518
+ * result with the parent suite.
519
+ *
520
+ * The body of the subtest is supplied as a callable (typically a lambda)
521
+ * that receives a `subtest&` reference as its first argument. Inside the
522
+ * body, `expect()` and `assume()` are used to evaluate conditions and
523
+ * record the results. Subtests may be nested to an arbitrary depth.
524
+ *
525
+ * The class is non-copyable and non-movable to preserve unique ownership
526
+ * and consistent state throughout the test session.
527
+ *
528
+ * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
529
+ */
530
+ class subtest : public runnable<subtest>
531
+ {
532
+ public:
533
+ /**
534
+ * @brief Constructs a subtest with a name, runner, parent suite, index,
535
+ * nesting depth, and callable.
536
+ *
537
+ * @tparam Callable_T The type of a callable object.
538
+ * @tparam Args_T The types of the callable arguments.
539
+ *
540
+ * @param [in] name The subtest name or description, used in reports.
541
+ * @param [in] runner The test runner managing this subtest.
542
+ * @param [in] parent_suite The suite that owns this subtest.
543
+ * @param [in] own_index The one-based positional index within the parent.
544
+ * @param [in] nesting_depth The depth of nesting; 1 for top-level
545
+ * subtests.
546
+ * @param [in] callable A generic callable object, usually a lambda,
547
+ * invoked when the subtest executes.
548
+ * @param [in] arguments A possibly empty list of arguments forwarded to
549
+ * the callable after the leading `subtest&` reference.
550
+ *
551
+ * @details
552
+ * The rule of five is enforced to prevent accidental copying or moving.
553
+ */
554
+ template <typename Callable_T, typename... Args_T>
555
+ subtest (const char* name, class runner& runner, suite& parent_suite,
556
+ size_t own_index, size_t nesting_depth, Callable_T&& callable,
557
+ Args_T&&... arguments);
558
+
559
+ /**
560
+ * @brief Deleted copy constructor to prevent copying.
561
+ */
562
+ subtest (const subtest&) = delete;
563
+
564
+ /**
565
+ * @brief Deleted move constructor to prevent moving.
566
+ */
567
+ subtest (subtest&&) = delete;
568
+
569
+ /**
570
+ * @brief Deleted copy assignment operator to prevent copying.
571
+ */
572
+ subtest&
573
+ operator= (const subtest&) = delete;
574
+
575
+ /**
576
+ * @brief Deleted move assignment operator to prevent moving.
577
+ */
578
+ subtest&
579
+ operator= (subtest&&) = delete;
580
+
581
+ /**
582
+ * @brief Virtual destructor.
583
+ */
584
+ virtual ~subtest () override;
585
+
586
+ // ------------------------------------------------------------------------
587
+
588
+ /**
589
+ * @brief Adds a test case to the suite.
590
+ *
591
+ * @tparam Callable_T The type of a callable object.
592
+ * @tparam Args_T The types of the callable arguments.
593
+ *
594
+ * @param [in] name The test case name or description, used in reports.
595
+ * @param [in] callable A generic callable object, usually a lambda,
596
+ * invoked to perform the test.
597
+ * @param [in] arguments A possibly empty list of arguments to be passed to
598
+ * the callable.
599
+ */
600
+ template <typename Callable_T, typename... Args_T>
601
+ void
602
+ test (const char* name, Callable_T&& callable, Args_T&&... arguments);
603
+
604
+ // ------------------------------------------------------------------------
605
+
606
+ /**
607
+ * @ingroup micro-test-plus-expectations
608
+ * @brief Evaluate a generic condition and report the results.
609
+ *
610
+ * @tparam Expr_T The type of the custom expression.
611
+ *
612
+ * @par Constraints
613
+ * Enabled only if `Expr_T` is derived from `detail::op` or
614
+ * is convertible to `bool` (enforced via a C++20 `requires` clause).
615
+ *
616
+ * @param [in] expr Logical expression to evaluate.
617
+ * @param [in] sl Optional source location, defaulting to the current line.
618
+ * @return An output stream to write optional messages.
619
+ *
620
+ * @details
621
+ * The `expect` function template evaluates a logical condition or custom
622
+ * expression and reports the result within the µTest++ framework. It is
623
+ * designed to provide detailed diagnostics for test failures, including
624
+ * the actual and expected values, when using the provided comparators
625
+ * (`eq()`, `ne()`, `lt()`, `le()`, `gt()`, `ge()`) or custom operators.
626
+ *
627
+ * The function template can be used with any expression that evaluates to
628
+ * a boolean or with custom comparators/operators derived from the local
629
+ * `detail::op` type. For complex checks performed outside the `expect()`
630
+ * logical expression (such as within `if` or `try`/`catch` statements),
631
+ * the result can be reported by calling `expect(true)` or `expect(false)`.
632
+ *
633
+ * The function returns an output stream, allowing optional messages to be
634
+ * appended to the test report.
635
+ *
636
+ * **Example**
637
+ *
638
+ * @code{.cpp}
639
+ * namespace mt = micro_os_plus::micro_test_plus;
640
+ *
641
+ * t.expect(compute_answer() == 42) << "answer is 42";
642
+ * @endcode
643
+ */
644
+ template <class Expr_T>
645
+ requires type_traits::checkable<Expr_T>
646
+ auto
647
+ expect (const Expr_T& expr, const reflection::source_location& sl
648
+ = reflection::source_location::current ())
649
+ {
650
+ return detail::deferred_reporter<Expr_T>{ expr, false, sl, *this };
651
+ }
652
+
653
+ /**
654
+ * @ingroup micro-test-plus-assumptions
655
+ * @brief Check a condition and, if false, abort test execution.
656
+ *
657
+ * @tparam Expr_T The type of the custom expression.
658
+ *
659
+ * @par Constraints
660
+ * Enabled only if `Expr_T` is derived from `detail::op` or
661
+ * is convertible to `bool` (enforced via a C++20 `requires` clause).
662
+ *
663
+ * @param [in] expr Logical expression to evaluate.
664
+ * @param [in] sl Optional source location, defaulting to the current line.
665
+ * @return An output stream to write optional messages.
666
+ *
667
+ * @details
668
+ * The `assume` function template evaluates a logical condition or custom
669
+ * expression and reports the result within the µTest++ framework. It is
670
+ * designed to provide detailed diagnostics for test failures, including
671
+ * the actual and expected values, when using the provided comparators
672
+ * (`eq()`, `ne()`, `lt()`, `le()`, `gt()`, `ge()`) or custom operators.
673
+ *
674
+ * The function template can be used with any expression that evaluates to
675
+ * a boolean or with custom comparators/operators derived from the local
676
+ * `detail::op` type. For complex checks performed outside the `expect()`
677
+ * logical expression (such as within `if` or `try`/`catch` statements),
678
+ * the result can be reported by calling `expect(true)` or `expect(false)`.
679
+ *
680
+ * The function returns an output stream, allowing optional messages to be
681
+ * appended to the test report.
682
+ *
683
+ * **Example**
684
+ *
685
+ * @code{.cpp}
686
+ * namespace mt = micro_os_plus::micro_test_plus;
687
+ * mt::assume(compute_answer() == 42) << "answer is 42";
688
+ * @endcode
689
+ */
690
+ template <class Expr_T>
691
+ requires type_traits::checkable<Expr_T>
692
+ auto
693
+ assume (const Expr_T& expr, const reflection::source_location& sl
694
+ = reflection::source_location::current ())
695
+ {
696
+ return detail::deferred_reporter<Expr_T>{ expr, true, sl, *this };
697
+ }
698
+
699
+ // ------------------------------------------------------------------------
700
+
701
+ /**
702
+ * @brief Executes the subtest body by invoking the stored callable.
703
+ *
704
+ * @details
705
+ * Calls `begin_subtest()` on the reporter, invokes `callable_(*this)`,
706
+ * then calls `end_subtest()`. The results are propagated to the parent
707
+ * suite's totals.
708
+ *
709
+ * @par Parameters
710
+ * None.
711
+ * @par Returns
712
+ * Nothing.
713
+ */
714
+ virtual void
715
+ run (void) override;
716
+
717
+ /**
718
+ * @brief Returns the nesting depth of this subtest.
719
+ *
720
+ * @details
721
+ * Top-level subtests (direct children of a `suite`) have depth 1.
722
+ * Each additional level of nesting increments the depth by 1.
723
+ *
724
+ * @par Parameters
725
+ * None.
726
+ * @return The nesting depth (1 = top-level).
727
+ */
728
+ [[nodiscard]] size_t
729
+ nesting_depth () const noexcept
730
+ {
731
+ return nesting_depth_;
732
+ }
733
+
734
+ protected:
735
+ /**
736
+ * @brief Reference to the parent suite that owns this subtest.
737
+ */
738
+ suite& parent_suite_;
739
+
740
+ /**
741
+ * @brief The nesting depth of this subtest within the suite.
742
+ */
743
+ size_t nesting_depth_;
744
+ };
745
+
746
+ // ==========================================================================
747
+
748
+ /**
749
+ * @ingroup micro-test-plus-test-suites
750
+ * @brief A named, runnable test suite registered with the test runner.
751
+ *
752
+ * @details
753
+ * `suite` represents a top-level named group of related test cases within
754
+ * the µTest++ framework. It is created by calling `runner::suite()`, which
755
+ * constructs the object, stores it in the runner's collection, and runs it
756
+ * immediately. Each suite records its own timing information and propagates
757
+ * its results to the owning `runner`.
758
+ *
759
+ * The body of a suite is supplied as a callable (typically a lambda) that
760
+ * receives a `suite&` reference as its first argument. Inside the body,
761
+ * `suite::test()` is called to create and run individual subtests.
762
+ *
763
+ * The class is non-copyable and non-movable to preserve unique ownership
764
+ * and consistent state throughout the test session.
765
+ *
766
+ * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
767
+ */
768
+ class suite : public runnable<suite>
769
+ {
770
+ public:
771
+ /**
772
+ * @brief Constructs a suite with a name, runner, and callable body.
773
+ *
774
+ * @tparam Callable_T The type of the callable object.
775
+ * @tparam Args_T The types of any additional callable arguments.
776
+ *
777
+ * @param [in] name The suite name or description, used in reports.
778
+ * @param [in] runner The test runner managing this suite.
779
+ * @param [in] callable A generic callable object, usually a lambda,
780
+ * invoked when the suite executes. Its first parameter must be
781
+ * `suite&`.
782
+ * @param [in] arguments A possibly empty list of arguments forwarded to
783
+ * the callable after the leading `suite&` reference.
784
+ *
785
+ * @details
786
+ * The rule of five is enforced to prevent accidental copying or moving.
787
+ */
788
+ template <typename Callable_T, typename... Args_T>
789
+ suite (const char* name, class runner& runner, Callable_T&& callable,
790
+ Args_T&&... arguments);
791
+
792
+ /**
793
+ * @brief Deleted copy constructor to prevent copying.
794
+ */
795
+ suite (const suite&) = delete;
796
+
797
+ /**
798
+ * @brief Deleted move constructor to prevent moving.
799
+ */
800
+ suite (suite&&) = delete;
801
+
802
+ /**
803
+ * @brief Deleted copy assignment operator to prevent copying.
804
+ */
805
+ suite&
806
+ operator= (const suite&) = delete;
807
+
808
+ /**
809
+ * @brief Deleted move assignment operator to prevent moving.
810
+ */
811
+ suite&
812
+ operator= (suite&&) = delete;
813
+
814
+ /**
815
+ * @brief Virtual destructor.
816
+ */
817
+ virtual ~suite () override;
818
+
819
+ // ------------------------------------------------------------------------
820
+
821
+ /**
822
+ * @brief Adds a test case to the suite.
823
+ *
824
+ * @tparam Callable_T The type of a callable object.
825
+ * @tparam Args_T The types of the callable arguments.
826
+ *
827
+ * @param [in] name The test case name or description, used in reports.
828
+ * @param [in] callable A generic callable object, usually a lambda,
829
+ * invoked to perform the test.
830
+ * @param [in] arguments A possibly empty list of arguments to be passed to
831
+ * the callable.
832
+ */
833
+ template <typename Callable_T, typename... Args_T>
834
+ void
835
+ test (const char* name, Callable_T&& callable, Args_T&&... arguments);
836
+
837
+ // ------------------------------------------------------------------------
838
+
839
+ /**
840
+ * @brief Gets the timings for this suite.
841
+ *
842
+ * @par Parameters
843
+ * None.
844
+ * @return A reference to the timestamps instance.
845
+ */
846
+ [[nodiscard]] timestamps&
847
+ timings () noexcept
848
+ {
849
+ return timings_;
850
+ }
851
+
852
+ /**
853
+ * @brief Gets the timings for this suite (const overload).
854
+ *
855
+ * @par Parameters
856
+ * None.
857
+ * @return A const reference to the timestamps instance.
858
+ */
859
+ [[nodiscard]] const timestamps&
860
+ timings () const noexcept
861
+ {
862
+ return timings_;
863
+ }
864
+
865
+ /**
866
+ * @brief Executes the suite body by invoking the stored callable.
867
+ *
868
+ * @details
869
+ * Calls `begin_suite()` on the reporter, records timing, invokes
870
+ * `callable_(*this)`, records end timing, and calls `end_suite()`. The
871
+ * results are propagated to the owning `runner`'s totals.
872
+ *
873
+ * @par Parameters
874
+ * None.
875
+ * @par Returns
876
+ * Nothing.
877
+ */
878
+ virtual void
879
+ run (void) override;
880
+
881
+ protected:
882
+ /**
883
+ * @brief Timing measurements for this suite's execution.
884
+ */
885
+ timestamps timings_;
886
+ };
887
+
888
+ // ==========================================================================
889
+
890
+ /**
891
+ * @brief The implicit top-level suite owned by every `runner` instance.
892
+ *
893
+ * @details
894
+ * `top_suite` is a thin specialisation of `suite` used as the implicit
895
+ * root context for the `runner`. It is created by the `runner` constructor
896
+ * and is available to user code via `runner::initialise()`, which returns
897
+ * a reference to it. Unlike regular `suite` objects, `top_suite` is not
898
+ * stored in the runner's child-suite vector; instead it is a direct member
899
+ * of `runner`.
900
+ *
901
+ * Users do not normally construct `top_suite` directly.
902
+ *
903
+ * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
904
+ */
905
+ class top_suite : public suite
906
+ {
907
+ public:
908
+ /**
909
+ * @brief Constructs the top-level suite with a name and runner reference.
910
+ *
911
+ * @param name The suite name used in reports.
912
+ * @param runner The test runner that owns this suite.
913
+ */
914
+ top_suite (const char* name, class runner& runner);
915
+
916
+ /**
917
+ * @brief Deleted copy constructor to prevent copying.
918
+ */
919
+ top_suite (const top_suite&) = delete;
920
+
921
+ /**
922
+ * @brief Deleted move constructor to prevent moving.
923
+ */
924
+ top_suite (top_suite&&) = delete;
925
+
926
+ /**
927
+ * @brief Deleted copy assignment operator to prevent copying.
928
+ */
929
+ top_suite&
930
+ operator= (const top_suite&) = delete;
931
+
932
+ /**
933
+ * @brief Deleted move assignment operator to prevent moving.
934
+ */
935
+ top_suite&
936
+ operator= (top_suite&&) = delete;
937
+
938
+ /**
939
+ * @brief Virtual destructor.
940
+ */
941
+ virtual ~top_suite () override;
942
+ };
943
+
944
+ // ==========================================================================
945
+
946
+ /**
947
+ * @ingroup micro-test-plus-test-suites
948
+ * @brief A test suite designed for static (namespace-scope) registration
949
+ * with a `static_runner`.
950
+ *
951
+ * @details
952
+ * `static_suite` extends `suite` to support the pattern where test suites
953
+ * are declared as namespace-scope objects and therefore constructed before
954
+ * or after the `static_runner` instance, in unspecified
955
+ * static-initialisation order.
956
+ *
957
+ * Upon construction, the suite automatically registers itself with the
958
+ * supplied `static_runner` by calling
959
+ * `static_runner::register_suite_()`. The runner defers execution of all
960
+ * registered static suites until `static_runner::run_suites_()` is invoked,
961
+ * which typically happens inside the implicit `main()` provided by the
962
+ * framework.
963
+ *
964
+ * In addition to the standard callable body inherited from `suite`, a
965
+ * `static_suite` may carry a second, statically-registered callable stored
966
+ * in `static_callable_`. The overridden `run()` method invokes both bodies
967
+ * in sequence, allowing the suite to integrate both dynamic and static
968
+ * registration patterns.
969
+ *
970
+ * The class is non-copyable and non-movable to preserve unique ownership
971
+ * and consistent state throughout the test session.
972
+ *
973
+ * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
974
+ */
975
+ class static_suite : public suite
976
+ {
977
+ public:
978
+ /**
979
+ * @brief Class template constructor for static_suite.
980
+ *
981
+ * @tparam Callable_T The type of a callable object.
982
+ * @tparam Args_T The types of the callable arguments.
983
+ *
984
+ * @param [in] name The test suite name or description, used in reports.
985
+ * @param [in] runner The static test runner managing this suite.
986
+ * @param [in] callable A generic callable object, usually a lambda or
987
+ * function, invoked to perform the test suite.
988
+ * @param [in] arguments A possibly empty list of arguments to be passed to
989
+ * the callable.
990
+ *
991
+ * @details
992
+ * The rule of five is enforced to prevent accidental copying or moving.
993
+ * Upon construction, the suite is automatically registered with the
994
+ * runner.
995
+ */
996
+ template <typename Callable_T, typename... Args_T>
997
+ static_suite (const char* name, static_runner& runner,
998
+ Callable_T&& callable, Args_T&&... arguments);
999
+
1000
+ /**
1001
+ * @brief Deleted copy constructor to prevent copying.
1002
+ */
1003
+ static_suite (const static_suite&) = delete;
1004
+
1005
+ /**
1006
+ * @brief Deleted move constructor to prevent moving.
1007
+ */
1008
+ static_suite (static_suite&&) = delete;
1009
+
1010
+ /**
1011
+ * @brief Deleted copy assignment operator to prevent copying.
1012
+ */
1013
+ static_suite&
1014
+ operator= (const static_suite&) = delete;
1015
+
1016
+ /**
1017
+ * @brief Deleted move assignment operator to prevent moving.
1018
+ */
1019
+ static_suite&
1020
+ operator= (static_suite&&) = delete;
1021
+
1022
+ /**
1023
+ * @brief Virtual destructor.
1024
+ */
1025
+ virtual ~static_suite () override;
1026
+
1027
+ // ------------------------------------------------------------------------
1028
+
1029
+ /**
1030
+ * @brief Executes the static suite body using the stored static callable.
1031
+ *
1032
+ * @details
1033
+ * Calls the base `suite::run()` implementation for the dynamically
1034
+ * registered callable, then additionally invokes `static_callable_(*this)`
1035
+ * if it is set. This allows `static_suite` objects to carry two separate
1036
+ * bodies: a standard one and a statically-registered one.
1037
+ *
1038
+ * @par Parameters
1039
+ * None.
1040
+ * @par Returns
1041
+ * Nothing.
1042
+ */
1043
+ virtual void
1044
+ run (void) override;
1045
+
1046
+ protected:
1047
+ /**
1048
+ * @brief Callable storing the static suite body and any bound arguments.
1049
+ * Invoked with a reference to the concrete `static_suite` instance.
1050
+ */
1051
+ std::function<void (static_suite&)> static_callable_;
1052
+ };
1053
+
1054
+ // --------------------------------------------------------------------------
1055
+ } // namespace micro_os_plus::micro_test_plus
1056
+
1057
+ #if defined(__GNUC__)
1058
+ #pragma GCC diagnostic pop
1059
+ #endif
1060
+
1061
+ // ----------------------------------------------------------------------------
1062
+
1063
+ #endif // __cplusplus
1064
+
1065
+ // ----------------------------------------------------------------------------
1066
+
1067
+ #endif // MICRO_TEST_PLUS_TEST_H_
1068
+
1069
+ // ----------------------------------------------------------------------------