rpn/src/rpn-test-core.h

250 lines
7.8 KiB
C

void test_get_stack(string& stack_is, stack& stk)
{
// write stack in a string, each entry separated between commas
for (int i = 0; i < (int)stk.size(); i++)
{
FILE* tmp_file = tmpfile();
char* line = NULL;
size_t len;
if (i > 0)
stack_is += ", ";
if (tmp_file != NULL)
{
((object*)stk.seq_obj(i))->show(tmp_file);
// write stack in a tmp file
(void)rewind(tmp_file);
if (getline(&line, &len, tmp_file) >=0)
{
stack_is += line;
free(line);
}
(void)fclose(tmp_file);
}
else
ERR_CONTEXT(ret_runtime_error);
}
}
void test_show_result(string title, int tests, int tests_failed, int steps, int steps_failed)
{
printf("%s: run %d tests: %d passed, ", title.c_str(), tests, tests-tests_failed);
if(tests_failed>0)
printf(FG_RED);
printf("%d failed", tests_failed);
if(tests_failed>0)
printf(COLOR_OFF);
printf(" (%d steps: %d passed, ", steps, steps-steps_failed);
if(steps_failed>0)
printf(FG_RED);
printf("%d failed", steps_failed);
if(steps_failed>0)
printf(COLOR_OFF);
printf(")\n");
}
void test()
{
MIN_ARGUMENTS(1);
ARG_MUST_BE_OF_TYPE(0, cmd_string);
int total_tests=0;
int total_tests_failed=0;
int total_steps=0;
int total_steps_failed=0;
string test_filename = ((ostring*)_stack->pop_back())->_value;
test(test_filename, total_tests, total_tests_failed, total_steps, total_steps_failed);
test_show_result("Total", total_tests, total_tests_failed, total_steps, total_steps_failed);
}
void test(string test_filename, int& total_tests, int& total_tests_failed, int& total_steps, int& total_steps_failed)
{
const string stack_size("-> stack size should be ");
const string stack_value("-> stack should be ");
const string cmd_error("-> error should be ");
const string cmd_exit("exit test");
ifstream test_file(test_filename.c_str());
int tests = 0;
int tests_failed = 0;
int steps = 0;
int steps_failed = 0;
if (test_file.is_open())
{
string test_title;
string entry;
ret_value ret;
stack stk;
heap hp;
bool failed = false;
bool is_first_step;
bool is_test_error_shown;
int last_err;
stringstream cerr_buffer;
streambuf* cerr_old_buffer;
// redirect cerr
cerr_old_buffer = cerr.rdbuf(cerr_buffer.rdbuf());
while (!test_file.eof())
{
getline(test_file, entry);
if (entry.substr(0,8)=="#include")
test(entry.substr(9), total_tests, total_tests_failed, total_steps, total_steps_failed);
else if (entry.substr(0,2)=="##")
printf("\n%s: %s\n", test_filename.c_str(), entry.substr(3).c_str());
else if (entry.substr(0,2)=="# ")
{
// indicates the status of previous test
if (failed == false && tests > 0)
printf(FG_GREEN " PASSED" COLOR_OFF "\n");
failed = false;
// read a test title
test_title = entry;
is_first_step = true;
is_test_error_shown = false;
printf("%s", test_title.c_str());
}
// treat "-> stack size should be "
else if (entry.find(stack_size, 0) == 0)
{
// count test and step
if (is_first_step)
tests++;
steps++;
// check current stack size
istringstream isub;
int size;
isub.str(entry.substr(stack_size.size()));
isub>>size;
if (size != (int)stk.size())
{
// count fail test and step
if (!is_test_error_shown)
{
printf(FG_RED " FAIL" COLOR_OFF "\n");
tests_failed++;
is_test_error_shown = true;
}
steps_failed++;
// show failure
printf("\t%s\n", entry.c_str());
printf("\tbut real stack size is " FG_RED "%d" COLOR_OFF "\n", stk.size());
failed = true;
}
is_first_step = false;
}
// treat "-> stack should be "
else if (entry.find(stack_value, 0) == 0)
{
// count test
if (is_first_step)
tests++;
steps++;
// check current stack value
string stack_should_be = entry.substr(stack_value.size());
string stack_is;
test_get_stack(stack_is, stk);
if (stack_is != stack_should_be)
{
// count fail test and step
if (!is_test_error_shown)
{
printf(FG_RED " FAIL" COLOR_OFF "\n");
tests_failed++;
is_test_error_shown = true;
}
steps_failed++;
// show failure
printf("\t%s\n", entry.c_str());
printf("\tbut real stack size is " FG_RED "%s" COLOR_OFF "\n", stack_is.c_str());
failed = true;
}
is_first_step = false;
}
// treat "-> error should be "
else if (entry.find(cmd_error, 0) == 0)
{
// count test
if (is_first_step)
tests++;
steps++;
// check current error
istringstream isub;
int err_should_be;
isub.str(entry.substr(cmd_error.size()));
isub>>err_should_be;
if (err_should_be != last_err)
{
// count fail test and step
if (!is_test_error_shown)
{
printf(FG_RED " FAIL" COLOR_OFF "\n");
tests_failed++;
is_test_error_shown = true;
}
steps_failed++;
// show failure
printf("\t%s\n", entry.c_str());
printf("\tbut last error is " FG_RED "%d" COLOR_OFF "\n", last_err);
failed = true;
}
is_first_step = false;
}
else if (entry.find(cmd_exit, 0) == 0)
{
// forced test end
break;
}
else if (entry.size() > 0)
{
// parse entry and run line
program prog;
ret = program::parse(entry.c_str(), prog);
if (ret == ret_ok)
{
// run it
(void)prog.run(stk, hp);
last_err = (int)prog.get_err();
}
}
}
// last test
// indicates the status of previous test
if (failed == false && tests > 0)
printf(FG_GREEN " PASSED" COLOR_OFF "\n");
// cerr back
cerr.rdbuf(cerr_old_buffer);
// conclusion: show and keep for total
if (tests != 0)
{
test_show_result(test_filename, tests, tests_failed, steps, steps_failed);
total_tests += tests;
total_tests_failed += tests_failed;
total_steps += steps;
total_steps_failed += steps_failed;
}
}
else
fprintf(stderr, "test file '%s' not found\n", test_filename.c_str());
}