micro-test-plus 6.0.0
µTest++ Testing Framework
Loading...
Searching...
No Matches
Function comparators

Functions for comparing actual and expected values in tests. More...

Functions

template<class Lhs_T, class Rhs_T, class Epsilon_T>
requires (extension::approx_operand<Lhs_T> and extension::approx_operand<Rhs_T> and extension::approx_operand<Epsilon_T>)
constexpr auto micro_os_plus::micro_test_plus::approx (Lhs_T &&lhs, Rhs_T &&rhs, Epsilon_T &&epsilon)
 Approximate equality comparator, with an explicit tolerance.
template<class Lhs_T, class Rhs_T>
requires detail::comparable_operands<detail::comparison::equal, Lhs_T, Rhs_T>
constexpr auto micro_os_plus::micro_test_plus::eq (Lhs_T &&lhs, Rhs_T &&rhs)
 Generic equality comparator.
template<class Lhs_T, class Rhs_T>
requires detail::comparable_operands<detail::comparison::greater_equal, Lhs_T, Rhs_T>
constexpr auto micro_os_plus::micro_test_plus::ge (Lhs_T &&lhs, Rhs_T &&rhs)
 Generic greater than or equal comparator.
template<class Lhs_T, class Rhs_T>
requires detail::comparable_operands<detail::comparison::greater, Lhs_T, Rhs_T>
constexpr auto micro_os_plus::micro_test_plus::gt (Lhs_T &&lhs, Rhs_T &&rhs)
 Generic greater than comparator.
template<class Lhs_T, class Rhs_T>
requires detail::comparable_operands<detail::comparison::less_equal, Lhs_T, Rhs_T>
constexpr auto micro_os_plus::micro_test_plus::le (Lhs_T &&lhs, Rhs_T &&rhs)
 Generic less than or equal comparator.
template<class Lhs_T, class Rhs_T>
requires detail::comparable_operands<detail::comparison::less, Lhs_T, Rhs_T>
constexpr auto micro_os_plus::micro_test_plus::lt (Lhs_T &&lhs, Rhs_T &&rhs)
 Generic less than comparator.
template<class Lhs_T, class Rhs_T>
requires detail::comparable_operands<detail::comparison::not_equal, Lhs_T, Rhs_T>
constexpr auto micro_os_plus::micro_test_plus::ne (Lhs_T &&lhs, Rhs_T &&rhs)
 Generic non-equality comparator.

Detailed Description

A check written as a plain boolean, such as t.expect (x == 42), reports only its location when it fails. The function comparators compare two values and, when the check fails, also report both values:

Comparator True when
mt::eq (a, b) a == b
mt::ne (a, b) a != b
mt::lt (a, b) a < b
mt::le (a, b) a <= b
mt::gt (a, b) a > b
mt::ge (a, b) a >= b
mt::approx (a, b, e) a and b differ by at most e
Example
ts.test ("Check various conditions", [] (auto& t) {
t.expect (mt::eq (compute_answer (), 42)) << "answer is 42";
t.expect (mt::ne (compute_answer (), 43)) << "answer is not 43";
t.expect (mt::lt (compute_answer (), 43)) << "answer is < 43";
t.expect (mt::le (compute_answer (), 43)) << "answer is <= 43";
t.expect (mt::gt (compute_answer (), 41)) << "answer is > 41";
t.expect (mt::ge (compute_answer (), 42)) << "answer is >= 42";
});

When compute_answer() returns 41, the human-readable reporter displays the failed checks with the compared values:

• Check various conditions
✗ answer is 42 FAILED (main.cpp:21, 41 == 42)
✗ answer is > 41 FAILED (main.cpp:25, 41 > 41)
✗ answer is >= 42 FAILED (main.cpp:26, 41 >= 42)
✗ Check various conditions - FAILED (3 checks passed, 3 failed)
How the values are compared
  • The operands must be comparable with the operator of the comparator; for example, mt::eq (a, b) does not compile when a == b would not.
  • Integers of different signedness are compared by value, as by std::cmp_equal(): mt::eq (-1, static_cast<unsigned> (-1)) fails, although -1 == static_cast<unsigned> (-1) is true. The single characters (char, wchar_t, char8_t, char16_t, and char32_t) are compared in the same way, as the integers of the same size and signedness.
  • C strings (the arrays, including the string literals, and the pointers of char, wchar_t, char8_t, char16_t, and char32_t) are compared by content, also with the standard strings and string views of the same character type, so mt::eq (actual, "abc") checks the characters, not the addresses. The text of an array ends at its first null character, or at its end. A null pointer is equal only to another null pointer (or nullptr), not to an empty string.
  • Other arrays (including uint8_t buffers) are compared element by element, also with a container, with the elements compared as the single values are.
  • Other pointers are compared by address.
  • The application types need an operator<< for the formatter, which writes their values in the report; without it, the comparator does not compile. See Customisation.
Cost and lifetime of the operands
A comparator moves the temporaries into the expression that it returns, and copies the named operands, for every check, passing or failing, so a large container or string costs an allocation; compare a std::string_view of the string instead, when the cost matters. Since the expression holds its own copies, it can be returned from the function that builds it, and kept after the operands are destroyed. The exceptions are the arrays and the characters of the C strings, which are only referred to and must outlive the expression.
Comparing approximately
The comparison of floating-point values with eq() is exact, so mt::eq (0.1 + 0.2, 0.3) fails. To accept a difference, use mt::approx (a, b, epsilon), which is true when the operands differ by at most epsilon, the limit included (for floating-point values, the distance is computed and rounded, so a distance that should be equal to a decimal limit, such as mt::approx (1.0, 1.1, 0.1), may be slightly above it and fail; do not rely on the exact limit):
  • the operands and the tolerance are integral or floating-point numbers, of any such type, except bool and the character types (char, wchar_t, char8_t, char16_t, and char32_t), which are not numbers and are rejected; signed char and unsigned char are accepted. The distance of integers is computed exactly, also for operands of different signedness;
  • a negative tolerance fails all the comparisons;
  • a failed check shows the operands and the tolerance, as in 1.0 ~ (1.5 +/- 0.1).
ts.test ("Check approximate values", [] (auto& t) {
t.expect (mt::approx (read_adc (), 512, 3)) << "ADC reading";
t.expect (mt::approx (compute_float (), 42.0f, 0.001f))
<< "result is about 42";
});
Comparing containers
Containers are compared with their own operators, so they must be comparable, usually by being of the same type. When the check fails, the elements of both containers are shown, up to the first 16; when two longer containers differ after them, the report adds the index of the first difference.
ts.test ("Check containers", [] (auto& t) {
t.expect (mt::eq (std::vector<int>{ 1, 2 }, std::vector<int>{ 1, 2 }))
<< "vector{ 1, 2 } eq vector{ 1, 2 }";
t.expect (mt::ne (std::vector<int>{ 1, 2, 3 },
std::vector<int>{ 1, 2, 4 }))
<< "vector{ 1, 2, 3 } ne vector{ 1, 2, 4 }";
});

Function Documentation

◆ approx()

template<class Lhs_T, class Rhs_T, class Epsilon_T>
requires (extension::approx_operand<Lhs_T> and extension::approx_operand<Rhs_T> and extension::approx_operand<Epsilon_T>)
auto micro_os_plus::micro_test_plus::approx ( Lhs_T && lhs,
Rhs_T && rhs,
Epsilon_T && epsilon )
nodiscardconstexpr

The comparison succeeds if the distance between lhs and rhs is less than or equal to epsilon, so a tolerance of zero requires equal values. The operands are numbers, integral or floating-point, possibly of different types (the deprecated value wrappers and numeric literals are also accepted, and their own tolerance is not used). For the integers, the distance is computed exactly, also for operands of different signedness, so approx (0u, -1, 2) succeeds; for the other types, in their common floating-point type. A failure is reported as lhs ~ (rhs +/- epsilon).

t.expect (mt::approx (read_adc (), 512, 3)) << "ADC reading";
t.expect (mt::approx (compute_float (), 42.0f, 0.001f));

The deprecated approx (value, epsilon) form, available only with MICRO_OS_PLUS_MICRO_TEST_PLUS_DEPRECATED_ENABLED, is a value wrapper instead, which applies its tolerance to the six comparisons and to the operators; it accepts only floating-point values.

Template Parameters
Lhs_TType of the left hand side operand.
Rhs_TType of the right hand side operand.
Epsilon_TType of the tolerance.
Parameters
lhsLeft hand side operand.
rhsRight hand side operand.
epsilonThe tolerance; a negative one fails all comparisons.
Returns
A comparator object that evaluates to true if lhs and rhs differ by at most epsilon.
Since
6.0.0

The approx function template constructs a detail::approx_op from the forwarded operands and tolerance; the operands are numbers, so detail::as_operand(), which converts the C strings, is not needed.

Definition at line 306 of file function-comparators-inlines.h.

307 {
308 return detail::approx_op{ std::forward<Lhs_T> (lhs),
309 std::forward<Rhs_T> (rhs),
310 std::forward<Epsilon_T> (epsilon) };
311 }
Approximate comparator struct template.
Definition detail.h:1003

References approx().

◆ eq()

template<class Lhs_T, class Rhs_T>
requires detail::comparable_operands<detail::comparison::equal, Lhs_T, Rhs_T>
auto micro_os_plus::micro_test_plus::eq ( Lhs_T && lhs,
Rhs_T && rhs )
nodiscardconstexpr

The C strings (the arrays, including the string literals, and the pointers of char, wchar_t, char8_t, char16_t, and char32_t) are compared by content, also with the standard strings and string views of the same character type; a null pointer is equal only to another null pointer, and the text of an array ends at its first null character, or at its end. The other arrays (e.g. byte buffers) are compared element by element, also with a container, with the elements compared as the single values are, and written as ranges; the other pointers are compared by address. The integers of different signedness are compared by value, as by std::cmp_equal(), not after the usual arithmetic conversions, so eq (-1, static_cast<unsigned> (-1)) fails; the single characters take part as the integers of the same size and signedness.

Both operands must satisfy extension::printable, since they are reported on failure; an application type needs an operator<< for mt::expression_formatter, otherwise the call is rejected, with a diagnostic that names the operand type. The operands must also be comparable with the operator of the comparator, otherwise the call is rejected in the same way.

The same rules apply to ne(), gt(), ge(), lt(), and le().

Template Parameters
Lhs_TType of the left hand side operand.
Rhs_TType of the right hand side operand.
Parameters
lhsLeft hand side operand.
rhsRight hand side operand.
Returns
A comparator object that evaluates to true if the operands are equal.

The eq function template provides a generic equality comparator for any types. The operands are first passed to detail::as_operand(), which converts the C strings to detail::basic_c_string, and the other arrays to detail::array_operand, so that they are compared by content. It constructs a comparator object, with the detail::equal_to tag, which evaluates to true if the two values are equal, and which is reported with both values if not.

The operands are forwarded, so that the comparator moves the temporaries, and copies the named operands (see stored_operand_t), so that the expression stays valid after the operands are destroyed, except for the arrays and the C strings, which are referred to.

Definition at line 89 of file function-comparators-inlines.h.

90 {
91 return detail::compare_op{ detail::as_operand (std::forward<Lhs_T> (lhs)),
92 detail::as_operand (std::forward<Rhs_T> (rhs)),
94 }
constexpr auto as_operand(T &&t) noexcept -> decltype(auto)
Prepares an operand of a comparator.
Relational comparator struct template.
Definition detail.h:887

References micro_os_plus::micro_test_plus::detail::as_operand(), and eq().

Referenced by eq().

◆ ge()

template<class Lhs_T, class Rhs_T>
requires detail::comparable_operands<detail::comparison::greater_equal, Lhs_T, Rhs_T>
auto micro_os_plus::micro_test_plus::ge ( Lhs_T && lhs,
Rhs_T && rhs )
nodiscardconstexpr
Template Parameters
Lhs_TType of the left hand side operand.
Rhs_TType of the right hand side operand.
Parameters
lhsLeft hand side operand.
rhsRight hand side operand.
Returns
A comparator object that evaluates to true if lhs is greater than or equal to rhs.

The operands are passed to detail::as_operand(), as for eq(), so that the C strings and the arrays are compared by content. It constructs a comparator object, with the detail::greater_equal tag, which evaluates to true if lhs is greater than or equal to rhs, and which is reported with both values if not.

Definition at line 197 of file function-comparators-inlines.h.

198 {
199 return detail::compare_op{ detail::as_operand (std::forward<Lhs_T> (lhs)),
200 detail::as_operand (std::forward<Rhs_T> (rhs)),
202 }
Greater than or equal tag for compare_op.
Definition detail.h:619

References micro_os_plus::micro_test_plus::detail::as_operand(), and ge().

Referenced by ge().

◆ gt()

template<class Lhs_T, class Rhs_T>
requires detail::comparable_operands<detail::comparison::greater, Lhs_T, Rhs_T>
auto micro_os_plus::micro_test_plus::gt ( Lhs_T && lhs,
Rhs_T && rhs )
nodiscardconstexpr
Template Parameters
Lhs_TType of the left hand side operand.
Rhs_TType of the right hand side operand.
Parameters
lhsLeft hand side operand.
rhsRight hand side operand.
Returns
A comparator object that evaluates to true if lhs is greater than rhs.

The operands are passed to detail::as_operand(), as for eq(), so that the C strings and the arrays are compared by content. It constructs a comparator object, with the detail::greater tag, which evaluates to true if lhs is greater than rhs, and which is reported with both values if not.

Definition at line 161 of file function-comparators-inlines.h.

162 {
163 return detail::compare_op{ detail::as_operand (std::forward<Lhs_T> (lhs)),
164 detail::as_operand (std::forward<Rhs_T> (rhs)),
165 detail::greater{} };
166 }
Greater than tag for compare_op.
Definition detail.h:560

References micro_os_plus::micro_test_plus::detail::as_operand(), and gt().

Referenced by gt().

◆ le()

template<class Lhs_T, class Rhs_T>
requires detail::comparable_operands<detail::comparison::less_equal, Lhs_T, Rhs_T>
auto micro_os_plus::micro_test_plus::le ( Lhs_T && lhs,
Rhs_T && rhs )
nodiscardconstexpr
Template Parameters
Lhs_TType of the left hand side operand.
Rhs_TType of the right hand side operand.
Parameters
lhsLeft hand side operand.
rhsRight hand side operand.
Returns
A comparator object that evaluates to true if lhs is less than or equal to rhs.

The operands are passed to detail::as_operand(), as for eq(), so that the C strings and the arrays are compared by content. It constructs a comparator object, with the detail::less_equal tag, which evaluates to true if lhs is less than or equal to rhs, and which is reported with both values if not.

Definition at line 270 of file function-comparators-inlines.h.

271 {
272 return detail::compare_op{ detail::as_operand (std::forward<Lhs_T> (lhs)),
273 detail::as_operand (std::forward<Rhs_T> (rhs)),
275 }
Less than or equal tag for compare_op.
Definition detail.h:737

References micro_os_plus::micro_test_plus::detail::as_operand(), and le().

Referenced by le().

◆ lt()

template<class Lhs_T, class Rhs_T>
requires detail::comparable_operands<detail::comparison::less, Lhs_T, Rhs_T>
auto micro_os_plus::micro_test_plus::lt ( Lhs_T && lhs,
Rhs_T && rhs )
nodiscardconstexpr
Template Parameters
Lhs_TType of the left hand side operand.
Rhs_TType of the right hand side operand.
Parameters
lhsLeft hand side operand.
rhsRight hand side operand.
Returns
A comparator object that evaluates to true if lhs is less than rhs.

The operands are passed to detail::as_operand(), as for eq(), so that the C strings and the arrays are compared by content. It constructs a comparator object, with the detail::less tag, which evaluates to true if lhs is less than rhs, and which is reported with both values if not.

Definition at line 234 of file function-comparators-inlines.h.

235 {
236 return detail::compare_op{ detail::as_operand (std::forward<Lhs_T> (lhs)),
237 detail::as_operand (std::forward<Rhs_T> (rhs)),
238 detail::less{} };
239 }
Less than tag for compare_op.
Definition detail.h:678

References micro_os_plus::micro_test_plus::detail::as_operand(), and lt().

Referenced by lt().

◆ ne()

template<class Lhs_T, class Rhs_T>
requires detail::comparable_operands<detail::comparison::not_equal, Lhs_T, Rhs_T>
auto micro_os_plus::micro_test_plus::ne ( Lhs_T && lhs,
Rhs_T && rhs )
nodiscardconstexpr
Template Parameters
Lhs_TType of the left hand side operand.
Rhs_TType of the right hand side operand.
Parameters
lhsLeft hand side operand.
rhsRight hand side operand.
Returns
A comparator object that evaluates to true if the operands are not equal.

The operands are passed to detail::as_operand(), as for eq(), so that the C strings and the arrays are compared by content. It constructs a comparator object, with the detail::not_equal_to tag, which evaluates to true if the two values are not equal, and which is reported with both values if not.

Definition at line 125 of file function-comparators-inlines.h.

126 {
127 return detail::compare_op{ detail::as_operand (std::forward<Lhs_T> (lhs)),
128 detail::as_operand (std::forward<Rhs_T> (rhs)),
130 }
Non-equality tag for compare_op.
Definition detail.h:501

References micro_os_plus::micro_test_plus::detail::as_operand(), and ne().

Referenced by ne().