3

If I run the following test witch Catch

bool eq(int x, int y) {
    return x == y;
}

TEST_CASE("operator vs. function call") {
    int x = 1;
    int y = 2;
    CHECK(x == y);
    CHECK(eq(x, y));
}

I get the following output

/path/to/MyTest.cpp:8: Failure:
  CHECK(x == y)
with expansion:
  1 == 2

/path/to/MyTest.cpp:9: Failure:
  CHECK(eq(x, y))
with expansion:
  false

Why can Catch convert x and y to strings in the operator expression x == y but not in the function call expression eq(x, y)? Is it somehow possible to stringify the function call expression in a similar way to get output like this:

/path/to/MyTest.cpp:9: Failure:
  CHECK(eq(x, y))
with expansion:
  eq(1, 2)
maiermic
  • 4,764
  • 6
  • 38
  • 77

2 Answers2

2

I suspect once CHECK sees eq(x, y) it just sees the result of this function call as an expression.

You can insert a INFO before your CHECK to see the parameters to your function call:

INFO("x:" << x << ", y:" << y);
CHECK(eq(x, y));

which will be logged at the CHECK call (showing "with message"):

  CHECK( eq(x, y) )
with expansion:
  false
with message:
  x:1, y:2
doctorlove
  • 18,872
  • 2
  • 46
  • 62
1

The interesting part is this:

#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
    do { \
        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
        try { \
            CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \
            ( __catchResult <= expr ).endExpression(); \
            CATCH_INTERNAL_UNSUPPRESS_PARENTHESES_WARNINGS \
        } \
        catch( ... ) { \
            __catchResult.useActiveException( resultDisposition ); \
        } \
        INTERNAL_CATCH_REACT( __catchResult ) \
    } while( Catch::isTrue( false && static_cast<bool>( !!(expr) ) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
    // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&.

where expr is x == y or eq(x, y).

How it works for x == y:
__catchResult <= expr results in __catchResult <= x == y which is equivalent to (__catchResult <= x) == y due to the lower precedence of <= compared to == (see C++ operator precedence). __catchResult <= x wraps x in an object with an == operator, which y gets passed to. That's how expr gets destructured. All the rest is easy to imagine.

Why it does not work for eq(x, y):

__catchResult <= expr results in __catchResult <= eq(x, y) and eq(x, y) is evaluated first (no destructuring).

For the same reason it does not work if the expression is surrounded by parentheses. For example, (x == y) would lead to __catchResult <= (x == y) in which case x == y is evaluated first (no destructuring). That's why CHECK((x == y)); causes output

/path/to/MyTest.cpp:8: Failure:
  CHECK((x == y))
with expansion:
  false
maiermic
  • 4,764
  • 6
  • 38
  • 77