I'm writing test for my class using Catch2 (single header file version catch.hpp
). My class output some text into std::cout
, and I cannot change this behavior. I need to retrieve output from std::cout
for comparison. To do this, I redirect std::cout
into std::ostringstream
like this:
auto stdoutBuffer = std::cout.rdbuf();
std::ostringstream oss;
std::cout.rdbuf(oss.rdbuf());
Now I am able to compare content of oss
with oss.str()
.
But when some REQUIRE()
fails, I get an exception Access violation reading location 0xFFFFFFFFFFFFFFFF
in TestRegistry
catch class
However, if all the checks were successful, when no assertion was failed, then no exception will be thrown
Catch allows to use CATCH_CONFIG_NOSTDOUT
to override the functions cout()
, cerr()
and clog()
. But examples that I have seen for their implementation (like this https://github.com/catchorg/Catch2/blob/devel/examples/231-Cfg-OutputStreams.cpp) look superfluous for the original problem. Are there any other ways to solve it?
Solution from avred
is good, but it is a good practice to provide helper function which will make this easier to use. This will also make test easier to read.
#include "catch2/catch_all.hpp"
#include <iostream>
#include <sstream>
void foo()
{
std::cout << "foo";
}
class AutoRestoreRdbuf {
std::ostream& out;
std::streambuf* old;
public:
~AutoRestoreRdbuf()
{
out.rdbuf(old);
}
AutoRestoreRdbuf(const AutoRestoreRdbuf&) = delete;
AutoRestoreRdbuf(AutoRestoreRdbuf&&) = delete;
AutoRestoreRdbuf(std::ostream& out)
: out { out }
, old { out.rdbuf() }
{
}
};
std::string stringWrittentToStream(std::function<void()> f, std::ostream& out = std::cout)
{
AutoRestoreRdbuf restore { std::cout };
std::ostringstream oss;
std::cout.rdbuf(oss.rdbuf());
f();
return oss.str();
}
TEST_CASE("Foo")
{
auto s = stringWrittentToStream(&foo);
REQUIRE(s == "foo1");
}