]> git.mdlowis.com Git - proto/sclpl.git/commitdiff
Added basic unit test framework to allow more invasive and targeted testing
authorMike Lowis <mike.lowis@gentex.com>
Tue, 29 Dec 2015 14:46:09 +0000 (14:46 +0000)
committerMike Lowis <mike.lowis@gentex.com>
Tue, 29 Dec 2015 14:46:09 +0000 (14:46 +0000)
Makefile
tests/atf.c [new file with mode: 0644]
tests/atf.h [new file with mode: 0644]

index 180c6c26f9817f999493f522630f10390a3a46dd..323108500356c45a0333b364cea20ffb569c8bfb 100644 (file)
--- 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 (file)
index 0000000..e1017e8
--- /dev/null
@@ -0,0 +1,94 @@
+/**
+  @file atf.c
+  @brief See header for details
+  $Revision$
+  $HeadURL$
+*/
+#include "atf.h"
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#ifndef NO_SIGNALS
+#include <signal.h>
+#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 (file)
index 0000000..0e2d2f1
--- /dev/null
@@ -0,0 +1,45 @@
+/**
+  @file atf.h
+  @brief Aardvark Test Framework main interface file.
+  $Revision$
+  $HeadURL$
+*/
+#ifndef TEST_H
+#define TEST_H
+
+#include <stddef.h>
+#include <stdbool.h>
+
+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 */