强制 fgets 阻止(即伪造“交互式设备”)
Posted
技术标签:
【中文标题】强制 fgets 阻止(即伪造“交互式设备”)【英文标题】:forcing fgets to block (i.e. faking an "interactive device") 【发布时间】:2010-03-03 21:22:29 【问题描述】:我有一个 C 应用程序,它提供了一个用于输入命令的“shell”。我正在尝试为应用程序编写一些自动化测试代码(使用 CUnit)。从标准输入读取“shell”输入,如下所示:
fgets(buf, sizeof(buf), stdin);
我可以通过 freopen()'ning 标准输入将命令自动“写入”到应用程序,并将其连接到中间文件。当应用程序“正常”执行时,fgets() 调用会阻塞,直到字符可用,因为它是“交互式设备”,但在中间文件上则不然。那么我怎样才能假装 fgets 认为中间文件是一个“交互式设备”。
C 程序适用于使用 MinGW 编译的 Windows (XP)。
问候!
【问题讨论】:
至少在 Linux 上,您可以将中间文件替换为 fifo。我不确定 Windows 上是否存在相同的东西。 【参考方案1】:fgets
在您从文件中读取时不会阻塞,因为它到达文件末尾,这会导致EOF
在流上设置,因此调用fgets
会立即返回。当您从交互式输入运行时,永远不会设置 EOF
,除非您当然键入 Ctrl-Z(或 UNIX 系统上的 Ctrl-D)。
如果你真的想使用中间文件,我认为你需要增强你的 shell,以便当它遇到 EOF 时它会清除并在适当的等待后重新测试它。我认为这样的功能应该可以工作:-
void waitForEofClear(FILE *f)
while (feof(f))
clearerr(f);
sleep(1);
然后你可以在 fgets
:-
waitForEofClear(stdin);
fgets(buf, sizeof(buf), stdin);
【讨论】:
嗨,安德鲁,我想出了这么多。我正在寻找的是以某种方式“欺骗”C 库在内部阻止 fget,因此我不必更改应用程序代码。唉,这可能是我唯一的选择。【参考方案2】:正如其他答案所表明的那样,仅使用文件是行不通的。所以,你需要决定你要做什么。 FIFO(命名管道)或普通(匿名)管道可用于为被测交互式程序提供数据——或者,在 Unix 上,您可以使用伪 tty。所有这些的好处是程序在没有数据读取时阻塞,等待下一个信息到达,而不是立即决定'没有数据要读取,必须是EOF'。
然后,您将需要一个半智能(甚至是智能)程序定期将数据写入通道以供被测程序读取。该程序需要知道在它写入的消息之间暂停多长时间。这可能就像“等待一秒钟;写入下一行数据'。或者你可能会做一些更复杂的事情。
我知道的一个方案有两个程序 - 一个捕获程序,用于记录用户键入的内容和时间(因此“数据”文件是结构化的;它的记录包括延迟(以秒为单位)一秒钟)加上一组要发送的字符(计数和字节列表)。运行此程序以捕获用户键入的内容并记录它(以及将数据发送到程序)。然后是第二个重播程序,读取文件,并解释延迟和字符序列。
如果输入序列是稳定的,这个方案就可以充分发挥作用;如果始终需要相同的击键序列来获得所需的结果。如果发送给程序的数据需要适应被测程序正在执行的操作及其响应,并且可能在不同的时间执行不同的操作,那么最好使用“expect”。这有能力做任何你需要的事情——至少对于非 GUI 程序。
【讨论】:
嗨乔纳森,我的谷歌搜索都指向了这个方向,但这带来了一些其他的技术问题。我希望测试执行和 C 应用程序作为单个进程运行。 @S.C. Madsen:嗯,我想你可以让它成为多线程的,让一个线程定时向另一个线程提供数据。但我认为这不像两个独立的过程那么简单。【参考方案3】:我不确定 Windows 等效项是什么,但在 Linux 中,我会将中间文件设为 fifo。如果我要做一个真正重要的自动驾驶,我会把它包装在一个期望脚本中。
【讨论】:
对,再一次,Linux 似乎拥有我需要的一切,而 Windows/MSYS:没有那么多...... :-(以上是关于强制 fgets 阻止(即伪造“交互式设备”)的主要内容,如果未能解决你的问题,请参考以下文章