2010-09-26 17 views
10

Mam funkcję odczytywania danych wprowadzanych przez użytkownika ze std :: cin i chcę napisać unittest, który wstawia niektóre ciągi znaków do std :: cin, tak, że później wyodrębnianie ze std :: cin będzie przeczytaj ten ciąg, zamiast wstrzymywać go przed wprowadzeniem z klawiatury.Wstrzykiwanie łańcucha znaków do 'cin'

Najlepiej byłoby zmienić sygnaturę funkcji, aby móc przekazać niestandardowy kod istream jako parametry, ale nie mogę tego zrobić, ponieważ mam stały interfejs, którego nie mogę zmienić.

cin.putback() to prawie co chciałem, jednak wstawia tylko jedną postać na raz, i wstawia je w odwrotnej kolejności (ale czytałem gdzieś, że przywracanie char, który nie był pierwotnie może być niebezpiecznie, chociaż strona nie wyjaśnia dlaczego). Próbowałem kilka metod, aby wstrzyknąć ciąg do wewnętrznego bufora cin.rdbuf() cin, ale żaden też by nie zadziałał. Zastanawiałem się też nad użyciem zewnętrznego skryptu testowego lub tworzenia podprocesu, ale chciałbym najpierw rozważyć test w czystym C++.

Czy jest więc jakaś metoda umieszczania napisów w cin? A może znasz lepszy sposób na wstrzyknięcie mojego "fałszywego wejścia klawiatury"?

Odpowiedz

8

Jeśli naprawdę chcesz używać std :: cin, spróbuj tego:

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

można przywrócić streambuf std :: cin, gdy skończysz z kopii zapasowej. Nie gwarantuję przenośności tego: P

+0

+1. lub 'stringbuf sb (" testdata "); streambuf * backup = cin.rdbuf (&sb); 'To jest zgodne i rozsądnie przenośne, ale nie jest to dobra praktyka O tak, i być może będzie musiał zrobić' cin.clear() ', aby uniknąć warunku EOF po wyczerpaniu się danych wejściowych : vP. – Potatoswatter

+0

+1 dokładnie to, o co prosiłem (wciąż jednak zastanawiam się, czy robienie czegoś takiego jest dobrym pomysłem, nawet dla kodu testowego WhiteBoxa). –

13

Zamiast wkręcać z cin, możesz mieć swój program akceptujący ogólny std::istream&. Podczas normalnego działania wystarczy przekazać go cin. Podczas testu jednostkowego przekaż mu strumień we/wy twojego własnego dzieła.

+2

To rozwiązanie jest naprawdę świetne. Możesz przekazać otwarty plik przez 'ifstream', jeśli chcesz przekazać plik jako dane testowe, lub możesz po prostu przekazać' istringstream', jeśli chcesz po prostu przekazać ciąg znaków jako dane wejściowe testu. – RPGillespie

0

cin.butback() ma gwarantowaną pracę z maksymalnie jednym znakiem, więc nie można odrzucić całego ciągu znaków. Użyj strumienia, który zawija cin i umożliwia dowolną długość sekwencji zwrotu(). Myślę, że Boost.Iostream ma coś podobnego, a jeśli nie, to może być przydatne do wdrożenia takiego wrappera.