Reputation: 5714
I like to use catch for my c++ unit tests.
My goal is to compare std::array
and std::vector
. I created the this failing example.
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
TEST_CASE("Vector") {
std::vector<double> direction = {0.1, 0.3, 0.4};
std::vector<double> false_direction = {0.1, 0.0, 0.4};
REQUIRE(direction == false_direction);
}
TEST_CASE("Array") {
std::array<double, 3> direction = {0.1, 0.3, 0.4};
std::array<double, 3> false_direction = {0.1, 0.0, 0.4};
REQUIRE(direction == false_direction);
}
The output of this test is for the check of std::vector
REQUIRE( direction == false_direction ) with expansion: { 0.1, 0.3, 0.4 } == { 0.1, 0.0, 0.4 }
and for std::array
REQUIRE( direction == false_direction ) with expansion: {?} == {?}
What can I do to display the actual and expected value? I like to have the very same display in a violated REQUIRE
condition for std::array
as for std::vector
.
I use the latest version of catch (v1.10.0).
Upvotes: 4
Views: 4180
Reputation: 3560
Fundamentally this is a question of how a type is stringified, and for that there is always the documentation.
The abridged version is that there is a simple algorithm
Check for specialization of Catch::StringMaker
for given type. If exists, use it.
Check for operator<<
overload for given type. If exists, use it.
Use "{?}".
Until recently, Catch provided a specialization for std::vector
out of the box, but not for std::array
, because std::array
was part of C++11 and generally less used. Since version 2.1.0 Catch instead checks whether the type provides a container-like interface, specifically, responds to begin(T)
and end(T)
. This provides an automatic stringification for many different types, including std::vector
, std::array
, but also static arrays.
Upvotes: 4
Reputation: 5714
I traced the problem down the the toString
method within the catch header. It is missing the overload for std::array
, std::vector
has already be instantiated. I will commit this change to the catch project.
// already exists in the catch header
template<typename T, typename Allocator>
std::string toString( std::vector<T,Allocator> const& v ) {
return Detail::rangeToString( v.begin(), v.end() );
}
// my modification in the catch header
template<typename T, std::size_t _Nm>
std::string toString( std::array<T, _Nm> const& v ) {
return Detail::rangeToString( v.begin(), v.end() );
}
Upvotes: 1
Reputation: 8511
I didn't check Catch's source code to see how exactly they implement the REQUIRE
clause, and why it won't work but vector
does.
But here is a workaround:
#define COMPARE_ARRAYS(lhs, rhs) compareArrays(Catch::getResultCapture().getCurrentTestName(), __LINE__, lhs, rhs)
template < typename T, size_t N >
void compareArrays(const std::string & test, unsigned line, std::array<T, N> lhs, std::array<T, N> rhs) {
std::vector<T> lv(lhs.begin(), lhs.end());
std::vector<T> rv(rhs.begin(), rhs.end());
INFO("Test case [" << test << "] failed at line " << line); // Reported only if REQUIRE fails
REQUIRE(lv == rv);
}
TEST_CASE("Array") {
std::array<double, 3> direction = {0.1, 0.3, 0.4};
std::array<double, 3> true_direction = {0.1, 0.3, 0.4};
COMPARE_ARRAYS(direction, true_direction);
std::array<double, 3> false_direction = {0.1, 0.0, 0.4};
COMPARE_ARRAYS(direction, false_direction);
}
Upvotes: 1