Nie znam niczego co by tak robiło, oprócz pisanych ręcznie bibliotek i programów. Ja używam swojego krótkiego programu (nie radzę używać przy dużym outpucie, bo wtedy trochę muli):
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
bool isWhiteSpace(char c) {
return (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == '\v' || c == '\f');
}
bool isNumber(string str) {
return !str.empty() && str.find_first_not_of("0123456789") == string::npos;
}
std::string itos(int value, int min_length = 1) {
std::string result = std::to_string(value);
reverse(result.begin(), result.end());
while(result.size() < min_length) {
result += "0";
}
reverse(result.begin(), result.end());
return result;
}
int main(int argc, char* argv[])
{
string program;
string testspath = ".";
string path = ".";
int ile = 0;
bool p = false;
bool o = false;
bool e = false;
for(int i = 1; i < argc; i++) {
if(string(argv[i]) == "-p")
p = true;
else if(string(argv[i]) == "-o")
o = true;
else if(string(argv[i]) == "-e")
e = true;
else if(string(argv[i]) == "-t" && i+1 < argc)
testspath = argv[++i];
else if(string(argv[i]) == "-d" && i+1 < argc)
path = argv[++i];
else if(isNumber(argv[i]))
ile = atoi(argv[i]);
else
program = argv[i];
}
cout << "tester" << (p?" -p":"") << (e?" -e":"") << (o?" -o":"") << " -t "+testspath << " -d "+path << " " << ile << " "+program << endl;
for(int i = 1; i <= ile && program.size(); i++) {
string ii = itos(i /*, itos(ile).size()*/);
system((program+" < "+testspath+"/in/test"+ii+".in > "+path+"/test"+ii+".out 2> "+path+"/test"+ii+".err").c_str());
fstream file0(testspath+"/in/test"+ii+".in", ios::in);
fstream file1(testspath+"/out/test"+ii+".out", ios::in);
fstream file2(path+"/test"+ii+".out", ios::in);
fstream file3(path+"/test"+ii+".err", ios::in);
if(file0.good() && file1.good() && file2.good() && file3.good()) {
string sp((istreambuf_iterator<char>(file0)), (istreambuf_iterator<char>()));
string so1((istreambuf_iterator<char>(file1)), (istreambuf_iterator<char>()));
string so2((istreambuf_iterator<char>(file2)), (istreambuf_iterator<char>()));
string se((istreambuf_iterator<char>(file3)), (istreambuf_iterator<char>()));
string po1 = so1;
string po2 = so2;
po1.erase(remove_if(po1.begin(), po1.end(), isWhiteSpace), po1.end());
po2.erase(remove_if(po2.begin(), po2.end(), isWhiteSpace), po2.end());
if(po1 == po2)
cout << "\033[32m"+ii+": OK\033[39m\n";
else
cout << "\033[31m"+ii+": ZLE\033[39m\n";
if(p) {
cout << "Pytanie:\n" << sp << "\n";
}
if(o) {
cout << "Poprawna odpowiedź:\n" << so1 << "\n";
cout << "Odpowiedź:\n" << so2 << "\n";
}
if(e) {
cout << "Błędy:\n" << se << "\n";
}
} else {
cout << "\033[31m"+ii+": Nie można otworzyć plików!\033[39m\n";
}
}
}
argumenty:
- ścieżka do programu (w takiej formie jak podajesz w konsoli przy uruchamianiu) (w przypadku niepodania program nic nie zrobi) (default "")
- ilość testów (w przypadku niepodania program nic nie zrobi) (default 0)
opcjonalne argumenty:
- -p - włącza wypisywanie pliku .in (default false)
- -o - włącza wypisywanie pliku .out i odpowiedzi programu (default false)
- -e - włącza wypisywanie błędów (standardowego wyjścia błędów) programu (dafault false)
- -t "ścieżka do folderu z testami" - testy będą brane z lokalizacji "ścieżka do folderu z testami" (dafault ".")
- -d "ścieżka do folderu z outputem programu na wszystkich testach" - odpowiedzi programu będą zapisywane w lokalizacji "ścieżka do folderu..." (default ".")
testy numerowane od 1 do ilości testów, (test1.in, test2.in, test3.in ... test[ilość testów].in)
po odkomentowaniu pierwszej linii w forze, testy powinny wyglądać tak (zawsze numer tej samej długości):
test01.in, test02.in, test03.in, test04.in ... test15.in, test16.in
ułożone są wtedy w dobrej kolejności w przeglądarce plików.
Ponadto pliki wyjścia programu są zapisane w "[ścieżka do folderu z outputem...]/test[numer testu].[in i err]"
Przykładowe użycie: ./tester ./program -p -o -e -t testy -d odpowiedzi 50
PS. Zapomniałem dodać, że pliki .out powinny być w katalogu out a pliki .in w katalogu in.