In Catch Unit Test v1.8.1, with gcc 6.2.0, I'm trying to conveniently output the contents of a vector when a test fails by passing the vector to INFO(...)
or CAPTURE(...)
. To do so I'm overloading the stream insertion operator:
#include <Catch/single_include/catch.hpp>
#include <vector>
#include <iostream>
#define THIS_WORKS_BUT_EXTENDING_NAMESPACE_STD_IS_ILLEGAL
#ifdef THIS_WORKS_BUT_EXTENDING_NAMESPACE_STD_IS_ILLEGAL
namespace std {
#endif
std::ostream& operator<<( std::ostream& os, const std::vector<int>& v ) {
for ( const auto& e : v ) {
os << e << " ";
}
return os;
}
#ifdef THIS_WORKS_BUT_EXTENDING_NAMESPACE_STD_IS_ILLEGAL
} //namespace std
#endif
int some_operation_on_vector( const std::vector<int>& v ) {
return 1;
}
SCENARIO( "some scenario" )
{
GIVEN( "a vector" )
{
const auto the_vector = std::vector<int>{ 1, 2, 3, 4, 5 };
WHEN( "some result is calculated from the vector" )
{
const auto actual_result = some_operation_on_vector( the_vector );
THEN( "the result should be correct. If not, print out the vector." )
{
const auto expected_result = 0;
CAPTURE( the_vector ); // <--------
//^^^^
//How do I legally make this work?
REQUIRE( expected_result == actual_result );
}
}
}
}
If I (illegally) extend the std
namespace as above, then it works, and I see the desired output:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
catchtestexample is a Catch v1.8.1 host application.
Run with -? for options
-------------------------------------------------------------------------------
Scenario: some scenario
Given: a vector
When: some result is calculated from the vector
Then: the result should be correct. If not, print out the vector.
-------------------------------------------------------------------------------
ExampleTest.cpp:91
...............................................................................
ExampleTest.cpp:95: FAILED:
REQUIRE( expected_result == actual_result )
with expansion:
0 == 1
with message:
the_vector := 1 2 3 4 5
===============================================================================
test cases: 1 | 1 failed
assertions: 1 | 1 failed
But to try to be legal, when I try to move the operator<<
overload out of the std
namespace and into the global namespace (by commenting out #define THIS_WORKS_BUT_EXTENDING_NAMESPACE_STD_IS_ILLEGAL
), the code doesn't compile due to passing a vector to the CAPTURE()
macro.
Per the Catch docs, I tried replacing the operator <<
overload with a Catch::toString
overload:
#include <string>
#include <sstream>
namespace Catch {
std::string toString( const std::vector<int>& v ) {
std::ostringstream ss;
for ( const auto& e : v ) {
ss << e << " ";
}
return ss.str();
}
}
or with a Catch::StringMaker
specialisation:
#include <string>
#include <sstream>
namespace Catch {
template<> struct StringMaker<std::vector<int>> {
static std::string convert( const std::vector<int>& v ) {
std::ostringstream ss;
for ( const auto& e : v ) {
ss << e << " ";
}
return ss.str();
}
};
}
but in either case the test still doesn't compile, due to passing a vector to the CAPTURE()
macro.
The Catch docs say to put the operator<<
overload into the same namespace as your type, but std::vector
is not my type, and putting that overload into namespace std
is illegal.
But the only way I've been able to find to get CAPTURE()
(or INFO()
, or WARN()
, etc.) to accept a std::vector
argument is to illegally put the operator<<
overload into namespace std
.
Is there a proper, legal way to do this?