Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I write a testing function for another function that uses stdin input?

I have the following functions as part of a college assignment:

int readMenuOption()
{
   /* local declarations */
   char option[2];
   /* read in 1 char from stdin plus 1 char for string termination character */
   readStdin(1 + 1, option);
   return (int)option[0] <= ASCII_OFFSET ? 0 : (int)option[0] - ASCII_OFFSET;
}

int readStdin(int limit, char *buffer) 
{
   char c;
   int i = 0;
   int read = FALSE;
   while ((c = fgetc(stdin)) != '\n') {
      /* if the input string buffer has already reached it maximum
       limit, then abandon any other excess characters. */
      if (i <= limit) {
         *(buffer + i) = c;
         i++;
         read = TRUE;
      }
   }
   /* clear the remaining elements of the input buffer with a null character. */
   for (i = i; i < strlen(buffer); i++) {
      *(buffer + i) = '\0';
   }
   return read;
}

It works perfectly for what I need it to do (take in input from keyboard). I've had to do it using stdin (like I have) because of a number of requirements outlined by my professor.

I want to write a series of "unit tests" for the assignment, but I dont know how to get my testing functions to call readMenuOption() and pass in input to it (without having to do it at run-time).

Is this possible, and if so, how can I do it? (i.e., is it possible to write to stdin)?

like image 426
Ash Avatar asked Jan 25 '26 08:01

Ash


1 Answers

One thing you could do is to simply modify readStdin to allow it to either get data from the real standard input, or from a helper function, something like:

char *fakeStdIn = "";
int myfgetc (FILE *fin) {
    if (*fakeStdIn == '\0')
        return fgetc (fin);
    return *fakeStdIn++;
}

int readStdin(int limit, char *buffer) 
{
   char c;
   int i = 0;
   int read = FALSE;
   while ((c = myfgetc(stdin)) != '\n') {
      /* if the input string buffer has already reached it maximum
       limit, then abandon any other excess characters. */
      if (i <= limit) {
         *(buffer + i) = c;
         i++;
         read = TRUE;
      }
   }
   /* clear the remaining elements of the input buffer with a null character. */
   for (i = i; i < strlen(buffer); i++) {
      *(buffer + i) = '\0';
   }
   return read;
}

Then, to call it from your unit test, you can do:

fakeStdIn = "1\npaxdiablo\nnice guy\n";
// Call your top-level input functions like  readMenuOption().

By putting a hook at the lower levels, you can inject your own character sequence instead of using standard input. And if, at any point, the fake standard input is exhausted, it reverts to the real one.

Obviously, this is using characters so, if you want to inject EOF events, you'll need an array of integers instead, but that would be a minor modification to the scheme.

like image 83
paxdiablo Avatar answered Jan 27 '26 01:01

paxdiablo



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!