@micro-os-plus/micro-test-plus 3.3.1 → 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 +330 -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
@@ -55,6 +55,8 @@
55
55
  // ----------------------------------------------------------------------------
56
56
 
57
57
  #include "math.h"
58
+ #include <string_view>
59
+ #include <type_traits>
58
60
 
59
61
  // ----------------------------------------------------------------------------
60
62
 
@@ -66,6 +68,8 @@
66
68
  #endif
67
69
  #endif
68
70
 
71
+ // ============================================================================
72
+
69
73
  namespace micro_os_plus::micro_test_plus
70
74
  {
71
75
  // --------------------------------------------------------------------------
@@ -83,7 +87,7 @@ namespace micro_os_plus::micro_test_plus
83
87
  * This includes templates for function traits, type lists, identity, value
84
88
  * wrappers, and compile-time checks for container types, floating point
85
89
  * types, and type convertibility. It also provides generic integral and
86
- * floating point constant wrappers, as well as mechanisms for SFINAE and
90
+ * floating point constant wrappers, as well as C++20 concepts and
87
91
  * requirements checking.
88
92
  *
89
93
  * These utilities facilitate advanced template programming, type deduction,
@@ -123,7 +127,10 @@ namespace micro_os_plus::micro_test_plus
123
127
  * @brief Struct template for compile-time type identity.
124
128
  *
125
129
  * @tparam T The type to be preserved.
126
- * @tparam Extra Additional template parameters, ignored.
130
+ * @tparam Extra Additional template parameters, ignored. The variadic
131
+ * `Extra` parameter pack absorbs additional type arguments that may
132
+ * arise during template argument deduction in some metaprogramming
133
+ * contexts, preventing substitution failures.
127
134
  *
128
135
  * @details
129
136
  * The `identity` struct template provides a mechanism for preserving a
@@ -132,8 +139,8 @@ namespace micro_os_plus::micro_test_plus
132
139
  * within the µTest++ framework.
133
140
  *
134
141
  * This utility is particularly useful in scenarios where type deduction or
135
- * SFINAE is required, as it allows the type to be carried through template
136
- * specialisations without modification.
142
+ * concept constraints are required, as it allows the type to be carried
143
+ * through template specialisations without modification.
137
144
  *
138
145
  * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
139
146
  */
@@ -314,369 +321,240 @@ namespace micro_os_plus::micro_test_plus
314
321
  using args = list<Args_T...>;
315
322
  };
316
323
 
317
- /**
318
- * @brief Utility function template to simulate std::declval for type
319
- * deduction.
320
- *
321
- * @tparam T The type for which an rvalue reference is required.
322
- *
323
- * @par Parameters
324
- * None.
325
- * @return An rvalue reference to type `T`.
326
- *
327
- * @details
328
- * The `declval` function template provides a mechanism for obtaining an
329
- * rvalue reference to a type `T` without requiring an actual object. This
330
- * is primarily used in unevaluated contexts, such as within `decltype`, to
331
- * deduce types during template metaprogramming in the µTest++ framework.
332
- */
333
- template <class T>
334
- T&&
335
- declval (void);
336
- template <class... Ts, class Expr_T>
337
- constexpr auto
338
- is_valid (Expr_T expr) -> decltype (expr (declval<Ts...> ()), bool ())
339
- {
340
- return true;
341
- }
324
+ // ------------------------------------------------------------------------
342
325
 
343
326
  /**
344
- * @brief Fallback function template for is_valid, returns false if the
345
- * expression is not valid.
327
+ * @brief Empty base struct for all operator types.
346
328
  *
347
- * @tparam Ts The argument types to be tested.
329
+ * @details
330
+ * The `op` struct serves as a common base for all operator and value
331
+ * wrapper types used in the µTest++ framework's type traits and
332
+ * metaprogramming utilities. It provides a unified type hierarchy,
333
+ * enabling compile-time detection and generic handling of operator-like
334
+ * types within the framework.
348
335
  *
349
- * @return `false` indicating the expression is not valid for the given
350
- * argument types.
336
+ * This struct is intended for internal use as a base for integral
337
+ * constants, floating point constants, and other value wrappers,
338
+ * supporting advanced template metaprogramming and type introspection.
351
339
  *
352
- * @details
353
- * This overload is selected when the primary `is_valid` template cannot be
354
- * instantiated, providing a `false` result for invalid expressions.
340
+ * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
355
341
  */
356
- template <class... Ts>
357
- constexpr auto
358
- is_valid (...) -> bool
342
+ struct op
359
343
  {
360
- return false;
361
- }
344
+ };
345
+
346
+ // ------------------------------------------------------------------------
347
+ // Concepts.
362
348
 
363
349
  /**
364
- * @brief Variable template to determine if a type models a container.
365
- *
366
- * @tparam T The type to be checked for container-like behaviour.
350
+ * @brief C++20 concept satisfied when `T` provides both `begin()` and
351
+ * `end()` member functions.
367
352
  *
368
- * @retval true if `T` has both `begin()` and `end()` member functions.
369
- * @retval false otherwise.
353
+ * @tparam T The type to be checked.
370
354
  *
371
355
  * @details
372
- * The `is_container_v` variable template evaluates to `true` if the given
373
- * type `T` provides both `begin()` and `end()` member functions,
374
- * indicating that it models a standard container concept. This trait is
375
- * determined at compile time using SFINAE and is_valid, and is used
376
- * throughout the µTest++ framework to enable generic handling of container
377
- * types in template metaprogramming.
356
+ * The `container_like` concept is satisfied when `T` exposes both a
357
+ * `begin()` and an `end()` member function, as required by standard
358
+ * range-based iteration. It is used to detect container types for
359
+ * specialised comparison and reporting within the framework.
378
360
  */
379
361
  template <class T>
380
- static constexpr auto is_container_v = is_valid<T> (
381
- [] (auto t) -> decltype (t.begin (), t.end (), void ()) {});
362
+ concept container_like = requires (const T& t) {
363
+ t.begin ();
364
+ t.end ();
365
+ };
382
366
 
383
367
  /**
384
- * @brief Variable template to determine if a type provides a static `npos`
385
- * member.
386
- *
387
- * @tparam T The type to be checked for the presence of a static `npos`
388
- * member.
368
+ * @brief C++20 concept satisfied when `T` provides a `npos` member.
389
369
  *
390
- * @retval true if `T` has a static member named `npos`.
391
- * @retval false otherwise.
370
+ * @tparam T The type to be checked.
392
371
  *
393
372
  * @details
394
- * The `has_npos_v` variable template evaluates to `true` if the given type
395
- * `T` defines a static member named `npos`. This trait is determined at
396
- * compile time using SFINAE and the `is_valid` utility, and is used
397
- * throughout the µTest++ framework to enable generic handling of types
398
- * that follow the standard string or container conventions.
373
+ * The `has_npos` concept is satisfied when `T` exposes a static `npos`
374
+ * member, as provided by `std::string_view` and similar types. It is
375
+ * used to detect string-like types for specialised comparison and
376
+ * reporting within the framework.
399
377
  */
400
378
  template <class T>
401
- static constexpr auto has_npos_v
402
- = is_valid<T> ([] (auto t) -> decltype (void (t.npos)) {});
379
+ concept has_npos = requires { T::npos; };
403
380
 
404
381
  /**
405
- * @brief Variable template to determine if a type provides a `value`
406
- * member.
382
+ * @brief C++20 concept satisfied when `T` provides a `value` member.
407
383
  *
408
- * @tparam T The type to be checked for the presence of a `value` member.
409
- *
410
- * @retval true if `T` has a member named `value`.
411
- * @retval false otherwise.
384
+ * @tparam T The type to be checked.
412
385
  *
413
386
  * @details
414
- * The `has_value_v` variable template evaluates to `true` if the given
415
- * type `T` defines a member named `value`. This trait is determined at
416
- * compile time using SFINAE and the `is_valid` utility, and is used
417
- * throughout the µTest++ framework to enable generic handling of types
418
- * that encapsulate a value, such as wrappers or constant types.
387
+ * The `has_value` concept is satisfied when an instance of `T` exposes
388
+ * a `value` member. It is used to detect framework value-wrapper types
389
+ * such as `integral_constant`, `floating_point_constant`, and `value<T>`,
390
+ * enabling specialised comparison and reporting.
419
391
  */
420
392
  template <class T>
421
- static constexpr auto has_value_v
422
- = is_valid<T> ([] (auto t) -> decltype (void (t.value)) {});
393
+ concept has_value = requires (const T& t) { t.value; };
423
394
 
424
395
  /**
425
- * @brief Variable template to determine if a type provides an `epsilon`
426
- * member.
427
- *
428
- * @tparam T The type to be checked for the presence of an `epsilon`
429
- * member.
396
+ * @brief C++20 concept satisfied when `T` provides an `epsilon` member.
430
397
  *
431
- * @retval true if `T` has a member named `epsilon`.
432
- * @retval false otherwise.
398
+ * @tparam T The type to be checked.
433
399
  *
434
400
  * @details
435
- * The `has_epsilon_v` variable template evaluates to `true` if the given
436
- * type `T` defines a member named `epsilon`. This trait is determined at
437
- * compile time using SFINAE and the `is_valid` utility, and is used
438
- * throughout the µTest++ framework to enable generic handling of types
439
- * that represent floating-point values or require precision control.
401
+ * The `has_epsilon` concept is satisfied when an instance of `T` exposes
402
+ * an `epsilon` member. It is used to detect floating point value-wrapper
403
+ * types such as `floating_point_constant` and the floating point
404
+ * specialisation of `value<T>`, enabling precision-aware comparisons.
440
405
  */
441
406
  template <class T>
442
- static constexpr auto has_epsilon_v
443
- = is_valid<T> ([] (auto t) -> decltype (void (t.epsilon)) {});
407
+ concept has_epsilon = requires (const T& t) { t.epsilon; };
444
408
 
445
409
  /**
446
- * @brief Variable template to determine if a type is a floating point
410
+ * @brief C++20 concept satisfied when `T` is a standard floating point
447
411
  * type.
448
412
  *
449
- * @tparam T The type to be checked for floating point classification.
450
- *
451
- * @retval true if `T` is a floating point type.
452
- * @retval false otherwise.
413
+ * @tparam T The type to be checked.
453
414
  *
454
415
  * @details
455
- * The `is_floating_point_v` variable template evaluates to `true` if the
456
- * given type `T` is a floating point type (`float`, `double`, or `long
457
- * double`). For all other types, it evaluates to `false`. This trait is
458
- * used throughout the µTest++ framework to enable type-safe handling and
459
- * specialisation for floating point types in template metaprogramming.
460
- *
461
- * Specialisations are provided for `float`, `double`, and `long double`,
462
- * each evaluating to `true`.
416
+ * The `is_floating_point` concept is satisfied when `T` is one of the
417
+ * standard floating point types (`float`, `double`, or `long double`).
418
+ * It is the primary definition; `is_floating_point_v` is derived from
419
+ * it for use in `if constexpr` and non-concept contexts.
463
420
  */
464
421
  template <class T>
465
- inline constexpr auto is_floating_point_v = false;
466
-
467
- /**
468
- * @brief Variable template specialisation indicating that `float` is a
469
- * floating point type.
470
- *
471
- * @details
472
- * This specialisation of the `is_floating_point_v` variable template
473
- * evaluates to `true` for the `float` type, confirming that it is
474
- * recognised as a floating point type within the µTest++ framework. This
475
- * enables type-safe handling and specialisation for floating point types
476
- * in template metaprogramming.
477
- *
478
- * @see is_floating_point_v
479
- */
480
- template <>
481
- inline constexpr auto is_floating_point_v<float> = true;
422
+ concept is_floating_point = std::is_floating_point_v<T>;
482
423
 
483
424
  /**
484
- * @brief Variable template specialisation indicating that `double` is a
485
- * floating point type.
425
+ * @brief C++20 concept satisfied when a type derives from `op`.
486
426
  *
487
- * @details
488
- * This specialisation of the `is_floating_point_v` variable template
489
- * evaluates to `true` for the `double` type, confirming that it is
490
- * recognised as a floating point type within the µTest++ framework. This
491
- * enables type-safe handling and specialisation for floating point types
492
- * in template metaprogramming.
493
- *
494
- * @see is_floating_point_v
495
- */
496
- template <>
497
- inline constexpr auto is_floating_point_v<double> = true;
498
-
499
- /**
500
- * @brief Variable template specialisation indicating that `long double` is
501
- * a floating point type.
427
+ * @tparam T The type to be checked.
502
428
  *
503
429
  * @details
504
- * This specialisation of the `is_floating_point_v` variable template
505
- * evaluates to `true` for the `long double` type, confirming that it is
506
- * recognised as a floating point type within the µTest++ framework. This
507
- * enables type-safe handling and specialisation for floating point types
508
- * in template metaprogramming.
509
- *
510
- * @see is_floating_point_v
430
+ * The `is_op` concept is satisfied when `T` is derived from the
431
+ * `type_traits::op` base struct. It is the primary definition used
432
+ * throughout the framework; `is_op_v` is derived from it for use in
433
+ * `if constexpr` and boolean contexts.
511
434
  */
512
- template <>
513
- inline constexpr auto is_floating_point_v<long double> = true;
435
+ template <class T>
436
+ concept is_op = std::is_base_of_v<type_traits::op, T>;
514
437
 
515
- #if defined(__clang__) or defined(_MSC_VER)
516
438
  /**
517
- * @brief Variable template to determine if one type is convertible to
518
- * another.
519
- *
520
- * @tparam From The source type to be checked for convertibility.
521
- * @tparam To The target type to which conversion is tested.
439
+ * @brief C++20 concept satisfied when at least one of two types derives
440
+ * from `op`.
522
441
  *
523
- * @retval true if `From` is convertible to `To`.
524
- * @retval false otherwise.
442
+ * @tparam Lhs_T The type of the left-hand operand.
443
+ * @tparam Rhs_T The type of the right-hand operand.
525
444
  *
526
445
  * @details
527
- * The `is_convertible_v` variable template evaluates to `true` if the type
528
- * `From` is implicitly convertible to the type `To`, and `false`
529
- * otherwise. This trait is determined at compile time and is used
530
- * throughout the µTest++ framework to enable type-safe conversions and
531
- * requirements checking in template metaprogramming.
532
- *
533
- * On supported compilers, this trait leverages compiler intrinsics for
534
- * optimal performance and accuracy.
446
+ * The `any_op` concept is satisfied when `Lhs_T` or `Rhs_T` (or both)
447
+ * are derived from the `type_traits::op` base struct. It is used to
448
+ * constrain binary operator overloads in the `operators` namespace so
449
+ * that they are enabled only when at least one operand is a framework
450
+ * type, avoiding unintended conflicts with user-defined operators.
535
451
  */
536
- template <class From, class To>
537
- static constexpr auto is_convertible_v = __is_convertible_to (From, To);
538
- #else
539
- /**
540
- * @brief Function template to determine if one type is convertible to
541
- * another.
542
- *
543
- * @tparam From The source type to be checked for convertibility.
544
- * @tparam To The target type to which conversion is tested.
545
- *
546
- * @param n Dummy parameter used for overload resolution.
547
- * @retval true if `From` is convertible to `To`.
548
- *
549
- * @details
550
- * The `is_convertible` function template checks, at compile time, whether
551
- * a value of type `From` can be implicitly converted to type `To`. This is
552
- * achieved using SFINAE and is primarily used as an implementation detail
553
- * for the `is_convertible_v` variable template within the µTest++
554
- * framework.
555
- *
556
- * If the conversion is valid, this overload is selected and returns
557
- * `true`.
558
- */
559
- template <class From, class To>
560
- constexpr auto
561
- is_convertible (int n) -> decltype (bool (To (declval<From> ())))
562
- {
563
- (void)n; // Prevent the unused parameter warning.
564
- return true;
565
- }
452
+ template <class Lhs_T, class Rhs_T>
453
+ concept any_op = is_op<Lhs_T> or is_op<Rhs_T>;
566
454
 
567
455
  /**
568
- * @brief Fallback function template for is_convertible, returns false if
569
- * the conversion is not valid.
456
+ * @brief C++20 concept satisfied when a type can be used as a test
457
+ * expression in `expect()` or `assume()`.
570
458
  *
571
- * @tparam ...Unused Unused template parameters.
572
- *
573
- * @retval false indicating the conversion is not valid.
459
+ * @tparam T The type to be checked.
574
460
  *
575
461
  * @details
576
- * This overload is selected when the primary `is_convertible` template
577
- * cannot be instantiated, providing a `false` result for invalid
578
- * conversions.
462
+ * The `checkable` concept is satisfied when `T` is either a
463
+ * framework operator type (derived from `op`) or is implicitly
464
+ * convertible to `bool`. It is used to constrain the `expect()` and
465
+ * `assume()` function templates, ensuring that only sensible
466
+ * expression types are accepted.
579
467
  */
580
- template <class...>
581
- constexpr auto
582
- is_convertible (...)
583
- {
584
- return false;
585
- }
468
+ template <class T>
469
+ concept checkable = is_op<T> or std::convertible_to<T, bool>;
586
470
 
587
471
  /**
588
- * @brief Variable template to determine if one type is convertible to
589
- * another.
590
- *
591
- * @tparam From The source type to be checked for convertibility.
592
- * @tparam To The target type to which conversion is tested.
472
+ * @brief C++20 concept satisfied when a type can be appended to the
473
+ * deferred reporter's output via `operator<<`.
593
474
  *
594
- * @retval true if `From` is convertible to `To`.
595
- * @retval false otherwise.
475
+ * @tparam T The type to be checked.
596
476
  *
597
477
  * @details
598
- * The `is_convertible_v` variable template evaluates to `true` if the type
599
- * `From` is implicitly convertible to the type `To`, and `false`
600
- * otherwise. This trait is determined at compile time and is used
601
- * throughout the µTest++ framework to enable type-safe conversions and
602
- * requirements checking in template metaprogramming.
478
+ * The `printable` concept is satisfied when `T` is an arithmetic
479
+ * type or is implicitly convertible to `std::string_view`. It
480
+ * constrains the `operator<<` overload of `deferred_reporter_base`,
481
+ * ensuring that only types that can be meaningfully appended to the
482
+ * output message are accepted.
603
483
  */
604
- template <class From, class To>
605
- constexpr auto is_convertible_v = is_convertible<From, To> (0);
606
- #endif
484
+ template <class T>
485
+ concept printable = std::is_arithmetic_v<T>
486
+ or std::is_convertible_v<T, std::string_view>;
487
+
488
+ // ------------------------------------------------------------------------
607
489
 
608
490
  /**
609
- * @brief Struct template for SFINAE requirements.
491
+ * @brief Base struct template providing common storage and accessors
492
+ * for runtime value-wrapper types.
493
+ *
494
+ * @tparam T The type of the stored value.
610
495
  *
611
496
  * @details
612
- * The `requires_` struct template is a utility for SFINAE (Substitution
613
- * Failure Is Not An Error) in template metaprogramming. It is typically
614
- * used to enable or disable template specialisations and function
615
- * templates based on compile-time boolean conditions.
497
+ * The `value_base_` struct template provides the `T value_{}` member,
498
+ * an explicit `operator T()` conversion, and a `get()` accessor,
499
+ * shared by `genuine_integral_value`, `value<T>`, and the floating
500
+ * point specialisation `value<T>`.
616
501
  *
617
- * When the boolean template parameter is `true`, the specialisation
618
- * provides a nested `type` alias, which can be used in conjunction with
619
- * `typename` and `requires_t` to enforce requirements in template
620
- * declarations.
502
+ * It inherits from `op` so that all derived types satisfy the `is_op`
503
+ * concept without each struct needing to inherit from `op` directly.
621
504
  *
622
505
  * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
623
506
  */
624
- template <bool Cond>
625
- struct requires_
507
+ template <class T>
508
+ struct value_base_ : op
626
509
  {
627
- };
510
+ /**
511
+ * @brief The type of the stored value.
512
+ */
513
+ using value_type = T;
628
514
 
629
- /**
630
- * @brief Specialisation of the requirements struct template for `true`.
631
- *
632
- * @details
633
- * When the condition is `true`, this specialisation provides a nested
634
- * `type` alias, typically used for SFINAE and requirements checking in
635
- * template metaprogramming.
636
- *
637
- * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
638
- */
639
- template <>
640
- struct requires_<true>
641
- {
642
515
  /**
643
- * @brief Alias type provided when the requirement is satisfied.
516
+ * @brief Constructs a `value_base_` with the given value.
517
+ *
518
+ * @param v The value to be stored.
644
519
  */
645
- using type = int;
646
- };
520
+ constexpr explicit value_base_ (const T& v) noexcept : value_{ v }
521
+ {
522
+ }
647
523
 
648
- /**
649
- * @brief Alias template for extracting the `type` member from `requires_`.
650
- *
651
- * @tparam Cond The boolean condition to be checked at compile time.
652
- *
653
- * @details
654
- * The `requires_t` alias template simplifies the use of the `requires_`
655
- * struct template by directly exposing the nested `type` member. It is
656
- * commonly used to enforce compile-time requirements in template
657
- * declarations.
658
- */
659
- template <bool Cond>
660
- using requires_t = typename requires_<Cond>::type;
524
+ /**
525
+ * @brief Explicit conversion operator to the underlying value type.
526
+ *
527
+ * @return The stored value as type `T`.
528
+ *
529
+ * @details
530
+ * Allows explicit conversion to the encapsulated value.
531
+ */
532
+ [[nodiscard]] constexpr explicit
533
+ operator T () const noexcept
534
+ {
535
+ return value_;
536
+ }
661
537
 
662
- /**
663
- * @brief Empty base struct for all operator types.
664
- *
665
- * @details
666
- * The `op` struct serves as a common base for all operator and value
667
- * wrapper types used in the µTest++ framework's type traits and
668
- * metaprogramming utilities. It provides a unified type hierarchy,
669
- * enabling compile-time detection and generic handling of operator-like
670
- * types within the framework.
671
- *
672
- * This struct is intended for internal use as a base for integral
673
- * constants, floating point constants, and other value wrappers,
674
- * supporting advanced template metaprogramming and type introspection.
675
- *
676
- * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
677
- */
678
- struct op
679
- {
538
+ /**
539
+ * @brief Getter for the stored value.
540
+ *
541
+ * @par Parameters
542
+ * None.
543
+ * @return The stored value.
544
+ *
545
+ * @details
546
+ * Returns the stored value by value.
547
+ */
548
+ [[nodiscard]] constexpr T
549
+ get (void) const noexcept
550
+ {
551
+ return value_;
552
+ }
553
+
554
+ /**
555
+ * @brief The stored value.
556
+ */
557
+ T value_{};
680
558
  };
681
559
 
682
560
  /**
@@ -687,28 +565,30 @@ namespace micro_os_plus::micro_test_plus
687
565
  * @details
688
566
  * The `integral_constant` struct template provides a compile-time constant
689
567
  * value of an integral type, with additional utility features. It inherits
690
- * from `op` to enable unified handling within the µTest++ framework's type
691
- * traits and metaprogramming utilities.
568
+ * from `value_base_<decltype(N)>`, which supplies the `value_type` alias,
569
+ * the `value_` runtime member, the explicit conversion operator, and the
570
+ * `get()` accessor.
692
571
  *
693
- * This struct template exposes the constant value via a static member, a
694
- * getter method, and explicit conversion operators. It also provides a
572
+ * This struct retains the compile-time `value` constant and provides a
695
573
  * unary minus operator to obtain the negative value as a new
696
574
  * `integral_constant` instance.
697
575
  *
698
576
  * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
699
577
  */
700
578
  template <auto N>
701
- struct integral_constant : op
579
+ struct integral_constant : value_base_<decltype (N)>
702
580
  {
703
581
  /**
704
- * @brief The type of the constant value.
582
+ * @brief The compile-time constant value.
705
583
  */
706
- using value_type = decltype (N);
584
+ static constexpr auto value = N;
707
585
 
708
586
  /**
709
- * @brief The constant value.
587
+ * @brief Default constructor. Initialises the base with `N`.
710
588
  */
711
- static constexpr auto value = N;
589
+ constexpr integral_constant () noexcept : value_base_<decltype (N)>{ N }
590
+ {
591
+ }
712
592
 
713
593
  /**
714
594
  * @brief Unary minus operator.
@@ -720,42 +600,10 @@ namespace micro_os_plus::micro_test_plus
720
600
  * of the current value.
721
601
  */
722
602
  [[nodiscard]] constexpr auto
723
- operator- () const
603
+ operator- () const noexcept
724
604
  {
725
605
  return integral_constant<-N>{};
726
606
  }
727
-
728
- /**
729
- * @brief Explicit conversion operator to value_type.
730
- *
731
- * @par Parameters
732
- * None.
733
- * @return The constant value as type `value_type`.
734
- *
735
- * @details
736
- * Allows explicit conversion to the underlying value type.
737
- */
738
- [[nodiscard]] constexpr explicit
739
- operator value_type (void) const
740
- {
741
- return N;
742
- }
743
-
744
- /**
745
- * @brief Getter for the constant value.
746
- *
747
- * @par Parameters
748
- * None.
749
- * @return The constant value.
750
- *
751
- * @details
752
- * Returns the compile-time constant value.
753
- */
754
- [[nodiscard]] constexpr auto
755
- get (void) const
756
- {
757
- return N;
758
- }
759
607
  };
760
608
 
761
609
  /**
@@ -772,23 +620,28 @@ namespace micro_os_plus::micro_test_plus
772
620
  * @details
773
621
  * The `floating_point_constant` struct template provides a compile-time
774
622
  * constant value of a floating point type, supporting custom size and
775
- * precision. It inherits from `op` to enable unified handling within the
776
- * µTest++ framework's type traits and metaprogramming utilities.
777
- *
778
- * This struct template exposes the constant value via a static member, a
779
- * getter method, and explicit conversion operators. It also provides a
780
- * unary minus operator to obtain the negative value as a new
781
- * `floating_point_constant` instance. The `epsilon` member defines the
782
- * precision used for floating point comparisons, calculated based on the
783
- * specified size.
623
+ * precision. It inherits from `op` directly rather than from
624
+ * `value_base_<T>`, which avoids introducing a user-provided constructor
625
+ * into the type and keeps it trivially default-constructible. This
626
+ * prevents the GCC ARM PSABI note about parameter-passing ABI changes
627
+ * that is emitted for non-trivially-constructible types under C++17.
628
+ *
629
+ * The `value_type` alias, explicit conversion operator, and `get()`
630
+ * accessor are provided directly by this struct. The compile-time
631
+ * `epsilon` and `value` static constants are retained, and a unary
632
+ * minus operator is provided to obtain the negative value as a new
633
+ * `floating_point_constant` instance.
784
634
  *
785
635
  * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
786
636
  */
787
637
  template <class T, auto N, auto D, auto Size, auto P = 1>
788
638
  struct floating_point_constant : op
789
639
  {
640
+ static_assert (P == 1 || P == -1,
641
+ "floating_point_constant: P must be +1 or -1");
642
+
790
643
  /**
791
- * @brief The type of the constant value.
644
+ * @brief The type of the stored value.
792
645
  */
793
646
  using value_type = T;
794
647
 
@@ -801,7 +654,7 @@ namespace micro_os_plus::micro_test_plus
801
654
  static constexpr auto epsilon = T (1) / math::pow (T (10), Size - 1);
802
655
 
803
656
  /**
804
- * @brief The constant value.
657
+ * @brief The compile-time constant value.
805
658
  *
806
659
  * @details
807
660
  * Computed as `P * (N + D / 10^Size)`.
@@ -810,47 +663,42 @@ namespace micro_os_plus::micro_test_plus
810
663
  = T (P) * (T (N) + (T (D) / math::pow (T (10), Size)));
811
664
 
812
665
  /**
813
- * @brief Unary minus operator.
814
- *
815
- * @return A `floating_point_constant` with value `-value`.
666
+ * @brief Explicit conversion operator to the underlying value type.
816
667
  *
817
- * @details
818
- * Returns a new `floating_point_constant` instance representing the
819
- * negative of the current value.
668
+ * @return The compile-time constant as type `T`.
820
669
  */
821
- [[nodiscard]] constexpr auto
822
- operator- () const
670
+ [[nodiscard]] constexpr explicit
671
+ operator T () const noexcept
823
672
  {
824
- return floating_point_constant<T, N, D, Size, -1>{};
673
+ return value;
825
674
  }
826
675
 
827
676
  /**
828
- * @brief Explicit conversion operator to value_type.
677
+ * @brief Getter for the compile-time constant value.
829
678
  *
830
- * @return The constant value as type `value_type`.
831
- *
832
- * @details
833
- * Allows explicit conversion to the underlying floating point value
834
- * type.
679
+ * @par Parameters
680
+ * None.
681
+ * @return The compile-time constant as type `T`.
835
682
  */
836
- [[nodiscard]] constexpr explicit
837
- operator value_type () const
683
+ [[nodiscard]] constexpr T
684
+ get (void) const noexcept
838
685
  {
839
686
  return value;
840
687
  }
841
688
 
842
689
  /**
843
- * @brief Getter for the constant value.
690
+ * @brief Unary minus operator.
844
691
  *
845
- * @return The constant value.
692
+ * @return A `floating_point_constant` with negated sign parameter.
846
693
  *
847
694
  * @details
848
- * Returns the compile-time floating point constant value.
695
+ * Returns a new `floating_point_constant` instance representing the
696
+ * negative of the current value by flipping the sign parameter `P`.
849
697
  */
850
698
  [[nodiscard]] constexpr auto
851
- get () const
699
+ operator- () const noexcept
852
700
  {
853
- return value;
701
+ return floating_point_constant<T, N, D, Size, -P>{};
854
702
  }
855
703
  };
856
704
 
@@ -861,161 +709,49 @@ namespace micro_os_plus::micro_test_plus
861
709
  *
862
710
  * @details
863
711
  * The `genuine_integral_value` struct template encapsulates a runtime
864
- * integral value, providing a consistent interface for value access and
865
- * conversion. It inherits from `op` to enable unified handling within the
866
- * µTest++ framework's type traits and metaprogramming utilities.
867
- *
868
- * This struct template exposes the value via a member variable, a getter
869
- * method, and an explicit conversion operator. It is intended for use
870
- * cases where a value must be wrapped and treated generically within the
871
- * framework, supporting advanced template metaprogramming and type
872
- * introspection.
712
+ * integral value. The stored value, explicit conversion operator, and
713
+ * getter are provided by the `value_base_` base.
873
714
  *
874
715
  * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
875
716
  */
876
717
  template <class T>
877
- struct genuine_integral_value : op
718
+ struct genuine_integral_value : value_base_<T>
878
719
  {
879
- /**
880
- * @brief The type of the encapsulated value.
881
- */
882
- using value_type = T;
883
-
884
720
  /**
885
721
  * @brief Constructs a genuine_integral_value with the specified value.
886
722
  *
887
723
  * @param _value The integral value to be stored.
888
724
  */
889
- constexpr genuine_integral_value (const T& _value) : value_{ _value }
890
- {
891
- }
892
-
893
- /**
894
- * @brief Explicit conversion operator to the underlying value type.
895
- *
896
- * @return The stored value as type `T`.
897
- *
898
- * @details
899
- * Allows explicit conversion to the encapsulated value.
900
- */
901
- [[nodiscard]] constexpr explicit
902
- operator T () const
725
+ constexpr genuine_integral_value (const T& _value) noexcept
726
+ : value_base_<T>{ _value }
903
727
  {
904
- return value_;
905
728
  }
906
-
907
- /**
908
- * @brief Getter for the encapsulated value.
909
- *
910
- * @return The value of type `T`.
911
- *
912
- * @details
913
- * Returns the stored integral value.
914
- */
915
- [[nodiscard]] constexpr decltype (auto)
916
- get () const
917
- {
918
- return value_;
919
- }
920
-
921
- /**
922
- * @brief The encapsulated integral value.
923
- */
924
- T value_{};
925
729
  };
926
730
 
927
- /**
928
- * @brief Variable template to determine if a type derives from `op`.
929
- *
930
- * @tparam T The type to be checked for derivation from `op`.
931
- *
932
- * @retval true if `T` is derived from `type_traits::op`.
933
- * @retval false otherwise.
934
- *
935
- * @details
936
- * The `is_op_v` variable template evaluates to `true` if the given type
937
- * `T` is derived from the `type_traits::op` base struct, and `false`
938
- * otherwise. This trait is determined at compile time using compiler
939
- * intrinsics and is used throughout the µTest++ framework to enable
940
- * generic handling and detection of operator-like or value wrapper types
941
- * in template metaprogramming.
942
- */
943
- template <class T>
944
- inline constexpr auto is_op_v = __is_base_of (type_traits::op, T);
945
-
946
731
  /**
947
732
  * @brief Struct template representing a generic value, accessible via a
948
733
  * getter.
949
734
  *
950
735
  * @tparam T The type of the value to be encapsulated.
951
- * @tparam Opt An optional parameter for SFINAE or specialisation,
952
- * defaults to `int`.
953
736
  *
954
737
  * @details
955
- * The `value` struct template encapsulates a value of type `T`, providing
956
- * a consistent interface for value access and conversion. It inherits from
957
- * `type_traits::op` to enable unified handling within the µTest++
958
- * framework's type traits and metaprogramming utilities.
959
- *
960
- * This struct template exposes the value via a member variable, a getter
961
- * method, and an explicit conversion operator. It is intended for use
962
- * cases where a value must be wrapped and treated generically within the
963
- * framework, supporting advanced template metaprogramming and type
964
- * introspection.
738
+ * The `value` struct template encapsulates a value of type `T`. The
739
+ * stored value, explicit conversion operator, and getter are provided
740
+ * by the `value_base_` base.
965
741
  *
966
742
  * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
967
743
  */
968
- template <class T, class Opt = int>
969
- struct value : type_traits::op
744
+ template <class T>
745
+ struct value : value_base_<T>
970
746
  {
971
- /**
972
- * @brief The type of the encapsulated value.
973
- */
974
- using value_type = T;
975
-
976
747
  /**
977
748
  * @brief Constructs a value object with the specified value.
978
749
  *
979
750
  * @param _value The value to be stored.
980
751
  */
981
- constexpr value (const T& _value) : value_{ _value }
752
+ constexpr value (const T& _value) noexcept : value_base_<T>{ _value }
982
753
  {
983
754
  }
984
-
985
- /**
986
- * @brief Explicit conversion operator to the underlying value type.
987
- *
988
- * @return The stored value as type `T`.
989
- *
990
- * @details
991
- * Allows explicit conversion to the encapsulated value.
992
- */
993
- [[nodiscard]] constexpr explicit
994
- operator T () const
995
- {
996
- return value_;
997
- }
998
-
999
- /**
1000
- * @brief Getter for the encapsulated value.
1001
- *
1002
- * @par Parameters
1003
- * None.
1004
- * @return The value of type `T`.
1005
- *
1006
- * @details
1007
- * Returns the stored value.
1008
- */
1009
- [[nodiscard]] constexpr decltype (auto)
1010
- get (void) const
1011
- {
1012
- return value_;
1013
- }
1014
-
1015
- /**
1016
- * @brief The encapsulated value.
1017
- */
1018
- T value_{};
1019
755
  };
1020
756
 
1021
757
  /**
@@ -1027,15 +763,12 @@ namespace micro_os_plus::micro_test_plus
1027
763
  * @details
1028
764
  * The `value` struct template specialisation for floating point types
1029
765
  * encapsulates a value of type `T` and provides an associated `epsilon`
1030
- * for precision control during comparisons. It inherits from
1031
- * `type_traits::op` to enable unified handling within the µTest++
1032
- * framework's type traits and metaprogramming utilities.
766
+ * for precision control during comparisons. The stored value, explicit
767
+ * conversion operator, and getter are provided by the `value_base_` base.
1033
768
  *
1034
- * This struct template exposes the value via a member variable, a getter
1035
- * method, and an explicit conversion operator. The `epsilon` member
1036
- * defines the precision used for floating point comparisons and can be set
1037
- * explicitly or computed as a default based on the number of decimal
1038
- * digits in the value.
769
+ * The `epsilon` member defines the precision used for floating point
770
+ * comparisons and can be set explicitly or computed as a default based
771
+ * on the number of decimal digits in the value.
1039
772
  *
1040
773
  * This specialisation is intended for use cases where floating point
1041
774
  * values require controlled precision, supporting advanced template
@@ -1044,34 +777,30 @@ namespace micro_os_plus::micro_test_plus
1044
777
  * @headerfile micro-test-plus.h <micro-os-plus/micro-test-plus.h>
1045
778
  */
1046
779
  template <class T>
1047
- struct value<T,
1048
- type_traits::requires_t<type_traits::is_floating_point_v<T>>>
1049
- : type_traits::op
780
+ requires is_floating_point<T>
781
+ struct value<T> : value_base_<T>
1050
782
  {
1051
783
  /**
1052
- * @brief The type of the encapsulated value.
1053
- */
1054
- using value_type = T;
1055
-
1056
- /**
1057
- * @brief The epsilon value used for floating point comparisons.
784
+ * @brief The epsilon value used for floating-point comparisons.
1058
785
  *
1059
786
  * @details
1060
- * This static inline member defines the precision for comparisons. It
1061
- * can be set explicitly via the constructor or computed as a default
1062
- * based on the number of decimal digits in the value.
787
+ * This instance member defines the precision for comparisons. It
788
+ * is set via the constructor, either explicitly or computed as a
789
+ * default based on the number of decimal digits in the value.
790
+ * Each instance carries its own epsilon, so two `value<T>` objects
791
+ * with different precisions do not interfere with each other.
1063
792
  */
1064
- static inline auto epsilon = T{}; // Why static?
793
+ T epsilon = T{};
1065
794
 
1066
795
  /**
1067
- * @brief Constructs a floating point value with a specified precision.
796
+ * @brief Constructs a floating-point value with a specified precision.
1068
797
  *
1069
- * @param _value The floating point value to be stored.
798
+ * @param _value The floating-point value to be stored.
1070
799
  * @param precision The epsilon value to be used for comparisons.
1071
800
  */
1072
- constexpr value (const T& _value, const T precision) : value_{ _value }
801
+ constexpr value (const T& _value, const T precision) noexcept
802
+ : value_base_<T>{ _value }, epsilon{ precision }
1073
803
  {
1074
- epsilon = precision;
1075
804
  }
1076
805
 
1077
806
  /**
@@ -1083,48 +812,13 @@ namespace micro_os_plus::micro_test_plus
1083
812
  * The epsilon is computed as 1 divided by 10 raised to the number of
1084
813
  * decimal digits in the value.
1085
814
  */
1086
- constexpr /*explicit(false)*/ value (const T& val)
815
+ constexpr value (const T& val)
1087
816
  : value{ val,
1088
817
  T (1)
1089
818
  / math::pow (T (10),
1090
819
  math::den_size<unsigned long long> (val)) }
1091
820
  {
1092
821
  }
1093
-
1094
- /**
1095
- * @brief Explicit conversion operator to the underlying value type.
1096
- *
1097
- * @return The stored value as type `T`.
1098
- *
1099
- * @details
1100
- * Allows explicit conversion to the encapsulated floating point value.
1101
- */
1102
- [[nodiscard]] constexpr explicit
1103
- operator T () const
1104
- {
1105
- return value_;
1106
- }
1107
-
1108
- /**
1109
- * @brief Getter for the encapsulated value.
1110
- *
1111
- * @par Parameters
1112
- * None.
1113
- * @return The value of type `T`.
1114
- *
1115
- * @details
1116
- * Returns the stored floating point value.
1117
- */
1118
- [[nodiscard]] constexpr decltype (auto)
1119
- get (void) const
1120
- {
1121
- return value_;
1122
- }
1123
-
1124
- /**
1125
- * @brief The encapsulated floating point value.
1126
- */
1127
- T value_{};
1128
822
  };
1129
823
 
1130
824
  // ------------------------------------------------------------------------