简体   繁体   English

获取用 C/C++ 打印的最后一个字符串

[英]Get the last string printed in C/C++

I am trying to create a tester using googletest.我正在尝试使用 googletest 创建测试仪。 the problem is that the function that I am testing is returning void and printing a result instead.问题是我正在测试的函数返回 void 并打印结果。 I want to get the last string printed into the console so I can test the output.我想将最后一个字符串打印到控制台中,以便我可以测试输出。 the string may include \\n .字符串可能包括\\n

so I have the function itself:所以我有这个功能:

void f_sequence(char sequenceStr[])
{
   //logic...
    if(condotion1)
        printf("somthing1");
    else if(condotion2)
        printf("somthing2")
(...)
}

and then the tester:然后是测试人员:

TEST(TesterGroup, TesterName)
{
    f_sequence("input");
    EXPECT_EQ("somthing1", /*how do i get the output?*/);
}

Is it possible?是否可以?

The functions I test are in c, while the Test function itself (the tester) is in c++.我测试的函数在 c 中,而 Test 函数本身(测试器)在 c++ 中。 the output is printed using printf .使用printf打印输出。 I cannot change the function itself.我无法更改功能本身。 I am using CLion latest version.我正在使用 CLion 最新版本。

Redirect the standard output to a buffer.将标准输出重定向到缓冲区。

Live on Coliru 住在 Coliru

#include <stdio.h>
#include <unistd.h>

#define BUFFER_SIZE 1024
int stdoutSave;
char outputBuffer[BUFFER_SIZE];

void replaceStdout()
{
    fflush(stdout); //clean everything first
    stdoutSave = dup(STDOUT_FILENO); //save the stdout state
    freopen("NUL", "a", stdout); //redirect stdout to null pointer
    setvbuf(stdout, outputBuffer, _IOFBF, 1024); //set buffer to stdout
}

void restoreStdout()
{
    freopen("NUL", "a", stdout); //redirect stdout to null again
    dup2(stdoutSave, STDOUT_FILENO); //restore the previous state of stdout
    setvbuf(stdout, NULL, _IONBF, BUFFER_SIZE); //disable buffer to print to screen instantly
}

void printHelloWorld()
{
    printf("hello\n");
    printf("world");
}

int main()
{
    replaceStdout();
    printHelloWorld();
    restoreStdout();
    // Use outputBuffer to test EXPECT_EQ("somthing1", outputBuffer);
    printf("Fetched output: (%s)", outputBuffer);
    return 0;
}

References: http://kaskavalci.com/redirecting-stdout-to-array-and-restoring-it-back-in-c/参考资料: http : //kaskavalci.com/redirecting-stdout-to-array-and-restoring-it-back-in-c/

I don't know if it's possible to get what was last printed, but if you control the environment before your test function is called, you can redirect where standard output goes, which lets you write it to a file, which you can then check.我不知道是否有可能获得上次打印的内容,但是如果您调用测试函数之前控制环境,则可以重定向标准输出的位置,这样您就可以将其写入文件,然后您可以检查.

See this old answer which IMO was neglected.请参阅 IMO 被忽略的旧答案 The example from it is modified here:来自它的示例在此处修改:

FILE *fp_old = stdout;  // preserve the original stdout
stdout = fopen("/path/to/file/you/want.txt","w");  // redirect stdout to anywhere you can open
// CALL YOUR FUNCTION UNDER TEST HERE
fclose(stdout);  // Close the file with the output contents
stdout=fp_old;  // restore stdout to normal

// Re-open the file from above, and read it to make sure it contains what you expect.

Two ways:两种方式:

If you're on a POSIX compatibile system, you can redirect the output of the program to a file using > , then read from the file later to confirm that the output is correct.如果您使用的是 POSIX 兼容系统,则可以使用>将程序的输出重定向到文件,然后稍后从文件中读取以确认输出正确。

The other way is something like this:另一种方式是这样的:

freopen("output.txt", "w", stdout);
f_sequence();
freopen("/dev/tty", "w", stdout);

for POSIX compatible systems.适用于 POSIX 兼容系统。 On other platforms you'd need to change the "/dev/tty" to something else.在其他平台上,您需要将"/dev/tty"更改为其他内容。 I'm not aware of a completely portable way to do this.我不知道一种完全可移植的方法来做到这一点。

And then read from output.txt .然后从output.txt读取。 What the above snippet does is change what stdout is, so that it prints to a file instead of the normal stdout.上面的代码片段所做的是改变stdout是什么,以便它打印到一个文件而不是普通的 stdout。

One solution: You can write a separate program that executes the function, and in the unit test, you can execute that program as a sub process and inspect the output.一种解决方案:您可以编写一个单独的程序来执行该函数,并且在单元测试中,您可以将该程序作为子进程执行并检查输出。 This can be done with std::system , but be very careful to not pass any non-constant input to it.这可以通过std::system ,但要非常小心,不要将任何非常量输入传递给它。 You don't want shell injection vulnerability even in a unit test.即使在单元测试中,您也不希望出现 shell 注入漏洞。 System specific functions exist that avoid the use of shell in the subprocess.存在避免在子进程中使用 shell 的系统特定功能。

Another solution, which is possible at least on POSIX: Replace the the standard out / err streams with file descriptors, and read the files afterwards.另一个解决方案,至少在 POSIX 上是可能的:用文件描述符替换标准输出/错误流,然后读取文件。

Googletest specific: There seems to be testing::internal::CaptureStdout , which appears to implement the idea of replacing standard streams. Googletest 具体:似乎有testing::internal::CaptureStdout ,它似乎实现了替换标准流的想法。 But as the namespace implies, this is not official API, so may change in future.但正如命名空间所暗示的那样,这不是官方 API,因此将来可能会发生变化。

There is a solution ( in C ) for an API call ( cmd_rsp ) with source code here , that when called in your program, creates a separate process, and pipes to both stdin and stdout , from which it accepts a command and returns the response via an auto sizing buffer.有一个 API 调用 ( cmd_rsp ) 的解决方案(在C带有源代码here ,当在您的程序中调用时,它会创建一个单独的进程,并通过管道连接到stdinstdout ,从中它接受命令并返回响应通过自动调整大小缓冲区。 Similar in concept to popen(...) .在概念上类似于popen(...)

A simple use case:一个简单的用例:

char *buf = NULL;

/// test cmd_rsp
buf = calloc(BUF_SIZE, 1);
if(!buf)return 0;
if (!cmd_rsp("dir /s", &buf, BUF_SIZE))//note the first argument can be any legal command that 
                                       //can be sent via the CMD prompt in windows, 
                                       //including a custom executable
{
    printf("%s", buf);
}
else
{
    printf("failed to send command.\n");
}
free(buf);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM