Redirect both cout and stdout to a string in C++ for Unit Testing

18,607

Solution 1

std::stringstream may be what you're looking for.

UPDATE
Alright, this is a bit of hack, but maybe you could do this to grab the printf output:

char huge_string_buf[MASSIVE_SIZE];
freopen("NUL", "a", stdout);
setbuf(stdout, huge_string_buffer);

Note you should use "/dev/null" for linux instead of "NUL". That will rapidly start to fill up huge_string_buffer. If you want to be able to continue redirecting output after the buffer is full you'll have to call fflush(), otherwise it will throw an error. See std::setbuf for more info.

Solution 2

You can use freopen(..., stdout) and then dump the file into memory or a std::string.

Solution 3

This may be an alternative:

char bigOutBuf[8192];
char savBuf[8192];

fflush(stdout);
setvbuf(stdout,bigOutBuf,IOFBF,8192);//stdout uses your buffer

//after each operation
strncpy(savBuf,bigOutBuf,8192);//won't flush until full or fflush called

//...

//at long last finished
setbuf(stdout,NULL);//reset to unnamed buffer

This just intercepts the buffered output, so still goes to console or wherever.

Hope this helps.

Share:
18,607
thelsdj
Author by

thelsdj

C# business logic programmer by day, electronic music and science fiction fan by night

Updated on June 03, 2022

Comments

  • thelsdj
    thelsdj about 2 years

    I'm working on getting some legacy code under unit tests and sometimes the only way to sense an existing program behavior is from the console output.

    I see lots of examples online for how to redirect stdout to another file in C++, but is there a way I can redirect it to an in-memory stream so my tests don't have to rely on the disk?

    I'd like to get anything that the legacy code sends to stdout into a std::string so I can easily .find on the output.

    Edit

    The legacy code is so bad that it users a mixture of cout << .. and printf. Here is what I have so far:

    void TestSuite::setUp(void)
    {
        oldStdoutBuf = std::cout.rdbuf();
        std::cout.rdbuf(consoleOutput.rdbuf());
    }
    void TestSuite::tearDown(void)
    {
        std::cout.rdbuf(oldStdoutBuf);
    }
    

    The problem is that this does not capture output using printf. I would like something that gets both. Any ideas?

  • thelsdj
    thelsdj almost 15 years
    I would really like to skip having to use the filesystem. Something that only uses ram would be best.
  • thelsdj
    thelsdj almost 15 years
    Accepted your answer as stringstream was good pointer and your UPDATE is about as far as we will probably get without writing some hugely massive convoluted mess, for now I think I'll just write to a file and hopefully I won't need the printf output for many tests.
  • Martze
    Martze over 9 years
    Works well, but if i use multiple unit tests, some fail with an exception because the buffer is already freed and stdout is written into it. In case of only a temporarly redirection into the buffer use a setbuf(stdout, NULL); at the end of the usage.
  • rraallvv
    rraallvv over 8 years
    I want to suppress the console output entirely, keeping just the captured buffer is it possible?
  • sigy
    sigy over 7 years
    See this answer to avoid the "NUL"-Hack on POSIX systems: stackoverflow.com/a/19499003/1557062