tags:

views:

62

answers:

3

I have a function that reads user input from std::cin, and I want to write a unittest that inserts some strings into std::cin, such that later extraction from std::cin will read that string instead of pausing for keyboard input.

Ideally, I would change the function signature so that I can pass a custom istream as parameters, but I can't do that here since I have a fixed interface that I cannot change.

cin.putback() is almost what I wanted, however it is inserting only one character at a time, and it is inserting them in reverse order (but I read somewhere that putting back char that wasn't originally there can be dangerous, though the website doesn't elaborate why). I've tried several methods to inject the string to cin's internal buffer cin.rdbuf(), but none would work either. I've also considered using an external testing script or creating subprocess, however I'd like to first consider a test in pure C++.

So, is there any method to put strings into cin? Or do you know a better way to inject my "fake keyboard input"?

+3  A: 

Instead of screwing around with cin, you can have your program accept a general std::istream&. When running normally, just pass it cin. During a unit test, pass it an I/O stream of your own creation.

Reinderien
+4  A: 

If you really, really want to use std::cin, try this:

int main() {
  using namespace std;
  streambuf *backup;
  istringstream oss("testdata");
  backup = cin.rdbuf();
  cin.rdbuf(oss.rdbuf());
  string str;
  cin >> str;
  cout << "read " << str;    
}

You can restore std::cin's streambuf when you are done from backup. I don't guarantee the portability of this ;P

hrnt
+1. or `stringbuf sb("testdata"); streambuf *backup = cin.rdbuf(`. It's compliant, and reasonably portable, but not good practice. Oh yeah, and he might have to do `cin.clear()` to escape the EOF condition once the input has run out :vP .
Potatoswatter
+1 exactly what I asked for (I'm still personally wondering though, whether doing something like this is a good idea, even for a whitebox testing code).
Lie Ryan
A: 

cin.butback() is guaranteed to work with at most one character, so you can't putback a whole string. Use a stream that wraps cin and allows arbitrary putback() sequence length. I think Boost.Iostream have something similar, and if it doesn't then it might be helpful to implement such a wrapper.

ybungalobill