Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to use redirected std::cout in Catch2

Tags:

c++

catch2

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?

like image 307
pklgn Avatar asked Oct 19 '25 12:10

pklgn


1 Answers

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");
}

https://godbolt.org/z/3877s5K56

like image 132
Marek R Avatar answered Oct 21 '25 02:10

Marek R



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!