Riddle #6: Po**t

Focus is on a routine calculating a midpoint. Tests for other code is out of scope.

```
#include <gtest/gtest.h>
struct Point {
int x, y;
};
bool operator==(const Point& lhs, const Point& rhs) {
return (lhs.x == rhs.x) && (lhs.y == rhs.y);
}
// assume Point and its operator== have sufficient test coverage
Point midpoint(const Point& topLeft, const Point& bottomRight) {
return Point{
(topLeft.x + bottomRight.x) / 2,
(topLeft.y + bottomRight.y) / 2};
}
TEST(PointTest, midpoint) {
const Point topLeft{10, 20};
const Point bottomRight{30, 40};
EXPECT_EQ((Point{20, 30}), midpoint(topLeft, bottomRight));
}
```

```
#include <gtest/gtest.h>
#include <ostream>
struct Point {
int x, y;
};
bool operator==(const Point& lhs, const Point& rhs) {
return (lhs.x == rhs.x) && (lhs.y == rhs.y);
}
// assume Point and its operator== have sufficient test coverage
std::ostream& operator<<(std::ostream& os, const Point& p) {
if (!os) return os;
return os << "Point[x=" << p.x << ",y=" << p.y << ']';
}
Point midpoint(const Point& topLeft, const Point& bottomRight) {
return Point{
(topLeft.x + topLeft.x) / 2,
(bottomRight.y + bottomRight.y) / 2};
}
TEST(PointTest, midpoint) {
const Point topLeft{10, 20};
const Point bottomRight{30, 40};
EXPECT_EQ((Point{20, 30}), midpoint(topLeft, bottomRight));
}
```

```
#include <gtest/gtest.h>
struct Point {
int x, y;
};
bool operator==(const Point& lhs, const Point& rhs) {
return (lhs.x == rhs.x) && (lhs.y == rhs.y);
}
// assume Point and its operator== have sufficient test coverage
Point midpoint(const Point& topLeft, const Point& bottomRight) {
return Point{
(topLeft.x + topLeft.x) / 2,
(bottomRight.y + bottomRight.y) / 2};
}
TEST(PointTest, midpoint) {
const Point topLeft{10, 20};
const Point bottomRight{30, 40};
EXPECT_EQ((Point{20, 30}), midpoint(topLeft, bottomRight));
}
```

Can you spot a weakness in the test?

Give me a hint

What will happen in case of a test failure? Show me

Reveal the answer

Diagnosis

If the expectation fails, GTest will try to give as much information as it can. It will describe the entities that were expected to be equal:

[ RUN ] PointTest.midpoint
test.cpp:22: Failure
Expected equality of these values:
(Point{20, 30})
Which is: 8-byte object <14-00 00-00 1E-00 00-00>
midpoint(topLeft, bottomRight)
Which is: 8-byte object <0A-00 00-00 28-00 00-00>
[ FAILED ] PointTest.midpoint (1 ms)

In this simple case, the printed byte values still map to actual data in a pretty straightforward manner. However, in a more general case (struct having strings, optionals or pointers), such feedback is little helpful in diagnosing a failed test and one is forced to employ a debugger. We can't, however, blame GTest here, it can't do any better.Reveal the remedy

Remedy

We can help GTest by adding the operator<< for the Point struct. Show me

Now the feedback from a failing test is a bit more helpful:

Now the feedback from a failing test is a bit more helpful:

[ RUN ] PointTest.midpoint
test.cpp:27: Failure
Expected equality of these values:
(Point{20, 30})
Which is: Point[x=20,y=30]
midpoint(topLeft, bottomRight)
Which is: Point[x=10,y=40]
[ FAILED ] PointTest.midpoint (0 ms)

With such setup we receive more information from a failed test practically for free. It is often worth investing a moment in the output operator for your structs and even considering to place it in the production code, as next to enriching the test feedback it may also prove helpful in e.g. log statements.Feedback on this riddle?