Skip to main content

Customisation

Reporting the application types, and writing application comparators. More...

Concepts Index​

conceptany_op

Concept satisfied when at least one of two types is a framework expression type. More...

conceptapprox_operand

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

conceptcheckable

Concept satisfied when a type can be used as a test expression in expect() or require(). More...

conceptcompare_tag

Concept satisfied by a tag that defines a custom comparator. More...

conceptis_op

Concept satisfied when a type is a framework expression type. More...

conceptpredicate_tag

Concept satisfied by a tag that defines a custom predicate. More...

conceptprintable

Concept satisfied when a type can be appended to the message of a check result via operator<<. More...

Typedefs Index​

usingexpression_formatter = detail::expression_formatter

Public name of the formatter used to report operand values. More...

Description​

Reporting the application types, and writing application comparators.

The applications extend the framework in two ways, both with public names only: they teach the formatter to write the values of their own types, and they write their own comparators and predicates, which are reported as the built-in ones.

Application types

The function comparators report the values of their operands when a check fails. The scalars, the strings, the containers, and the scoped enumerations are written by the framework. For any other type, the application provides an operator<< that writes the value to the expression_formatter, declared in the namespace of the type, so that it is found by argument-dependent lookup. Without it, a comparator such as eq() does not compile for that type. The same operator writes the values appended to the messages of the checks.

Application comparators and predicates

A comparator is an expression template, parametrised by a tag of the application: a type with a symbol text, which separates the operands in the report, and a static apply() function, which returns the result. extension::compare_op takes two operands and a tag, and extension::predicate_op takes one operand and a tag. The result is an expression like those returned by eq() and negate(), so it can be combined with all_of(), any_of(), and negate(), and a failed check displays the operands and the symbol.

The concepts of the extension namespace (is_op, any_op, checkable, printable, compare_tag, predicate_tag, and approx_operand) describe the types that these templates and the checks accept; the last one constrains the operands of approx(), for the helpers that forward their operands to it. Only the deprecated floating-point wrappers have a tolerance: with the deprecated definitions enabled, has_epsilon detects them, and a comparator tag may define a static constexpr bool within_tolerance_result, which is the result for the operands that are within the tolerance of such a wrapper; without it, the tolerance is ignored.

Example
 
 namespace app
 {
  struct point
  {
  int x;
  int y;
  };
 
  constexpr bool
  operator== (const point& lhs, const point& rhs)
  {
  return lhs.x == rhs.x && lhs.y == rhs.y;
  }
 
  // Found by argument-dependent lookup.
  inline mt::expression_formatter&
  operator<< (mt::expression_formatter& formatter, const point& p)
  {
  return formatter << "{ " << p.x << ", " << p.y << " }";
  }
 
  struct divides_tag
  {
  static constexpr const char* symbol = " divides ";
 
  template <class Lhs_T, class Rhs_T>
  static constexpr bool
  apply (const Lhs_T& lhs, const Rhs_T& rhs)
  {
  return rhs % lhs == 0;
  }
  };
 
  template <class Lhs_T, class Rhs_T>
  constexpr auto
  divides (const Lhs_T& lhs, const Rhs_T& rhs)
  {
  return mt::extension::compare_op{ lhs, rhs, divides_tag{} };
  }
 } // namespace app
 
 ts.test ("Check points", [] (auto& t) {
  t.expect (mt::eq (app::point{ 1, 2 }, app::point{ 1, 3 })) << "differ";
 });
 
 ts.test ("Check divisors", [] (auto& t) {
  t.expect (app::divides (5, 12)) << "5 divides 12";
 });

The failed checks are reported with the values and the symbol:

 • Check points
  ✗ differ FAILED (main.cpp:75, { 1, 2 } == { 1, 3 })
 • Check divisors
  ✗ 5 divides 12 FAILED (main.cpp:79, 5 divides 12)

A predicate is written in the same way, with a tag that has a symbol and an apply() function of one operand, and the template extension::predicate_op. The report writes the symbol before the operand, so the symbol ends with the space that separates them ("is even "):

 namespace app
 {
  struct is_even_tag
  {
  static constexpr const char* symbol = "is even ";
 
  template <class T>
  static constexpr bool
  apply (const T& value)
  {
  return value % 2 == 0;
  }
  };
 
  template <class T>
  constexpr auto
  is_even (const T& value)
  {
  return mt::extension::predicate_op{ value, is_even_tag{} };
  }
 } // namespace app
 
 ts.test ("Check parity", [] (auto& t) {
  t.expect (app::is_even (3)) << "3 is even";
  t.expect (mt::negate (app::is_even (4))) << "4 is not even";
 });

Both checks fail, and a predicate can be combined with negate(), all_of(), and any_of(), as the comparators are:

 • Check parity
  ✗ 3 is even FAILED (main.cpp:28, is even 3)
  ✗ 4 is not even FAILED (main.cpp:29, not is even 4)

Typedefs​

expression_formatter​

using micro_os_plus::micro_test_plus::expression_formatter = detail::expression_formatter

Public name of the formatter used to report operand values.

The function comparators and the custom operators report the values of their operands when a check fails. Values of user-defined types can be reported only if the application provides an operator<< that writes them to this formatter, declared in the namespace of the type, so that it is found by argument-dependent lookup:

 namespace app
 {
  struct point
  {
  int x;
  int y;
  };
 
  constexpr bool
  operator== (const point& lhs, const point& rhs)
  {
  return lhs.x == rhs.x && lhs.y == rhs.y;
  }
 
  inline mt::expression_formatter&
  operator<< (mt::expression_formatter& formatter, const point& p)
  {
  return formatter << "{ " << p.x << ", " << p.y << " }";
  }
 } // namespace app

Without such an operator, comparators such as eq() do not compile for user-defined types, since the operand values cannot be formatted; only the scoped enumerations are formatted without it, by their underlying value. Plain boolean checks, such as expect (a == b), do not need it, but they report only the source location on failure. The same operator also writes the values appended to the messages of the checks (expect (a == b) << "a is " << a).

Applications use the operator<< overloads, and str() to test their own operators; the functions that manage the buffer are private to the framework.

Definition at line 1824 of file expression-formatter.h.


Generated via doxygen2docusaurus 2.2.8 by Doxygen 1.18.0.