我在寻找什么
像stream一样的管道,用std :: ostream连接std :: istream。我应该能够写一些东西到std :: ostream部分,然后从std :: istream部分读取它。在istream部分调用std :: getline()时,它应该阻塞,直到来自std :: ostream部分的数据可用。
std :: stringstream完全符合我的要求,除非它没有阻止。在空的std :: stringstream上调用std :: getline()时,它只返回并设置eof()标志。
为什么我需要这个
为了测试使用流进行输入/输出的Console类,我需要对应的对象来读取Console类的输出并为其生成输入。 std :: cin上的std :: getline()是阻塞的,所以如果管道流为空,管道流也应该阻塞。
详情
我有一个 Console 类,用于处理控制台输入和输出。简化版本就像
class Console {
public:
Console(): Console(std::cin, std::cout) {}
Console(istream &istr, ostream &ostr): _istr(istr), _ostr(ostr) {}
string ask(const string &question) {
_ostr << question << "\n";
string answer;
std::getline(_istr, answer);
return answer;
}
private:
istream &_istr;
ostream &_ostr;
};
在生产中,_istr将设置为std :: cin,_ostr将设置为std :: cout。 在测试用例中,我将它们设置为拥有内存中的流类。
为此,我想使用std :: stringstream,因为我可以用
测试输出void EXPECT_OUTPUT_LINE(const string &expected) {
string actual;
std::getline(ostr, actual);
EXPECT_EQ(expected, actual);
}
并使用
发送输入void sendInputLine(const string &line) {
istr << line << "\n";
}
在这种情况下, Console 类在不同的线程中运行,因为它在尝试从_istr读取时应该阻塞其线程。 一般的测试用例看起来像
TEST(ConsoleTest, MyTest) {
stringstream istr, ostr;
future<string> answer = std::async(std::launch::async, [&] () {
Console(ostr, istr).ask("Question?");
});
EXPECT_OUTPUT_LINE("Question?");
sendInputLine("Answer");
EXPECT_EQ("Answer", answer.get());
}
然而,结果是std :: getline()没有阻塞。当与std :: cin一起使用时,它会阻塞。当与空的std :: stringstream一起使用时,std :: getline会立即返回并设置eof标志。
因此,即使我的测试用例说明了sendInputLine(“bla”),这也没有任何效果,因为Console类不会等待它,并且它的std :: getline()调用可能已经返回了过去的空串流。
同样的问题出在EXPECT_OUTPUT_LINE中。它调用std :: getline来获取Console类的输出,但它不会等待它。如果在Console类实际产生任何输出之前发生这种情况,那么它只返回并设置字符串流的eof标志。