I have an nunit Tes开发者_Go百科t in C#, that calls a C# wrapper of a function in a C++ DLL. The C++ code uses std::cerr to output various messages.
These messages cannot be redirected using nunit-console /out /err or /xml switch. In nunit (the GUI version) the output does not appear anywhere.
I would like to be able to see this output in nunit (GUI version). Ideally I would like to be able to access this output in the Test.
Thanks for any help.
Redirecting std::cerr is a matter of replacing the stream buffer with your own. It is important to restore in original buffer before we exit. I don't know what your wrapper looks like, but you can probably figure out how to make it read output.str().
#include <iostream>
#include <sstream>
#include <cassert>
using namespace std;
int main()
{
streambuf* buf(cerr.rdbuf());
stringstream output;
cerr.rdbuf(output.rdbuf());
cerr << "Hello, world!" << endl;
assert(output.str() == "Hello, world!\n");
cerr.rdbuf(buf);
return 0;
}
Thanks for the hint. This is what I ended up doing:
.CPP file ------------------------
#include <iostream>
#include <sstream>
static std::stringstream buffer;
static std::streambuf * savedBuffer = NULL;
extern "C" __declspec(dllexport) bool Redirect()
{
if (savedBuffer)
{
return false;
}
std::streambuf * buf(std::cerr.rdbuf());
std::cerr.rdbuf(buffer.rdbuf());
// This two lines are for illustration purposes only!
std::cerr << "Hello world" << std::endl;
return true;
}
extern "C" __declspec(dllexport) void Revert()
{
if (savedBuffer)
{
std::cerr.rdbuf(savedBuffer);
}
savedBuffer = NULL;
}
extern "C" __declspec(dllexport) const char * getCerr()
{
return _strdup(buffer.str().c_str());
}
extern "C" __declspec(dllexport) void freeCharPtr(char *ptr)
{
free(ptr);
}
.CS file ------------------------------------------
public static class Redirector
{
// PRIVATE ------------------------------------------------------------
private const String LibraryName = "MyCpp.dll";
[DllImport(LibraryName, CharSet = CharSet.Ansi)]
private static extern IntPtr getCerr();
// PUBLIC -------------------------------------------------------------
[DllImport(LibraryName, CharSet = CharSet.Ansi)]
public static extern bool Redirect();
[DllImport(LibraryName, CharSet = CharSet.Ansi)]
public static extern void Revert();
[DllImport(LibraryName, CharSet = CharSet.Ansi)]
internal static extern void freeCharPtr(IntPtr ptr);
public static string GetCerr()
{
IntPtr temp = getCerr();
string result = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(temp);
freeCharPtr(temp);
return result;
}
}
NUnit Test -----------------------
[Test]
// [Ignore]
public void TestRedirect()
{
Redirector.Redirect();
// Call more functions that output to std::cerr here.
Redirector.Revert();
System.Console.WriteLine(Redirector.GetCerr());
}
The freeCharPtr() stuff is necessary to free the allocated memory from _strdup(), since I could not work out (if it's even possible) how to marshal an std::string.
Note: This is not thread safe!
精彩评论