c++catch2

Unable to use redirected std::cout in 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?


Solution

  • 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