tags:

views:

61

answers:

3

Hi,

I have a C application which provides a "shell" for entering commands. I'm trying to write some automated test-code for the application (Using CUnit). The "shell" input is read from stdin like so:

fgets(buf, sizeof(buf), stdin);

I can "write" commands automatically to the application by freopen()'ning stdin and hooking it to an intermediate file. When the application is executed "normally" the fgets() call blocks untill characters are available because it is "an interactive device", but not so on the intermediate file. So how can I fake fgets into thinking the intermediate file is an "interactive device".

The C program is for Windows (XP) compiled using MinGW.

Regards!

+1  A: 

fgets is not blocking when you are reading from a file because it reaches the end of the file which causes EOF to set on the stream and thus calls to fgets return immediately. When you are running from an interactive input EOF is never set, unless you type Ctrl-Z (or Ctrl-D on UNIX system) of course.

If you really want to use an intermediate file I think you'll need to enhance your shell so that when it hits an EOF it clears and retests it after a suitable wait. A function like this should work I think:-

void waitForEofClear(FILE *f)
{
   while (feof(f)) {
      clearerr(f);
      sleep(1);
   }
}

You could then call this before the fgets:-

waitForEofClear(stdin);
fgets(buf, sizeof(buf), stdin);
Andrew O'Reilly
Hi Andrew,This much I'd figured out. What I was searching for was to some-how "trick" the C-library into blocking fgets internally, so I would NOT have to alter the application code. Alas that may be my only option.
S.C. Madsen
A: 

I'm not sure what the windows equivalent is, but in Linux I would make the intermediate file a fifo. If I was going to do a real non-trivial autopilotting, I would wrap it in an expect script.

frankc
Right, Once again it seems Linux has everything I need, while Windows/MSYS: Not so much...... :-(
S.C. Madsen
+1  A: 

Simply using a file is not going to work, as the other answers have indicated. So, you need to decide what you are going to do instead. A FIFO (named pipe) or plain (anonymous) pipe could be used to feed the interactive program under test - or, on Unix, you could use a pseudo-tty. The advantage of all these is that a program blocks when there is no data read, waiting for the next information to arrive, rather than immediately deciding 'no data to read, must be EOF'.

You will then need a semi-intelligent (or even intelligent) program periodically writing data to the channel for the program under test to read. This program will need to know how long to pause between the messages it writes. This might be as simplistic as 'wait one second; write the next line of data'. Or you might do something more complex.

One scheme that I know of has two programs - a capture program to record what a user types and the timing of it (so the 'data' file is structured; it has records consisting of a delay (in seconds and fractions of a second) plus a set of characters to send (count and list of bytes). This is run to capture what the user types and record it (as well as send the data to the program). There is then a second replay program that reads the file, and interprets the delays and character sequences.

This scheme works adequately if the input sequence is stable; if the same sequence of key strokes is always needed to get the required result. If the data sent to the program needs to adapt to what the program under test is doing and its responses, and may do different things at different times, then you are probably better off going with 'expect'. This has the capacity to do whatever you need - at least for non-GUI programs.

Jonathan Leffler
Hi Jonathan,My Google'ing efforts all pointed in this direction, but that poses some other technical problems. I would like the Test execution and the C-application to run as a single process.
S.C. Madsen
@S.C. Madsen: Well, I suppose you could make it multi-threaded, and have one thread do the timed provision of data to the other thread. But I don't think that's as easy as two separate processes.
Jonathan Leffler