From 572a4e51e709ce1d327918dfe83d7f5829b6e4d6 Mon Sep 17 00:00:00 2001 From: Mike Lowis Date: Tue, 29 Dec 2015 14:46:09 +0000 Subject: [PATCH] Added basic unit test framework to allow more invasive and targeted testing --- Makefile | 49 ++++++++++++++++++++++------ tests/atf.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++ tests/atf.h | 45 +++++++++++++++++++++++++ 3 files changed, 178 insertions(+), 10 deletions(-) create mode 100644 tests/atf.c create mode 100644 tests/atf.h diff --git a/Makefile b/Makefile index 180c6c2..3231085 100644 --- a/Makefile +++ b/Makefile @@ -6,16 +6,26 @@ # tools CC = c99 LD = ${CC} +AR = ar -# flags -INCS = -Isource/ +# completed flags +INCS = -Isource/ -Itests/ CPPFLAGS = -D_XOPEN_SOURCE=700 -CFLAGS += ${INCS} ${CPPFLAGS} -g --coverage -LDFLAGS += --coverage ${LIBS} +CFLAGS += ${INCS} ${CPPFLAGS} +LDFLAGS += ${LIBS} +ARFLAGS = rcs + +# Enable GCC/Clang debug symbols +#CFLAGS += -g + +# Enable GCC coverage +#CFLAGS += --coverage +#LDFLAGS += --coverage #------------------------------------------------------------------------------ # Build Targets and Rules #------------------------------------------------------------------------------ +BIN = sclpl OBJS = source/main.o \ source/gc.o \ source/vec.o \ @@ -26,7 +36,11 @@ OBJS = source/main.o \ source/anf.o \ source/codegen.o -all: options sclpl test +TESTBIN = testsclpl +TESTOBJS = tests/atf.o \ + tests/sclpl/main.o + +all: options sclpl tests specs options: @echo "Toolchain Configuration:" @@ -34,12 +48,25 @@ options: @echo " CFLAGS = ${CFLAGS}" @echo " LD = ${LD}" @echo " LDFLAGS = ${LDFLAGS}" + @echo " AR = ${AR}" + @echo " ARFLAGS = ${ARFLAGS}" + +lib${BIN}.a: ${OBJS} + @echo AR $@ $* + @${AR} ${ARFLAGS} $@ $^ -sclpl: ${OBJS} +${BIN}: lib${BIN}.a @echo LD $@ - @${LD} ${LDFLAGS} -o $@ ${OBJS} + @${LD} ${LDFLAGS} -o $@ $^ + +${TESTBIN}: ${TESTOBJS} + @echo LD $@ + @${LD} ${LDFLAGS} -o $@ $^ + +tests: $(TESTBIN) + @./$< -test: sclpl +specs: $(BIN) @echo TEST $< @rspec --pattern 'spec/**{,/*/**}/*_spec.rb' @@ -48,7 +75,9 @@ test: sclpl @${CC} ${CFLAGS} -c -o $@ $< clean: - @rm -f sclpl ${OBJS} ${OBJS:.o=.gcda} ${OBJS:.o=.gcno} + @rm -f ${BIN} lib${BIN}.a + @rm -f ${TESTBIN} ${TESTOBJS} ${TESTOBJS:.o=.gcda} ${TESTOBJS:.o=.gcno} + @rm -f ${OBJS} ${OBJS:.o=.gcda} ${OBJS:.o=.gcno} -.PHONY: all options test +.PHONY: all options tests specs diff --git a/tests/atf.c b/tests/atf.c new file mode 100644 index 0000000..e1017e8 --- /dev/null +++ b/tests/atf.c @@ -0,0 +1,94 @@ +/** + @file atf.c + @brief See header for details + $Revision$ + $HeadURL$ +*/ +#include "atf.h" +#include +#include +#include +#ifndef NO_SIGNALS +#include +#endif + +char* Curr_Test = NULL; +char* Curr_File = NULL; +unsigned int Curr_Line = 0; +static unsigned int Total = 0; +static unsigned int Failed = 0; + +#ifndef NO_SIGNALS +static void handle_signal(int sig) { + /* Determine the signal name */ + char* sig_name = NULL; + switch(sig) { + case SIGABRT: sig_name = "SIGABRT"; break; + case SIGBUS: sig_name = "SIGBUS"; break; + case SIGFPE: sig_name = "SIGFPE"; break; + case SIGILL: sig_name = "SIGILL"; break; + case SIGSEGV: sig_name = "SIGSEGV"; break; + case SIGSYS: sig_name = "SIGSYS"; break; + /* If we don't recognize it then just return and let the default handler + catch it. */ + default: return; + } + /* Error and exit. No summary will be printed but the user will know which + test has crashed. */ + fprintf(stderr,"%s:%d:0:%s:CRASH (signal: %d - %s)\n", Curr_File, Curr_Line, Curr_Test, sig, sig_name); + Failed++; + (void)atf_print_results(); + exit(1); +} +#endif + +void atf_init(int argc, char** argv) { + /* I reserve the right to use these later */ + (void)argc; + (void)argv; + +#ifndef NO_SIGNALS + /* Init signal handler */ + signal(SIGABRT, handle_signal); + signal(SIGBUS, handle_signal); + signal(SIGFPE, handle_signal); + signal(SIGILL, handle_signal); + signal(SIGSEGV, handle_signal); + signal(SIGSYS, handle_signal); +#endif +} + +void atf_run_suite(suite_t suite) { + suite(); +} + +void atf_test_start(char* file, unsigned int line, char* name) { + Curr_File = file; + Curr_Line = line; + Curr_Test = name; + Total++; +} + +bool atf_test_assert(bool success, char* expr, char* file, int line) { + bool failed = !success; + if (failed) atf_test_fail(expr,file,line); + return failed; +} + +void atf_test_fail(char* expr, char* file, int line) { + Failed++; + printf("%s:%d:0:%s:FAIL:( %s )\n", file, line, Curr_Test, expr); \ +} + +int atf_print_results(void) { + static const char* results_string = + "\nUnit Test Summary" + "\n-----------------" + "\nTotal: %d" + "\nPassed: %d" + "\nFailed: %d" + "\n\n"; + printf(results_string, Total, Total - Failed, Failed); + return Failed; +} + diff --git a/tests/atf.h b/tests/atf.h new file mode 100644 index 0000000..0e2d2f1 --- /dev/null +++ b/tests/atf.h @@ -0,0 +1,45 @@ +/** + @file atf.h + @brief Aardvark Test Framework main interface file. + $Revision$ + $HeadURL$ +*/ +#ifndef TEST_H +#define TEST_H + +#include +#include + +typedef void (*suite_t)(void); + +extern char* Curr_Test; + +void atf_init(int argc, char** argv); + +void atf_run_suite(suite_t suite); + +void atf_test_start(char* file, unsigned int line, char* name); + +bool atf_test_assert(bool success, char* expr_str, char* file, int line); + +void atf_test_fail(char* expr, char* file, int line); + +int atf_print_results(void); + +#define CHECK(expr) \ + if(atf_test_assert((expr), #expr, __FILE__, __LINE__)) break + +#define TEST_SUITE(name) void name(void) + +#define TEST(desc) \ + for(atf_test_start(__FILE__,__LINE__,#desc); Curr_Test != NULL; Curr_Test = NULL) + +#define RUN_EXTERN_TEST_SUITE(name) \ + do { extern TEST_SUITE(name); atf_run_suite(&name); } while(0) + +#define RUN_TEST_SUITE(name) \ + atf_run_suite(&name) + +#define PRINT_TEST_RESULTS atf_print_results + +#endif /* TEST_H */ -- 2.52.0