Updated testing framework

This commit is contained in:
Daniel Holden
2013-09-23 22:41:58 +01:00
parent 4daf2527a0
commit 48812155a1
10 changed files with 1429 additions and 219 deletions

81
tests/core.c Normal file
View File

@@ -0,0 +1,81 @@
#include "ptest.h"
#include "../mpc.h"
#include <stdlib.h>
#include <string.h>
static bool int_eq(void* x, void* y) { return (*(int*)x == *(int*)y); }
static void int_print(void* x) { printf("'%i'", *((int*)x)); }
static bool string_eq(void* x, void* y) { return (strcmp(x, y) == 0); }
static void string_print(void* x) { printf("'%s'", (char*)x); }
void test_ident(void) {
/* ^[a-zA-Z_][a-zA-Z0-9_]*$ */
mpc_parser_t* Ident = mpc_ends(
mpc_also(
mpc_else(mpc_alpha(), mpc_underscore()),
mpc_many1(mpc_or(3, mpc_alpha(), mpc_underscore(), mpc_digit()), mpcf_strfold),
free, mpcf_strfold),
free
);
PT_ASSERT(mpc_match(Ident, "test", "test", string_eq, free, string_print));
PT_ASSERT(mpc_unmatch(Ident, " blah", "", string_eq, free, string_print));
PT_ASSERT(mpc_match(Ident, "anoth21er", "anoth21er", string_eq, free, string_print));
PT_ASSERT(mpc_match(Ident, "du__de", "du__de", string_eq, free, string_print));
PT_ASSERT(mpc_unmatch(Ident, "some spaces", "", string_eq, free, string_print));
PT_ASSERT(mpc_unmatch(Ident, "", "", string_eq, free, string_print));
PT_ASSERT(mpc_unmatch(Ident, "18nums", "", string_eq, free, string_print));
mpc_delete(Ident);
}
void test_maths(void) {
mpc_parser_t* Expr = mpc_new();
mpc_parser_t* Factor = mpc_new();
mpc_parser_t* Term = mpc_new();
mpc_parser_t* Maths = mpc_new();
mpc_define(Expr, mpc_else(
mpc_and(3, mpcf_maths, Factor, mpc_oneof("*/"), Factor, free, free),
Factor
));
mpc_define(Factor, mpc_else(
mpc_and(3, mpcf_maths, Term, mpc_oneof("+-"), Term, free, free),
Term
));
mpc_define(Term, mpc_else(
mpc_int(),
mpc_parens(Expr, free)
));
mpc_define(Maths, mpc_ends(Expr, free));
PT_ASSERT(mpc_match(Maths, "1", (int[]){ 1 }, int_eq, free, int_print));
PT_ASSERT(mpc_match(Maths, "(5)", (int[]){ 5 }, int_eq, free, int_print));
PT_ASSERT(mpc_match(Maths, "(4*2)+5", (int[]){ 13 }, int_eq, free, int_print));
PT_ASSERT(mpc_unmatch(Maths, "a", (int[]){ 0 }, int_eq, free, int_print));
PT_ASSERT(mpc_unmatch(Maths, "2b+4", (int[]){ 2 }, int_eq, free, int_print));
mpc_undefine(Expr);
mpc_undefine(Factor);
mpc_undefine(Term);
mpc_undefine(Maths);
mpc_delete(Expr);
mpc_delete(Factor);
mpc_delete(Term);
mpc_delete(Maths);
}
void suite_core(void) {
pt_add_test(test_ident, "Test Ident", "Suite Core");
pt_add_test(test_maths, "Test Maths", "Suite Core");
}

56
tests/grammar.c Normal file
View File

@@ -0,0 +1,56 @@
#include "ptest.h"
#include "../mpc.h"
bool ast_eq(void* x, void* y) {
return false;
}
void test_grammar(void) {
mpc_parser_t* Test = mpc_new();
mpc_define(Test, mpca_grammar("'c'*"));
mpc_print(Test);
mpc_undefine(Test);
mpc_delete(Test);
mpc_parser_t* Expression = mpc_new();
mpc_parser_t* Product = mpc_new();
mpc_parser_t* Value = mpc_new();
mpc_define(Expression, mpca_grammar("<0> (('+' | '-') <0>)*", Product));
mpc_define(Product, mpca_grammar("<0> (('*' | '/') <0>)*", Value));
mpc_define(Value, mpca_grammar("/[0-9]/ | '(' <0> ')'", Expression));
mpc_print(Expression);
mpc_print(Product);
mpc_print(Value);
mpc_ast_t* empty = mpc_ast_empty();
/*
PT_ASSERT(mpc_match(Expression, "1", empty, ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(void*))mpc_ast_print));
PT_ASSERT(mpc_match(Expression, "(5)", empty, ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(void*))mpc_ast_print));
PT_ASSERT(mpc_match(Expression, "(4*2)+5", empty, ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(void*))mpc_ast_print));
PT_ASSERT(mpc_match(Expression, "a", empty, ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(void*))mpc_ast_print));
PT_ASSERT(mpc_match(Expression, "2b+4", empty, ast_eq, (mpc_dtor_t)mpc_ast_delete, (void(*)(void*))mpc_ast_print));
*/
mpc_ast_delete(empty);
mpc_undefine(Expression);
mpc_undefine(Product);
mpc_undefine(Value);
mpc_delete(Expression);
mpc_delete(Product);
mpc_delete(Value);
}
void suite_grammar(void) {
pt_add_test(test_grammar, "Test Grammar", "Suite Grammar");
}

301
tests/ptest.c Normal file
View File

@@ -0,0 +1,301 @@
#include "ptest.h"
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <time.h>
#include <unistd.h>
/* Globals */
#define MAX_NAME 512
#define MAX_ERROR 2048
#define MAX_TESTS 2048
static bool test_passing = false;
static bool suite_passing = false;
/* Colors */
enum {
BLACK = 0x0,
BLUE = 0x1,
GREEN = 0x2,
AQUA = 0x3,
RED = 0x4,
PURPLE = 0x5,
YELLOW = 0x6,
WHITE = 0x7,
GRAY = 0x8,
LIGHT_BLUE = 0x9,
LIGHT_GREEN = 0xA,
LIGHT_AQUA = 0xB,
LIGHT_RED = 0xC,
LIGHT_PURPLE = 0xD,
LIGHT_YELLOW = 0xE,
LIGHT_WHITE = 0xF,
};
#ifdef _WIN32
#include <windows.h>
static void pt_color(int color) {
HANDLE hCon = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleTextAttribute(hCon, color);
}
#else
static const char* colors[] = {
"\x1B[0m",
"\x1B[34m",
"\x1B[32m",
"\x1B[36m",
"\x1B[31m",
"\x1B[35m",
"\x1B[33m",
"\x1B[37m",
"",
"\x1B[34m",
"\x1B[32m",
"\x1B[36m",
"\x1B[31m",
"\x1B[35m",
"\x1B[33m",
"\x1B[37m"
};
static void pt_color(int color) {
printf("%s", colors[color]);
}
#endif
/* Asserts */
static int num_asserts = 0;
static int num_assert_passes = 0;
static int num_assert_fails = 0;
static char assert_err[MAX_ERROR];
static char assert_err_buff[MAX_ERROR];
static int assert_err_num = 0;
void pt_assert_run(bool result, const char* expr, const char* func, const char* file, int line) {
num_asserts++;
test_passing = test_passing && result;
if (result) {
num_assert_passes++;
} else {
sprintf(assert_err_buff, " %i. Assert [ %s ] (%s:%i)\n", assert_err_num+1, expr, file, line );
strcat(assert_err, assert_err_buff);
assert_err_num++;
num_assert_fails++;
}
}
static void ptest_signal(int sig) {
test_passing = false;
switch( sig ) {
case SIGFPE: sprintf(assert_err_buff, " %i. Division by Zero\n", assert_err_num+1); break;
case SIGILL: sprintf(assert_err_buff, " %i. Illegal Instruction\n", assert_err_num+1); break;
case SIGSEGV: sprintf(assert_err_buff, " %i. Segmentation Fault\n", assert_err_num+1); break;
}
assert_err_num++;
strcat(assert_err, assert_err_buff);
pt_color(RED); printf("Failed! \n\n%s\n", assert_err); pt_color(WHITE);
printf(" | Stopping Execution.\n");
fflush(stdout);
exit(0);
}
/* Tests */
static void pt_title_case(char* output, const char* input) {
bool space = true;
strcpy(output, input);
unsigned int i;
for(i = 0; i < strlen(output); i++) {
if (output[i] == '_' || output[i] == ' ') {
space = true;
output[i] = ' ';
continue;
}
if (space && output[i] >= 'a' && output[i] <= 'z') {
output[i] = output[i] - 32;
continue;
}
space = false;
}
}
typedef struct {
void (*func)(void);
char name[MAX_NAME];
char suite[MAX_NAME];
} test_t;
static test_t tests[MAX_TESTS];
static int num_tests = 0;
static int num_tests_passes = 0;
static int num_tests_fails = 0;
void pt_add_test(void (*func)(void), const char* name, const char* suite) {
if (num_tests == MAX_TESTS) {
printf("ERROR: Exceeded maximum test count of %i!\n", MAX_TESTS); abort();
}
if (strlen(name) >= MAX_NAME) {
printf("ERROR: Test name '%s' too long (Maximum is %i characters)\n", name, MAX_NAME); abort();
}
if (strlen(suite) >= MAX_NAME) {
printf("ERROR: Test suite '%s' too long (Maximum is %i characters)\n", suite, MAX_NAME); abort();
}
test_t test;
test.func = func;
pt_title_case(test.name, name);
pt_title_case(test.suite, suite);
tests[num_tests] = test;
num_tests++;
}
/* Suites */
static int num_suites = 0;
static int num_suites_passes = 0;
static int num_suites_fails = 0;
void pt_add_suite(void (*func)(void)) {
num_suites++;
func();
}
/* Running */
static clock_t start, end;
static char current_suite[MAX_NAME];
int pt_run(void) {
printf(" \n");
printf(" +-------------------------------------------+\n");
printf(" | ptest MicroTesting Magic for C |\n");
printf(" | |\n");
printf(" | http://github.com/orangeduck/ptest |\n");
printf(" | |\n");
printf(" | Daniel Holden (contact@theorangeduck.com) |\n");
printf(" +-------------------------------------------+\n");
signal(SIGFPE, ptest_signal);
signal(SIGILL, ptest_signal);
signal(SIGSEGV, ptest_signal);
start = clock();
strcpy(current_suite, "");
unsigned int i;
for(i = 0; i < num_tests; i++) {
test_t test = tests[i];
/* Check for transition to a new suite */
if (strcmp(test.suite, current_suite)) {
/* Don't increment any counter for first entrance */
if (strcmp(current_suite, "")) {
if (suite_passing) {
num_suites_passes++;
} else {
num_suites_fails++;
}
}
suite_passing = true;
strcpy(current_suite, test.suite);
printf("\n\n ===== %s =====\n\n", current_suite);
}
/* Run Test */
test_passing = true;
strcpy(assert_err, "");
strcpy(assert_err_buff, "");
assert_err_num = 0;
printf(" | %s ... ", test.name);
test.func();
suite_passing = suite_passing && test_passing;
if (test_passing) {
num_tests_passes++;
pt_color(GREEN); printf("Passed! \n"); pt_color(WHITE);
} else {
num_tests_fails++;
pt_color(RED); printf("Failed! \n\n%s\n", assert_err); pt_color(WHITE);
}
}
if (suite_passing) {
num_suites_passes++;
} else {
num_suites_fails++;
}
end = clock();
printf(" \n");
printf(" +---------------------------------------------------+\n");
printf(" | Summary |\n");
printf(" +---------++------------+-------------+-------------+\n");
printf(" | Suites ||");
pt_color(YELLOW); printf(" Total %4d ", num_suites); pt_color(WHITE); printf("|");
pt_color(GREEN); printf(" Passed %4d ", num_suites_passes); pt_color(WHITE); printf("|");
pt_color(RED); printf(" Failed %4d ", num_suites_fails); pt_color(WHITE); printf("|\n");
printf(" | Tests ||");
pt_color(YELLOW); printf(" Total %4d ", num_tests); pt_color(WHITE); printf("|");
pt_color(GREEN); printf(" Passed %4d ", num_tests_passes); pt_color(WHITE); printf("|");
pt_color(RED); printf(" Failed %4d ", num_tests_fails); pt_color(WHITE); printf("|\n");
printf(" | Asserts ||");
pt_color(YELLOW); printf(" Total %4d ", num_asserts); pt_color(WHITE); printf("|");
pt_color(GREEN); printf(" Passed %4d ", num_assert_passes); pt_color(WHITE); printf("|");
pt_color(RED); printf(" Failed %4d ", num_assert_fails); pt_color(WHITE); printf("|\n");
printf(" +---------++------------+-------------+-------------+\n");
printf(" \n");
double total = (double)(end - start) / CLOCKS_PER_SEC;
printf(" Total Running Time: %0.3fs\n\n", total);
if (num_suites_fails > 0) { return 1; } else { return 0; }
}

19
tests/ptest.h Normal file
View File

@@ -0,0 +1,19 @@
#ifndef ptest_h
#define ptest_h
#include <stdbool.h>
#include <string.h>
#define PT_SUITE(name) void name(void)
#define PT_TEST(name) auto void name(void); pt_add_test(name, #name, __func__); void name(void)
#define PT_ASSERT(expr) pt_assert_run((bool)(expr), #expr, __func__, __FILE__, __LINE__)
#define PT_ASSERT_STR_EQ(fst, snd) pt_assert_run(strcmp(fst, snd) == 0, "strcmp( " #fst ", " #snd " ) == 0", __func__, __FILE__, __LINE__)
void pt_assert_run(bool result, const char* expr, const char* func, const char* file, int line);
void pt_add_test(void (*func)(void), const char* name, const char* suite);
void pt_add_suite(void (*func)(void));
int pt_run(void);
#endif

View File

@@ -1,27 +1,29 @@
#include "ptest.h"
#include "../mpc.h"
#include <string.h>
#include <stdlib.h>
/*
static bool string_eq(void* x, void* y) { return (strcmp(x, y) == 0); }
static void string_print(void* x) { printf("'%s'", (char*)x); }
*/
bool suite_regex(void) {
void test_regex_basic(void) {
mpc_parser_t* re0 = mpc_re("abc|bcd");
mpc_parser_t* re1 = mpc_re("abc|bcd|e");
mpc_parser_t* re2 = mpc_re("abc(ab)*");
mpc_parser_t* re2 = mpc_re("ab()c(ab)*");
mpc_parser_t* re3 = mpc_re("abc(abdd)?");
mpc_parser_t* re4 = mpc_re("ab|c(abdd)?");
mpc_parser_t* re5 = mpc_re("abc(ab|dd)+g$");
mpc_print(re0);
mpc_print(re1);
mpc_print(re2);
mpc_print(re3);
mpc_print(re4);
mpc_print(re5);
PT_ASSERT(mpc_match(re0, "abc", "abc", string_eq, free, string_print));
PT_ASSERT(mpc_match(re0, "bcd", "bcd", string_eq, free, string_print));
PT_ASSERT(mpc_unmatch(re0, "bc", "bc", string_eq, free, string_print));
PT_ASSERT(mpc_unmatch(re0, "ab", "ab", string_eq, free, string_print));
PT_ASSERT(mpc_match(re1, "e", "e", string_eq, free, string_print));
PT_ASSERT(mpc_match(re2, "abc", "abc", string_eq, free, string_print));
PT_ASSERT(mpc_match(re2, "abcabab", "abcabab", string_eq, free, string_print));
PT_ASSERT(mpc_match(re2, "abcababd", "abcabab", string_eq, free, string_print));
mpc_delete(re0);
mpc_delete(re1);
@@ -29,6 +31,29 @@ bool suite_regex(void) {
mpc_delete(re3);
mpc_delete(re4);
mpc_delete(re5);
}
void test_regex_range(void) {
mpc_parser_t* re0 = mpc_re("abg[abcdef]");
mpc_parser_t* re1 = mpc_re("y*[a-z]");
mpc_parser_t* re2 = mpc_re("zz(p+)?[A-Z_0\\]123]*");
mpc_parser_t* re3 = mpc_re("[^56hy].*$");
mpc_print(re0);
mpc_print(re1);
mpc_print(re2);
mpc_print(re3);
return true;
mpc_delete(re0);
mpc_delete(re1);
mpc_delete(re2);
mpc_delete(re3);
}
void suite_regex(void) {
pt_add_test(test_regex_basic, "Test Regex Basic", "Suite Regex");
pt_add_test(test_regex_range, "Test Regex Range", "Suite Regex");
}

View File

@@ -1,15 +1,12 @@
#include <stdbool.h>
#include "ptest.h"
bool suite_ident(void);
bool suite_math(void);
bool suite_regex(void);
void suite_core(void);
void suite_regex(void);
void suite_grammar(void);
int main(int argc, char** argv) {
suite_ident();
suite_math();
suite_regex();
return 0;
pt_add_suite(suite_core);
pt_add_suite(suite_regex);
pt_add_suite(suite_grammar);
return pt_run();
}