Skip to main content

detail.h File

C++ header file with declarations for the µTest++ internals. More...

Included Headers​

#include "extension.h" #include "math.h" #include <algorithm> #include <compare> #include <concepts> #include <cstddef> #include <cstdio> #include <string> #include <string_view> #include <type_traits> #include <utility> #include "inlines/detail-inlines.h"

Namespaces Index​

namespacemicro_os_plus

The primary namespace for the µOS++ framework. More...

namespacemicro_test_plus

Primary namespace for the µTest++ testing framework. More...

namespacedetail

Internal implementation details for the µTest++ framework. More...

namespaceextension

The templates and the concepts for extending the µTest++ testing framework. More...

Classes Index​

structand_op<Lhs_T, Rhs_T>

Logical AND comparator struct template. More...

structapprox_op<Lhs_T, Rhs_T, Epsilon_T>

Approximate comparator struct template. More...

structarray_operand<T>

An array operand of a comparator, other than a character array. More...

structbasic_c_string<Char_T>

A C string operand of a comparator. More...

structbinary_op<Lhs_T, Rhs_T>

Common base struct template for binary comparators. More...

structcallable_op

Common base struct for callable-wrapping operators. More...

structcallable_result

The result of the invocation of the callable of a check. More...

structcompare_op<Lhs_T, Rhs_T, Compare_T>

Relational comparator struct template. More...

structcompare_op<Lhs_T, Rhs_T, Compare_T>

Relational comparator struct template. More...

structequal_to

Equality tag for compare_op. More...

structfailed_requirement

The exception thrown to stop a test case after a failed require(). More...

structgreater

Greater than tag for compare_op. More...

structgreater_equal

Greater than or equal tag for compare_op. More...

structless

Less than tag for compare_op. More...

structless_equal

Less than or equal tag for compare_op. More...

structnot_equal_to

Non-equality tag for compare_op. More...

structnot_op<T>

Logical NOT comparator struct template. More...

structnothrow_op

Operator struct to check if an expression does not throw any exception. More...

structor_op<Lhs_T, Rhs_T>

Logical OR comparator struct template. More...

structpredicate_op<T, Predicate_T>

Unary predicate struct template. More...

structpredicate_op<T, Predicate_T>

Unary predicate struct template. More...

structthrows_op<Exception_T>

Operator struct template to check if an expression throws a specific exception. More...

structthrows_op<void>

Operator struct to check if an expression throws any exception. More...

structunary_op<T>

Common base struct template for unary comparators. More...

Concepts Index​

conceptcharacter

Concept satisfied by the character types. More...

conceptcharacter_pointer

Concept satisfied by the pointers to the character types. More...

conceptapprox_operand

Concept satisfied when T is a valid operand of the approximate comparator. More...

Typedefs Index​

usingc_string = basic_c_string< char >

The C string operand of char strings. More...

template <class T>
usingstored_operand_t = std::conditional_t< std::is_lvalue_reference_v< T > and not std::is_copy_constructible_v< std::remove_cvref_t< T > >, const std::remove_reference_t< T > &, std::remove_cvref_t< T > >

The type with which an expression stores an operand. More...

template <class T>
usingunwrapped_t = std::remove_cvref_t< decltype(detail::unwrap( std::declval< const std::remove_cvref_t< T > & >()))>

The type of an operand, after the framework wrappers are removed by detail::unwrap(). More...

Enumerations Index​

enum classthrow_outcome : unsigned char { ... }

The kind of exception thrown by the callable of a check. More...

Operators Index​

template <class T, class R>
constexpr autooperator<=> (const array_operand< T > &lhs, const R &rhs)

Orders an array operand and a range lexicographically. More...

template <character Char_T>
constexpr std::strong_orderingoperator<=> (const basic_c_string< Char_T > &lhs, const basic_c_string< Char_T > &rhs) noexcept

Orders two C string operands. More...

template <character Char_T>
constexpr std::strong_orderingoperator<=> (const basic_c_string< Char_T > &lhs, std::type_identity_t< std::basic_string_view< Char_T > > rhs) noexcept

Orders a C string operand and a string. More...

template <class T, class R>
constexpr booloperator== (const array_operand< T > &lhs, const R &rhs)

Compares an array operand with a range for equality. More...

template <character Char_T>
constexpr booloperator== (const basic_c_string< Char_T > &lhs, const basic_c_string< Char_T > &rhs) noexcept

Compares two C string operands for equality. More...

template <character Char_T>
constexpr booloperator== (const basic_c_string< Char_T > &lhs, std::nullptr_t) noexcept

Checks whether a C string operand is a null pointer. More...

template <character Char_T>
constexpr booloperator== (const basic_c_string< Char_T > &lhs, std::type_identity_t< std::basic_string_view< Char_T > > rhs) noexcept

Compares a C string operand with a string. More...

Functions Index​

template <typename Lhs_T, typename Rhs_T>
and_op (Lhs_T &&, Rhs_T &&) -> and_op< stored_operand_t< Lhs_T >, stored_operand_t< Rhs_T > >

Deduction guide for the logical AND comparator. More...

template <class T>
voidappend_number (std::string &buffer, T v)

Appends the shortest decimal representation of a numeric value to a buffer. More...

template <class T>
voidappend_pointer (std::string &buffer, T *v)

Appends the hexadecimal address of a pointer to a buffer. More...

template <class Lhs_T, class Rhs_T, class Epsilon_T>
approx_op (Lhs_T &&, Rhs_T &&, Epsilon_T &&) -> approx_op< stored_operand_t< Lhs_T >, stored_operand_t< Rhs_T >, stored_operand_t< Epsilon_T > >

Deduction guide for the approximate comparator. More...

template <class T>
constexpr auto as_operand (T &&t) noexcept -> decltype(auto)

Prepares an operand of a comparator. More...

template <class Lhs_T, class Rhs_T, class Compare_T>
compare_op (Lhs_T &&, Rhs_T &&, Compare_T) -> compare_op< stored_operand_t< decltype(detail::as_operand(std::declval< Lhs_T >()))>, stored_operand_t< decltype(detail::as_operand(std::declval< Rhs_T >()))>, Compare_T >

Deduction guide for the relational comparator. More...

template <class Lhs_T, class Rhs_T, class Epsilon_T>
constexpr booldiffer_by_at_most (Lhs_T lhs, Rhs_T rhs, Epsilon_T epsilon)

Tells whether two numbers differ by at most a tolerance. More...

template <typename Lhs_T, typename Rhs_T>
or_op (Lhs_T &&, Rhs_T &&) -> or_op< stored_operand_t< Lhs_T >, stored_operand_t< Rhs_T > >

Deduction guide for the logical OR comparator. More...

template <class T, class Predicate_T>
predicate_op (T &&, Predicate_T) -> predicate_op< stored_operand_t< decltype(detail::as_operand(std::declval< T >()))>, Predicate_T >

Deduction guide for the unary predicate. More...

template <class T>
auto unwrap (const T &t) -> decltype(auto) constexpr

Returns the value wrapped by a framework type, or the operand itself. More...

template <class Lhs_T, class Rhs_T>
constexpr boolwithin_tolerance (const Lhs_T &lhs, const Rhs_T &rhs)

Deprecated check whether two operands are equal within the tolerance of the floating-point wrappers. More...

Macro Definitions Index​

#defineMICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE   "zu"

Portable printf() conversion for the size_t values. More...

Description​

C++ header file with declarations for the µTest++ internals.

This header provides the declarations for the internal components of the µTest++ framework, encapsulated within the micro_os_plus::micro_test_plus::detail namespace. It defines the core mechanisms, helper structures, and utility templates that underpin the framework's value retrieval, comparator logic, operand preparation, and exception checking facilities.

All definitions reside within the micro_os_plus::micro_test_plus::detail namespace.

This file is included by micro-os-plus/micro-test-plus.h, which is the header that the applications include.

Typedefs​

c_string​

using micro_os_plus::micro_test_plus::detail::c_string = basic_c_string<char>

The C string operand of char strings.

The type to which as_operand() converts the char arrays, including the string literals, and the char pointers; the framework itself names basic_c_string, and the alias is kept for the tests that name the type of a comparator.

Definition at line 1746 of file detail.h.

stored_operand_t​

template <class T>
using micro_os_plus::micro_test_plus::detail::stored_operand_t = std::conditional_t< std::is_lvalue_reference_v<T> and not std::is_copy_constructible_v<std::remove_cvref_t<T>>, const std::remove_reference_t<T>&, std::remove_cvref_t<T>>

The type with which an expression stores an operand.

Applied by the deduction guides and the factory functions to the type deduced for a forwarding reference: X& (or const X&) for an lvalue, X for an rvalue.

An lvalue is copied into the expression, so that an expression built in a function from its parameters, and returned, does not refer to the destroyed locals of that function. An rvalue is moved into the expression, so that an expression that outlives the statement, like auto op = eq (f (), 1);, does not refer to a destroyed temporary.

The arrays and the character pointers are first converted by as_operand() to basic_c_string or array_operand, which are stored, but which refer to the characters or to the elements of the operand, without copying them; such an expression is valid only as long as the operand.

Only an lvalue of a class type that cannot be copied (for example a std::unique_ptr) is stored as a const reference; such a reference remains valid only as long as the named operand, which is always the case within the statement that checks the expression.

Template Parameters
T

The type deduced for a forwarding reference.

Definition at line 234 of file detail.h.

234 using stored_operand_t = std::conditional_t<

unwrapped_t​

template <class T>
using micro_os_plus::micro_test_plus::detail::unwrapped_t = std::remove_cvref_t<decltype (detail::unwrap ( std::declval<const std::remove_cvref_t<T>&> ()))>

The type of an operand, after the framework wrappers are removed by detail::unwrap().

Template Parameters
T

The type of the operand, possibly a reference.

Without references and qualifiers; for example int for a to_i wrapper and for a 42_i literal, and the type itself for the other operands. Used by extension::approx_operand and by comparison_operand_t.

Definition at line 828 of file detail.h.

828 using unwrapped_t = std::remove_cvref_t<decltype (detail::unwrap (

Enumerations​

throw_outcome​

enum class micro_os_plus::micro_test_plus::detail::throw_outcome : unsigned char
strong

The kind of exception thrown by the callable of a check.

Enumeration values
noneNothing was thrown, or the expected exception was thrown
std_exceptionA std::exception that was not the expected one was thrown; its what() is kept
unknown_exceptionAnother exception was thrown

Kept only when the check failed, to be written in the report.

Definition at line 1335 of file detail.h.

1336 {
1341
1347
1352 };

Operators​

operator<=>()​

template <class T, class R>
auto micro_os_plus::micro_test_plus::detail::operator<=> (const array_operand< T > & lhs, const R & rhs)
nodiscard constexpr

Orders an array operand and a range lexicographically.

Template Parameters
T

The element type of the array operand.

R

The type of the range.

Parameters
lhs

The array operand.

rhs

The range, which may be another array operand.

Returns

The lexicographic order of the elements.

A range that is a prefix of the other is the lesser one.

Definition at line 1696 of file detail-inlines.h.

1697 constexpr auto
1698 operator<=> (const array_operand<T>& lhs, const R& rhs)
1699 {
1700 return std::lexicographical_compare_three_way (lhs.begin (), lhs.end (),
1701 rhs.begin (), rhs.end ());

References micro_os_plus::micro_test_plus::detail::array_operand< T >::begin, micro_os_plus::micro_test_plus::detail::array_operand< T >::end and micro_os_plus::micro_test_plus::detail::operator<=>.

operator<=>()​

template <character Char_T>
std::strong_ordering micro_os_plus::micro_test_plus::detail::operator<=> (const basic_c_string< Char_T > & lhs, const basic_c_string< Char_T > & rhs)
nodiscard constexpr noexcept

Orders two C string operands.

Template Parameters
Char_T

The character type.

Parameters
lhs

The left operand.

rhs

The right operand.

Returns

The lexicographic order of the characters; a null pointer is equal to another null pointer and less than any string.

A null pointer orders before any string.

Definition at line 1594 of file detail-inlines.h.

1595 constexpr std::strong_ordering
1597 const basic_c_string<Char_T>& rhs) noexcept
1598 {
1599 if (lhs.is_null () || rhs.is_null ())
1600 {
1601 return !lhs.is_null () <=> !rhs.is_null ();
1602 }
1603 return lhs.view () <=> rhs.view ();

Referenced by micro_os_plus::micro_test_plus::detail::operator<=>.

operator<=>()​

template <character Char_T>
std::strong_ordering micro_os_plus::micro_test_plus::detail::operator<=> (const basic_c_string< Char_T > & lhs, std::type_identity_t< std::basic_string_view< Char_T > > rhs)
nodiscard constexpr noexcept

Orders a C string operand and a string.

Template Parameters
Char_T

The character type.

Parameters
lhs

The C string operand.

rhs

The string.

Returns

The lexicographic order of the characters; a null pointer is less than any string.

A null pointer orders before any string.

Definition at line 1610 of file detail-inlines.h.

1611 constexpr std::strong_ordering
1613 const basic_c_string<Char_T>& lhs,
1614 std::type_identity_t<std::basic_string_view<Char_T>> rhs) noexcept
1615 {
1616 if (lhs.is_null ())
1617 {
1618 return std::strong_ordering::less;
1619 }
1620 return lhs.view () <=> rhs;

operator==()​

template <class T, class R>
bool micro_os_plus::micro_test_plus::detail::operator== (const array_operand< T > & lhs, const R & rhs)
nodiscard constexpr

Compares an array operand with a range for equality.

Template Parameters
T

The element type of the array operand.

R

The type of the range.

Parameters
lhs

The array operand.

rhs

The range, which may be another array operand.

Return Values
true

The ranges have the same size and equal elements.

false

Otherwise.

Ranges of different sizes are not equal, without comparing any element. The elements are compared as the scalar operands of eq() are, with equal_to::apply(), so that integers of different signedness are compared by value, not by converting the signed one to the unsigned type.

Definition at line 1681 of file detail-inlines.h.

1681 constexpr bool
1682 operator== (const array_operand<T>& lhs, const R& rhs)
1683 {
1684 return std::equal (lhs.begin (), lhs.end (), rhs.begin (), rhs.end (),
1685 [] (const auto& l, const auto& r)
1686 { return equal_to::apply (l, r); });

References micro_os_plus::micro_test_plus::detail::array_operand< T >::begin and micro_os_plus::micro_test_plus::detail::array_operand< T >::end.

operator==()​

template <character Char_T>
bool micro_os_plus::micro_test_plus::detail::operator== (const basic_c_string< Char_T > & lhs, const basic_c_string< Char_T > & rhs)
nodiscard constexpr noexcept

Compares two C string operands for equality.

Template Parameters
Char_T

The character type.

Parameters
lhs

The left operand.

rhs

The right operand.

Return Values
true

Both are null, or both are strings with the same characters.

false

Otherwise.

Two null pointers are equal; a null pointer is not equal to any string, not even an empty one.

Definition at line 1555 of file detail-inlines.h.

1555 constexpr bool
1557 const basic_c_string<Char_T>& rhs) noexcept
1558 {
1559 if (lhs.is_null () || rhs.is_null ())
1560 {
1561 return lhs.is_null () && rhs.is_null ();
1562 }
1563 return lhs.view () == rhs.view ();

operator==()​

template <character Char_T>
bool micro_os_plus::micro_test_plus::detail::operator== (const basic_c_string< Char_T > & lhs, std::nullptr_t)
nodiscard constexpr noexcept

Checks whether a C string operand is a null pointer.

Template Parameters
Char_T

The character type.

Parameters
lhs

The C string operand.

Return Values
true

The operand is a null pointer.

false

Otherwise.

Returns whether the operand is a null pointer.

Definition at line 1584 of file detail-inlines.h.

1584 constexpr bool
1585 operator==(const basic_c_string<Char_T>& lhs, std::nullptr_t) noexcept
1586 {
1587 return lhs.is_null ();

operator==()​

template <character Char_T>
bool micro_os_plus::micro_test_plus::detail::operator== (const basic_c_string< Char_T > & lhs, std::type_identity_t< std::basic_string_view< Char_T > > rhs)
nodiscard constexpr noexcept

Compares a C string operand with a string.

Also used for the standard strings of the same character type, which convert to the string view, and, as a rewritten candidate, with the operands in the reverse order.

Template Parameters
Char_T

The character type.

Parameters
lhs

The C string operand.

rhs

The string.

Return Values
true

The operand is not null and has the same characters.

false

Otherwise.

A null pointer is not equal to any string.

Definition at line 1571 of file detail-inlines.h.

1571 constexpr bool
1573 const basic_c_string<Char_T>& lhs,
1574 std::type_identity_t<std::basic_string_view<Char_T>> rhs) noexcept
1575 {
1576 return !lhs.is_null () && lhs.view () == rhs;

Functions​

and_op()​

template <typename Lhs_T, typename Rhs_T>
micro_os_plus::micro_test_plus::detail::and_op (Lhs_T &&, Rhs_T &&)

Deduction guide for the logical AND comparator.

Deduces Lhs_T and Rhs_T from the constructor arguments, so that and_op{ lhs, rhs } can be written without explicit template arguments. The operand types are deduced as forwarding references, and stored as stored_operand_t selects.

Definition at line 1111 of file detail.h.

append_number()​

template <class T>
void micro_os_plus::micro_test_plus::detail::append_number (std::string & buffer, T v)

Appends the shortest decimal representation of a numeric value to a buffer.

Template Parameters
T

The numeric type to format.

Parameters
buffer

The string to append to.

v

The value to format.

Returns

Nothing.

The value is formatted into a local buffer, which is then appended to buffer.

For long double, a platform-specific path is chosen:

  • On Windows and on platforms where long double has the same storage width as double (e.g. 32-bit Arm), the value is cast to double and formatted with std::to_chars.
  • On all other platforms (e.g. x86-64 Linux/macOS with 80-bit extended precision, or AArch64 and RISC-V with 128-bit quad precision), snprintf with %.*Lg is used as a portable fallback, because std::to_chars for long double may be unavailable (e.g. when linking with lld). The precision starts at LDBL_DIG and is increased until the text reads back, with strtold, as the same value, up to LDBL_DECIMAL_DIG, which always reads back exactly. This gives the shortest exact form, as std::to_chars gives for the other types; a shorter form would need fewer than LDBL_DIG digits, and Lg removes the trailing zeros, so starting at LDBL_DIG does not lose it. For zero and the subnormal values, which have fewer significant digits, the precision starts at 1. The value of errno, which strtold may set for subnormal values, is preserved. If no precision reads back exactly, the C library handles long double with the precision of double (e.g. newlib on AArch64 and RISC-V), and the value is cast to double and formatted with std::to_chars, as above.

For all other numeric types, std::to_chars is called directly, providing locale-independent formatting. The snprintf() path uses the decimal point of the C locale, which is . unless the application changes it with setlocale().

Definition at line 1348 of file detail-inlines.h.

1348 void
1349 append_number (std::string& buffer, const T v)
1350 {
1351 if constexpr (std::is_same_v<T, long double>)
1352 {
1353#if defined(_WIN32) \
1354 || (defined(__SIZEOF_LONG_DOUBLE__) \
1355 && __SIZEOF_LONG_DOUBLE__ == __SIZEOF_DOUBLE__)
1356 // On Windows (all toolchains: MinGW, Clang, MSVC), the C runtime
1357 // does not handle the %Lg printf specifier correctly for 80-bit
1358 // long double, producing garbage output. On platforms where long
1359 // double has the same width as double (e.g. 32-bit Arm), the cast
1360 // is lossless. In both cases, cast to double and use
1361 // std::to_chars.
1362 char buf[32];
1363 const auto [ptr, ec] = std::to_chars (buf, buf + sizeof (buf),
1364 static_cast<double> (v));
1365 if (ec == std::errc{})
1366 buffer.append (buf, ptr);
1367#else
1368 // On other platforms (80-bit extended precision on x86-64,
1369 // 128-bit quad precision on AArch64 and RISC-V), std::to_chars
1370 // for long double may be unavailable (e.g., with lld).
1371 // Use snprintf as a portable fallback; %Lg is supported by the C
1372 // libraries used on these platforms (e.g. glibc, the macOS libc,
1373 // and newlib, the latter with the precision of double on AArch64
1374 // and RISC-V). Use the smallest precision that reads back as the
1375 // same value; the buffer fits the 36 digits of the 128-bit
1376 // format, with the sign, the point, and the exponent.
1377 char buf[48];
1378 const int saved_errno = errno;
1379 // The subnormal values have fewer significant digits.
1380 const int min_precision
1381 = (v > -LDBL_MIN && v < LDBL_MIN) ? 1 : LDBL_DIG;
1382 bool is_exact = false;
1383 for (int precision = min_precision; precision <= LDBL_DECIMAL_DIG;
1384 ++precision)
1385 {
1386 // GCC 11 does not know the range of the precision, and
1387 // warns that the text may be truncated; it cannot be, since
1388 // the precision is at most LDBL_DECIMAL_DIG.
1389#if defined(__GNUC__) && !defined(__clang__)
1390#pragma GCC diagnostic push
1391#pragma GCC diagnostic ignored "-Wformat-truncation"
1392#endif // defined(__GNUC__) && !defined(__clang__)
1393 snprintf (buf, sizeof (buf), "%.*Lg", precision, v);
1394#if defined(__GNUC__) && !defined(__clang__)
1395#pragma GCC diagnostic pop
1396#endif // defined(__GNUC__) && !defined(__clang__)
1397 // A NaN is never equal to itself, and has no digits.
1398 if (v != v || strtold (buf, nullptr) == v)
1399 {
1400 is_exact = true;
1401 break;
1402 }
1403 }
1404 errno = saved_errno;
1405 if (is_exact)
1406 {
1407 buffer.append (buf);
1408 }
1409 else
1410 {
1411 // The C library formats or reads long double with the
1412 // precision of double (e.g. newlib on AArch64 and RISC-V),
1413 // and its long text would only show the error of the
1414 // conversion; use the shortest form of the double value,
1415 // as on the platforms above.
1416 const auto [ptr, ec] = std::to_chars (buf, buf + sizeof (buf),
1417 static_cast<double> (v));
1418 if (ec == std::errc{})
1419 buffer.append (buf, ptr);
1421#endif // long double formatting
1422 }
1423 else
1424 {
1425 char buf[32];
1426 const auto [ptr, ec] = std::to_chars (buf, buf + sizeof (buf), v);
1427 if (ec == std::errc{})
1428 buffer.append (buf, ptr);
1429 }

Reference micro_os_plus::micro_test_plus::detail::append_number.

Referenced by micro_os_plus::micro_test_plus::detail::expression_formatter::append_first_difference, micro_os_plus::micro_test_plus::detail::append_number, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<< and micro_os_plus::micro_test_plus::detail::reporter::operator<<.

append_pointer()​

template <class T>
void micro_os_plus::micro_test_plus::detail::append_pointer (std::string & buffer, T * v)

Appends the hexadecimal address of a pointer to a buffer.

Shared by the reporter and the expression_formatter, so that the pointers are displayed identically in the messages and in the expressions. Pointers to const or volatile objects, and function pointers, are accepted too.

Template Parameters
T

The type pointed to (an object or a function type).

Parameters
buffer

The string to append to.

v

The pointer.

Returns

Nothing.

Null pointers are rendered as "0x0", regardless of the platform, avoiding platform-specific representations such as "(nil)" on Linux/glibc. Non-null pointers are formatted with snprintf(), using the p specifier.

The p specifier expects a void*. Object pointers are converted implicitly to const volatile void*, which accepts any qualification, and the qualifiers are then removed with const_cast; a reinterpret_cast to void* would not compile for pointers to const objects. The object is not accessed. Function pointers, which do not convert to void* implicitly, use reinterpret_cast.

Definition at line 1454 of file detail-inlines.h.

1454 void
1455 append_pointer (std::string& buffer, T* v)
1456 {
1457 if (v == nullptr)
1458 {
1459 buffer.append ("0x0");
1460 return;
1461 }
1462
1463 void* p;
1464 if constexpr (std::is_function_v<T>)
1465 {
1466 p = reinterpret_cast<void*> (v);
1467 }
1468 else
1469 {
1470 const volatile void* cvp = v;
1471 p = const_cast<void*> (cvp);
1472 }
1473
1474#if defined(__GNUC__)
1475#pragma GCC diagnostic push
1476
1477#if defined(__clang__)
1478#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
1479#endif // defined(__clang__)
1480#endif // defined(__GNUC__)
1481
1482 char buf[20];
1483 snprintf (buf, sizeof (buf), "%p", p);
1484 buffer.append (buf);
1485
1486#if defined(__GNUC__)
1487#pragma GCC diagnostic pop
1488#endif // defined(__GNUC__)

Reference micro_os_plus::micro_test_plus::detail::append_pointer.

Referenced by micro_os_plus::micro_test_plus::detail::append_pointer, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<< and micro_os_plus::micro_test_plus::detail::reporter::operator<<.

approx_op()​

template <class Lhs_T, class Rhs_T, class Epsilon_T>
micro_os_plus::micro_test_plus::detail::approx_op (Lhs_T &&, Rhs_T &&, Epsilon_T &&)

Deduction guide for the approximate comparator.

Deduces Lhs_T, Rhs_T, and Epsilon_T from the constructor arguments, which are stored as stored_operand_t selects.

Definition at line 1055 of file detail.h.

as_operand()​

template <class T>
decltype(auto) micro_os_plus::micro_test_plus::detail::as_operand (T && t)
nodiscard constexpr noexcept

Prepares an operand of a comparator.

The arrays and the pointers of the character types (char, wchar_t, char8_t, char16_t, and char32_t, but not signed char or unsigned char, which are byte buffers) are converted to basic_c_string, so that they are compared by content; the other arrays, including those of volatile characters, are converted to array_operand, so that they are compared element by element, the functions to function pointers, and all other operands are returned unchanged, so the other pointers, including the pointers to volatile characters, and the functions are compared by address.

The other operands are forwarded, so that the comparator moves a temporary, and refers to a named operand.

Template Parameters
T

The type deduced for the forwarding reference.

Parameters
t

The operand.

Returns

A basic_c_string for the C strings, an array_operand for the other arrays, otherwise t, forwarded.

Arrays of the character types are converted using their size as a bound, pointers to them using the null terminator; the const qualifier of the characters is ignored. The volatile characters are not strings, since basic_c_string cannot refer to them: an array of them is converted to array_operand, like the other arrays, and compared element by element, and a pointer to them is forwarded, and compared by address, like the other pointers. The functions are converted to function pointers. Every other operand is forwarded, unchanged, as an lvalue or an rvalue reference.

The qualifiers of an array are those of its elements, so the element type is taken from the type of the argument, not from the type without qualifiers, which would lose the volatile of the elements, and the conversion to the pointer to const elements would not compile.

Definition at line 1725 of file detail-inlines.h.

1725 constexpr auto
1726 as_operand (T&& t) noexcept -> decltype (auto)
1727 {
1728 using type = std::remove_cvref_t<T>;
1729 // The cv-qualifiers of an array are those of its elements, which
1730 // std::remove_cvref_t removes; keep volatile for the element type.
1731 using element_type = std::remove_const_t<
1732 std::remove_extent_t<std::remove_reference_t<T>>>;
1733
1734 if constexpr (std::is_array_v<type> && character<element_type>
1735 && not std::is_volatile_v<element_type>)
1736 {
1738 t, std::extent_v<type>
1739 };
1740 }
1741 else if constexpr (character_pointer<type>)
1742 {
1744 t
1745 };
1746 }
1747 else if constexpr (std::is_array_v<type>)
1748 {
1749 // Other arrays (e.g. byte buffers) are compared by content.
1751 static_cast<const element_type*> (t), std::extent_v<type>
1752 };
1753 }
1754 else if constexpr (std::is_function_v<type>)
1755 {
1756 // Functions are compared by address, as function pointers.
1757 return &t;
1758 }
1759 else
1760 {
1761 return std::forward<T> (t);
1762 }

Reference micro_os_plus::micro_test_plus::detail::as_operand.

Referenced by micro_os_plus::micro_test_plus::detail::compare_op< Lhs_T, Rhs_T, Compare_T >::compare_op, micro_os_plus::micro_test_plus::detail::predicate_op< T, Predicate_T >::predicate_op, micro_os_plus::micro_test_plus::detail::as_operand, micro_os_plus::micro_test_plus::detail::compare_op, micro_os_plus::micro_test_plus::eq, micro_os_plus::micro_test_plus::ge, micro_os_plus::micro_test_plus::gt, micro_os_plus::micro_test_plus::le, micro_os_plus::micro_test_plus::lt and micro_os_plus::micro_test_plus::ne.

compare_op()​

template <class Lhs_T, class Rhs_T, class Compare_T>
micro_os_plus::micro_test_plus::detail::compare_op (Lhs_T &&, Rhs_T &&, Compare_T)

Deduction guide for the relational comparator.

Deduces Lhs_T, Rhs_T, and Compare_T from the constructor arguments, so that compare_op{ lhs, rhs, equal_to{} } can be written without explicit template arguments. The operand types are deduced as forwarding references, prepared by as_operand(), and stored as stored_operand_t selects.

Definition at line 941 of file detail.h.

References micro_os_plus::micro_test_plus::detail::as_operand and micro_os_plus::micro_test_plus::detail::differ_by_at_most.

differ_by_at_most()​

template <class Lhs_T, class Rhs_T, class Epsilon_T>
bool micro_os_plus::micro_test_plus::detail::differ_by_at_most (Lhs_T lhs, Rhs_T rhs, Epsilon_T epsilon)
nodiscard constexpr

Tells whether two numbers differ by at most a tolerance.

If the three values are integers, the distance is computed exactly, as an unsigned value, also for operands of mixed signedness, and compared with the tolerance with std::cmp_less_equal(), so that neither overflows nor wraps around. Otherwise, the values are converted to their common floating-point type, and the absolute value of the difference is compared with the tolerance. A negative tolerance, or a NaN, makes the result false.

Template Parameters
Lhs_T

The arithmetic type of the first value.

Rhs_T

The arithmetic type of the second value.

Epsilon_T

The arithmetic type of the tolerance.

Parameters
lhs

The first value.

rhs

The second value.

epsilon

The tolerance.

Return Values
true

The distance between the values is less than or equal to the tolerance.

false

Otherwise.

For the integers, the larger value is selected with std::cmp_less(), and the distance is computed in std::uintmax_t: when both values have the same sign, as the modular difference of their conversions, which is exact; otherwise, as the sum of the larger value and of the magnitude of the negative one. A sum that does not fit in std::uintmax_t is flagged as an overflow, and gives false, since the true distance is larger than any tolerance. The tolerance is compared with std::cmp_less_equal(), so a negative one gives false.

For the other types, the values are converted to their common type, which is a floating-point one, so std::int64_t values compared with a float tolerance lose precision; the comparison is inclusive, so a distance equal to the tolerance succeeds. Two equal values, including two infinities of the same sign, whose difference would be NaN, are at the distance zero; a NaN operand always fails.

Definition at line 940 of file detail-inlines.h.

940 constexpr bool
941 differ_by_at_most (Lhs_T lhs, Rhs_T rhs, Epsilon_T epsilon)
942 {
943 if constexpr (std::is_integral_v<Lhs_T> and std::is_integral_v<Rhs_T>
944 and std::is_integral_v<Epsilon_T>)
945 {
946 bool overflow = false;
947 const auto distance
948 = [&overflow] (auto larger,
949 auto smaller) constexpr -> std::uintmax_t
950 {
951 if constexpr (std::is_signed_v<decltype (smaller)>)
952 {
953 if (smaller < 0 and std::cmp_greater_equal (larger, 0))
954 {
955 // The magnitude of the negative value, without
956 // negating the minimum of its type.
957 const auto magnitude
958 = static_cast<std::uintmax_t> (-(smaller + 1)) + 1u;
959 const auto upper = static_cast<std::uintmax_t> (larger);
960 if (upper > std::numeric_limits<std::uintmax_t>::max ()
961 - magnitude)
962 {
963 overflow = true;
964 return std::numeric_limits<std::uintmax_t>::max ();
965 }
966 return upper + magnitude;
967 }
968 }
969 return static_cast<std::uintmax_t> (larger)
970 - static_cast<std::uintmax_t> (smaller);
971 };
972
973 const std::uintmax_t difference = std::cmp_less (lhs, rhs)
974 ? distance (rhs, lhs)
975 : distance (lhs, rhs);
976 return !overflow && std::cmp_less_equal (difference, epsilon);
977 }
978 else
979 {
980 using float_type = std::common_type_t<Lhs_T, Rhs_T, Epsilon_T>;
981 const auto left = static_cast<float_type> (lhs);
982 const auto right = static_cast<float_type> (rhs);
983
984#if defined(__GNUC__)
985#pragma GCC diagnostic push
986#pragma GCC diagnostic ignored "-Wfloat-equal"
987#endif // defined(__GNUC__)
988 // The exact comparison is deliberate, for the infinities.
989 const float_type distance
990 = (left == right) ? float_type{} : math::abs (left - right);
991#if defined(__GNUC__)
992#pragma GCC diagnostic pop
993#endif // defined(__GNUC__)
994
995 return distance <= static_cast<float_type> (epsilon);
996 }

References micro_os_plus::micro_test_plus::detail::math::abs and micro_os_plus::micro_test_plus::detail::differ_by_at_most.

Referenced by micro_os_plus::micro_test_plus::detail::approx_op< Lhs_T, Rhs_T, Epsilon_T >::approx_op, micro_os_plus::micro_test_plus::detail::compare_op and micro_os_plus::micro_test_plus::detail::differ_by_at_most.

or_op()​

template <typename Lhs_T, typename Rhs_T>
micro_os_plus::micro_test_plus::detail::or_op (Lhs_T &&, Rhs_T &&)

Deduction guide for the logical OR comparator.

Deduces Lhs_T and Rhs_T from the constructor arguments, so that or_op{ lhs, rhs } can be written without explicit template arguments. The operand types are deduced as forwarding references, and stored as stored_operand_t selects.

Definition at line 1166 of file detail.h.

predicate_op()​

template <class T, class Predicate_T>
micro_os_plus::micro_test_plus::detail::predicate_op (T &&, Predicate_T)

Deduction guide for the unary predicate.

Deduces T and Predicate_T from the constructor arguments, so that predicate_op{ t, even{} } can be written without explicit template arguments. The operand type is deduced as a forwarding reference, prepared by as_operand(), and stored as stored_operand_t selects.

Definition at line 1301 of file detail.h.

unwrap()​

template <class T>
decltype(auto) constexpr micro_os_plus::micro_test_plus::detail::unwrap (const T & t)
nodiscard constexpr

Returns the value wrapped by a framework type, or the operand itself.

Always call it qualified, as detail::unwrap(), so that argument-dependent lookup cannot select a function of the application, defined in the namespace of an operand.

The operand is returned by reference, without a copy; the result is valid only as long as the operand.

Template Parameters
T

The type of the operand.

Parameters
t

The operand.

Returns

The value returned by t.get() for the framework wrappers (the literals and the to_* wrappers), otherwise a reference to t.

If the type T is a framework expression type (see extension::is_op) that provides a get() member function, it is invoked and its result returned. Otherwise a reference to the argument itself is returned, so that the types of the application, even those with a get() member function, are compared with their own operators, without a copy. The selection is performed at compile time via if constexpr with an inline requires expression; the return type is deduced with decltype (auto) from the selected branch.

Declaration at line 167 of file detail.h, definition at line 98 of file detail-inlines.h.

98 unwrap (const T& t)
99 {
100#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
101 if constexpr (extension::is_op<T> && requires { t.get (); })
102 return t.get ();
103 else
104#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
105 return t;
106 }

Reference micro_os_plus::micro_test_plus::detail::unwrap.

Referenced by micro_os_plus::micro_test_plus::detail::approx_op< Lhs_T, Rhs_T, Epsilon_T >::approx_op, micro_os_plus::micro_test_plus::detail::compare_op< Lhs_T, Rhs_T, Compare_T >::compare_op, micro_os_plus::micro_test_plus::detail::predicate_op< T, Predicate_T >::predicate_op, micro_os_plus::micro_test_plus::detail::approx_op< Lhs_T, Rhs_T, Epsilon_T >::epsilon, micro_os_plus::micro_test_plus::detail::binary_op< Lhs_T, Rhs_T >::lhs, micro_os_plus::micro_test_plus::detail::unary_op< T >::operand, micro_os_plus::micro_test_plus::detail::expression_formatter::operator<<, micro_os_plus::micro_test_plus::detail::binary_op< Lhs_T, Rhs_T >::rhs, micro_os_plus::micro_test_plus::detail::unwrap and micro_os_plus::micro_test_plus::detail::within_tolerance.

Macro Definitions​

MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE​

#define MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE   "zu"

Portable printf() conversion for the size_t values.

The format checker of Clang (MSVC target) on Windows rejects the standard z modifier, even though the C runtime printf() implementation supports it, so the Microsoft-specific I modifier is used there ("Iu"). The format checker of GCC (MinGW-w64, the "ms_printf" archetype) rejects z too, but also ignores I, so the modifier that matches the width of size_t is used ("llu" for 64-bit Windows, "u" for 32-bit Windows). Elsewhere, including Clang for MinGW, it is "zu".

It is used in all the library formats that print size_t values, in the reporter output and in the trace messages alike, concatenated with the adjacent string literals, as the standard PRIu32 macros are (for example "%" MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE " checks").

The templates in the inline headers use it too; their string literals are concatenated when they are parsed, not when they are instantiated, so the macro is undefined at the end of micro-test-plus.h, after all the headers, to keep it out of the application code. The library sources include the individual headers, which keep it defined.

Definition at line 102 of file detail.h.

102#define MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE "zu"

Referenced by micro_os_plus::micro_test_plus::detail::runnable_base::runnable_base, micro_os_plus::micro_test_plus::suite::suite, micro_os_plus::micro_test_plus::test_case::test_case, micro_os_plus::micro_test_plus::detail::reporter_tap::end_session, micro_os_plus::micro_test_plus::detail::reporter_tap::end_suite, micro_os_plus::micro_test_plus::detail::reporter_human::end_test_case, micro_os_plus::micro_test_plus::detail::reporter_tap::end_test_case, micro_os_plus::micro_test_plus::detail::reporter::format_session_totals, micro_os_plus::micro_test_plus::detail::anonymous{reporter.cpp}::format_skipped, micro_os_plus::micro_test_plus::detail::reporter::format_suite_totals, micro_os_plus::micro_test_plus::detail::reporter::format_test_case_totals, micro_os_plus::micro_test_plus::counters::operator+=, micro_os_plus::micro_test_plus::runner::run_suites, micro_os_plus::micro_test_plus::detail::reporter_tap::skip_suite and micro_os_plus::micro_test_plus::detail::reporter_tap::skip_test_case.

File Listing​

The file content with the documentation metadata removed is:

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
36
37#ifndef MICRO_OS_PLUS_MICRO_TEST_PLUS_DETAIL_H_
38#define MICRO_OS_PLUS_MICRO_TEST_PLUS_DETAIL_H_
39
40// ----------------------------------------------------------------------------
41
42#if defined(__cplusplus)
43
44// ----------------------------------------------------------------------------
45
46#if __has_include("micro-os-plus/project-config.h")
47#include "micro-os-plus/project-config.h"
48#endif // __has_include("micro-os-plus/project-config.h")
49
50#if __has_include("micro-os-plus/micro-test-plus-defines.h")
51#include "micro-os-plus/micro-test-plus-defines.h"
52#endif // __has_include("micro-os-plus/micro-test-plus-defines.h")
53
54#include "extension.h"
55#include "math.h"
56
57#include <algorithm>
58#include <compare>
59#include <concepts>
60#include <cstddef>
61#include <cstdio>
62#include <string>
63#include <string_view>
64#include <type_traits>
65#include <utility>
66
67// ----------------------------------------------------------------------------
68
93#if defined(_WIN32) && defined(__clang__) && !defined(__MINGW32__)
94#define MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE "Iu"
95#elif defined(_WIN32) && defined(__GNUC__) && !defined(__clang__)
96#if defined(_WIN64)
97#define MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE "llu"
98#else
99#define MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE "u"
100#endif // defined(_WIN64)
101#else
102#define MICRO_OS_PLUS_MICRO_TEST_PLUS_PRI_SIZE "zu"
103#endif // defined(_WIN32) && defined(__clang__) && !defined(__MINGW32__)
104
105// ----------------------------------------------------------------------------
106
107#if defined(__GNUC__)
108#pragma GCC diagnostic push
109
110#pragma GCC diagnostic ignored "-Wpadded"
111#pragma GCC diagnostic ignored "-Waggregate-return"
112#if defined(__clang__)
113#pragma clang diagnostic ignored "-Wc++98-compat"
114#pragma clang diagnostic ignored "-Wdocumentation"
115#endif // defined(__clang__)
116#endif // defined(__GNUC__)
117
118// ============================================================================
119
121{
141 namespace detail
142 {
143 // ========================================================================
144
164 template <class T>
165 // The specifier order works around a Doxygen (1.17, 1.18) mismatch
166 // with the definition, reported as "no matching file member found".
167 [[nodiscard]] decltype (auto) constexpr unwrap (const T& t);
168
169#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
196 template <class Lhs_T, class Rhs_T>
197 requires (extension::has_epsilon<Lhs_T> or extension::has_epsilon<Rhs_T>)
198 [[nodiscard]] constexpr bool
199 within_tolerance (const Lhs_T& lhs, const Rhs_T& rhs);
200#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
201
202 // ========================================================================
203
233 template <class T>
234 using stored_operand_t = std::conditional_t<
235 std::is_lvalue_reference_v<T>
236 and not std::is_copy_constructible_v<std::remove_cvref_t<T>>,
237 const std::remove_reference_t<T>&, std::remove_cvref_t<T>>;
238
239 // ========================================================================
240
256 template <class T>
257 struct unary_op : op
258 {
272 template <class U>
273 constexpr unary_op (U&& t, bool value);
274
282 [[nodiscard]] constexpr
283 operator bool () const;
284
296 [[nodiscard]] constexpr decltype (auto)
297 operand (void) const;
298
299 private:
309 T t_;
310
317 const bool value_{};
318 };
319
320 // ========================================================================
321
341 template <class Lhs_T, class Rhs_T>
342 struct binary_op : op
343 {
359 template <class L, class R>
360 constexpr binary_op (L&& lhs, R&& rhs, bool value);
361
369 [[nodiscard]] constexpr
370 operator bool () const;
371
383 [[nodiscard]] constexpr decltype (auto)
384 lhs (void) const;
385
397 [[nodiscard]] constexpr decltype (auto)
398 rhs (void) const;
399
400 private:
410 Lhs_T lhs_;
411
418 Rhs_T rhs_;
419
426 const bool value_{};
427 };
428
429 // ========================================================================
430
441 struct equal_to
442 {
451 static constexpr const char* symbol = " == ";
452
453#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
468 static constexpr bool within_tolerance_result = true;
469#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
470
485 template <class Lhs_T, class Rhs_T>
486 [[nodiscard, gnu::always_inline]] static constexpr bool
487 apply (const Lhs_T& lhs, const Rhs_T& rhs);
488 };
489
501 {
510 static constexpr const char* symbol = " != ";
511
512#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
527 static constexpr bool within_tolerance_result = false;
528#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
529
544 template <class Lhs_T, class Rhs_T>
545 [[nodiscard, gnu::always_inline]] static constexpr bool
546 apply (const Lhs_T& lhs, const Rhs_T& rhs);
547 };
548
559 struct greater
560 {
569 static constexpr const char* symbol = " > ";
570
571#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
586 static constexpr bool within_tolerance_result = false;
587#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
588
603 template <class Lhs_T, class Rhs_T>
604 [[nodiscard, gnu::always_inline]] static constexpr bool
605 apply (const Lhs_T& lhs, const Rhs_T& rhs);
606 };
607
619 {
628 static constexpr const char* symbol = " >= ";
629
630#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
645 static constexpr bool within_tolerance_result = true;
646#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
647
662 template <class Lhs_T, class Rhs_T>
663 [[nodiscard, gnu::always_inline]] static constexpr bool
664 apply (const Lhs_T& lhs, const Rhs_T& rhs);
665 };
666
677 struct less
678 {
687 static constexpr const char* symbol = " < ";
688
689#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
704 static constexpr bool within_tolerance_result = false;
705#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
706
721 template <class Lhs_T, class Rhs_T>
722 [[nodiscard, gnu::always_inline]] static constexpr bool
723 apply (const Lhs_T& lhs, const Rhs_T& rhs);
724 };
725
737 {
746 static constexpr const char* symbol = " <= ";
747
748#if defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
763 static constexpr bool within_tolerance_result = true;
764#endif // defined(MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED)
765
780 template <class Lhs_T, class Rhs_T>
781 [[nodiscard, gnu::always_inline]] static constexpr bool
782 apply (const Lhs_T& lhs, const Rhs_T& rhs);
783 };
784
785 // ========================================================================
786
811 template <class T>
812 [[nodiscard]] constexpr auto
813 as_operand (T&& t) noexcept -> decltype (auto);
814
827 template <class T>
828 using unwrapped_t = std::remove_cvref_t<decltype (detail::unwrap (
829 std::declval<const std::remove_cvref_t<T>&> ()))>;
830
831 // ========================================================================
832
885 template <class Lhs_T, class Rhs_T, class Compare_T>
886 struct compare_op : binary_op<Lhs_T, Rhs_T>
887 {
902 template <class L, class R>
905 constexpr compare_op (L&& lhs, R&& rhs, Compare_T);
906
907#if !defined(__DOXYGEN__)
923 template <class L, class R>
926 constexpr compare_op (L&& lhs, R&& rhs, Compare_T);
927#endif // !defined(__DOXYGEN__)
928 };
929
940 template <class Lhs_T, class Rhs_T, class Compare_T>
941 compare_op (Lhs_T&&, Rhs_T&&, Compare_T)
943 std::declval<Lhs_T> ()))>,
945 std::declval<Rhs_T> ()))>,
946 Compare_T>;
947
948 // ========================================================================
949
973 template <class Lhs_T, class Rhs_T, class Epsilon_T>
974 [[nodiscard]] constexpr bool
975 differ_by_at_most (Lhs_T lhs, Rhs_T rhs, Epsilon_T epsilon);
976
1001 template <class Lhs_T, class Rhs_T, class Epsilon_T>
1002 struct approx_op : binary_op<Lhs_T, Rhs_T>
1003 {
1019 template <class L, class R, class E>
1020 constexpr approx_op (L&& lhs, R&& rhs, E&& epsilon);
1021
1033 [[nodiscard]] constexpr decltype (auto)
1034 epsilon (void) const;
1035
1036 private:
1044 Epsilon_T epsilon_;
1045 };
1046
1054 template <class Lhs_T, class Rhs_T, class Epsilon_T>
1055 approx_op (Lhs_T&&, Rhs_T&&, Epsilon_T&&)
1058
1059 // ========================================================================
1060
1081 template <class Lhs_T, class Rhs_T>
1082 struct and_op : binary_op<Lhs_T, Rhs_T>
1083 {
1097 template <class L, class R>
1098 constexpr and_op (L&& lhs, R&& rhs);
1099 };
1100
1110 template <typename Lhs_T, typename Rhs_T>
1111 and_op (Lhs_T&&, Rhs_T&&)
1113
1114 // ========================================================================
1115
1136 template <class Lhs_T, class Rhs_T>
1137 struct or_op : binary_op<Lhs_T, Rhs_T>
1138 {
1152 template <class L, class R>
1153 constexpr or_op (L&& lhs, R&& rhs);
1154 };
1155
1165 template <typename Lhs_T, typename Rhs_T>
1166 or_op (Lhs_T&&, Rhs_T&&)
1168
1169 // ========================================================================
1170
1193 template <class T>
1194 struct not_op : unary_op<T>
1195 {
1208 template <class U>
1209 requires (not std::is_same_v<std::remove_cvref_t<U>, not_op<T>>)
1210 explicit constexpr not_op (U&& t);
1211 };
1212
1213 // ========================================================================
1214
1251 template <class T, class Predicate_T>
1253 {
1266 template <class U>
1268 constexpr predicate_op (U&& t, Predicate_T);
1269
1270#if !defined(__DOXYGEN__)
1285 template <class U>
1287 constexpr predicate_op (U&& t, Predicate_T);
1288#endif // !defined(__DOXYGEN__)
1289 };
1290
1300 template <class T, class Predicate_T>
1301 predicate_op (T&&, Predicate_T) -> predicate_op<
1303 Predicate_T>;
1304
1305 // ========================================================================
1306
1322 {
1323 };
1324
1325 // ========================================================================
1326
1327#if defined(__cpp_exceptions)
1328
1335 enum class throw_outcome : unsigned char
1336 {
1341
1347
1352 };
1353
1362 {
1370 bool value;
1371
1380
1387 std::string what;
1388 };
1389
1403 {
1410 explicit callable_op (callable_result&& result);
1411
1419 [[nodiscard]] constexpr
1420 operator bool () const;
1421
1431 [[nodiscard]] throw_outcome
1432 outcome (void) const noexcept;
1433
1442 [[nodiscard]] const std::string&
1443 what (void) const noexcept;
1444
1445 private:
1453 const bool value_{};
1454
1462
1471 std::string what_{};
1472 };
1473
1474 // ========================================================================
1475
1496 template <class Exception_T = void>
1498 {
1508 template <class Callable_T>
1509 requires std::invocable<Callable_T&>
1510 explicit throws_op (Callable_T&& func);
1511 };
1512
1513 // ========================================================================
1514
1528 template <>
1529 struct throws_op<void> : callable_op
1530 {
1540 template <class Callable_T>
1541 requires std::invocable<Callable_T&>
1542 explicit throws_op (Callable_T&& func);
1543 };
1544
1545 // ========================================================================
1546
1563 {
1573 template <class Callable_T>
1574 requires std::invocable<Callable_T&>
1575 explicit nothrow_op (Callable_T&& func);
1576 };
1577
1578#endif // defined(__cpp_exceptions)
1579
1580 // ========================================================================
1581
1592 template <class T>
1593 requires std::is_arithmetic_v<T>
1594 void
1595 append_number (std::string& buffer, T v);
1596
1612 template <class T>
1613 void
1614 append_pointer (std::string& buffer, T* v);
1615
1616 // ========================================================================
1617
1630 template <class T>
1631 concept character = std::is_same_v<std::remove_cv_t<T>, char>
1632 or std::is_same_v<std::remove_cv_t<T>, wchar_t>
1633 or std::is_same_v<std::remove_cv_t<T>, char8_t>
1634 or std::is_same_v<std::remove_cv_t<T>, char16_t>
1635 or std::is_same_v<std::remove_cv_t<T>, char32_t>;
1636
1649 template <class T>
1651 = std::is_pointer_v<T> and character<std::remove_pointer_t<T>>
1652 and not std::is_volatile_v<std::remove_pointer_t<T>>;
1653
1672 template <character Char_T>
1674 {
1681 constexpr explicit basic_c_string (const Char_T* str) noexcept;
1682
1694 constexpr basic_c_string (const Char_T* str,
1695 std::size_t capacity) noexcept;
1696
1705 [[nodiscard]] constexpr std::basic_string_view<Char_T>
1706 view (void) const noexcept;
1707
1716 [[nodiscard]] constexpr bool
1717 is_null (void) const noexcept;
1718
1719 private:
1726 const Char_T* str_;
1727
1734 std::size_t size_;
1735 };
1736
1747
1758 template <character Char_T>
1759 [[nodiscard]] constexpr bool
1761 const basic_c_string<Char_T>& rhs) noexcept;
1762
1777 template <character Char_T>
1778 [[nodiscard]] constexpr bool
1780 const basic_c_string<Char_T>& lhs,
1781 std::type_identity_t<std::basic_string_view<Char_T>> rhs) noexcept;
1782
1791 template <character Char_T>
1792 [[nodiscard]] constexpr bool
1793 operator==(const basic_c_string<Char_T>& lhs, std::nullptr_t) noexcept;
1794
1804 template <character Char_T>
1805 [[nodiscard]] constexpr std::strong_ordering
1807 const basic_c_string<Char_T>& rhs) noexcept;
1808
1818 template <character Char_T>
1819 [[nodiscard]] constexpr std::strong_ordering
1821 const basic_c_string<Char_T>& lhs,
1822 std::type_identity_t<std::basic_string_view<Char_T>> rhs) noexcept;
1823
1844 template <class T>
1846 {
1854 constexpr array_operand (const T* first, std::size_t count) noexcept;
1855
1863 [[nodiscard]] constexpr const T*
1864 begin (void) const noexcept;
1865
1873 [[nodiscard]] constexpr const T*
1874 end (void) const noexcept;
1875
1876 private:
1883 const T* first_;
1884
1891 std::size_t count_;
1892 };
1893
1905 template <class T, class R>
1906 requires (container_like<R>
1907 and std::equality_comparable_with<
1908 T, typename range_element<R>::type>)
1909 [[nodiscard]] constexpr bool
1910 operator== (const array_operand<T>& lhs, const R& rhs);
1911
1922 template <class T, class R>
1923 requires (container_like<R>
1924 and std::three_way_comparable_with<
1925 T, typename range_element<R>::type>)
1926 [[nodiscard]] constexpr auto
1927 operator<=> (const array_operand<T>& lhs, const R& rhs);
1928
1929 // ------------------------------------------------------------------------
1930 } // namespace detail
1931
1932 // --------------------------------------------------------------------------
1933
1934 namespace extension
1935 {
1936 // ------------------------------------------------------------------------
1937 // The expressions of the custom comparators, predicates, and operators.
1938
1939 // The definitions are in `detail`, with the built-in expressions that
1940 // share them; the using-declarations name the same templates, so the
1941 // class template argument deduction applies, and the formatter
1942 // reports them as the built-in ones.
1943
1944 using detail::compare_op;
1946
1947 // ------------------------------------------------------------------------
1948
1966 template <class T>
1968 = std::is_arithmetic_v<detail::unwrapped_t<T>>
1969 and not std::is_same_v<detail::unwrapped_t<T>, bool>
1970 and not std::is_same_v<detail::unwrapped_t<T>, char>
1971 and not std::is_same_v<detail::unwrapped_t<T>, wchar_t>
1972 and not std::is_same_v<detail::unwrapped_t<T>, char8_t>
1973 and not std::is_same_v<detail::unwrapped_t<T>, char16_t>
1974 and not std::is_same_v<detail::unwrapped_t<T>, char32_t>;
1975
1976 // ------------------------------------------------------------------------
1977 } // namespace extension
1978
1979 // --------------------------------------------------------------------------
1980} // namespace micro_os_plus::micro_test_plus
1981
1982#if defined(__GNUC__)
1983#pragma GCC diagnostic pop
1984#endif // defined(__GNUC__)
1985
1986// ----------------------------------------------------------------------------
1987
1988#endif // defined(__cplusplus)
1989
1990// ============================================================================
1991// Templates, inlines & constexpr implementations.
1992
1994
1995// ----------------------------------------------------------------------------
1996
1997#endif // MICRO_OS_PLUS_MICRO_TEST_PLUS_DETAIL_H_
1998
1999// ----------------------------------------------------------------------------

Generated via doxygen2docusaurus 2.2.8 by Doxygen 1.18.0.