NUnit 不捕获 std::cerr 的输出

发布于 2024-08-26 15:51:12 字数 241 浏览 3 评论 0原文

我有一个 C# 中的 nunit 测试,它调用 C++ DLL 中函数的 C# 包装器。 C++ 代码使用 std::cerr 输出各种消息。

无法使用 nunit-console /out /err 或 /xml 开关重定向这些消息。 在 nunit(GUI 版本)中,输出不会出现在任何地方。

我希望能够在 nunit (GUI 版本)中看到这个输出。 理想情况下,我希望能够在测试中访问此输出。

感谢您的任何帮助。

I have an nunit Test 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

灼疼热情 2024-09-02 15:51:12

重定向 std::cerr 就是用您自己的流缓冲区替换流缓冲区。
在退出之前恢复原始缓冲区非常重要。我不知道你的包装器是什么样的,但你可能可以弄清楚如何让它读取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;
}

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;
}
说不完的你爱 2024-09-02 15:51:12

谢谢你的提示。
这就是我最终所做的:

.CPP 文件 ------------------------

#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 文件 ------------ ------------------------------

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]
    // [Ignore]
    public void TestRedirect()
    {
        Redirector.Redirect();
        // Call more functions that output to std::cerr here.
        Redirector.Revert();
        System.Console.WriteLine(Redirector.GetCerr());
    }

freeCharPtr() 的东西对于从 _strdup() 释放分配的内存是必要的,因为我无法弄清楚(如果可能的话)如何封送 std::string。

注意:这不是线程安全的!

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!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文