diff --git a/thorn/Makefile b/thorn/Makefile index e510523..9ccad57 100644 --- a/thorn/Makefile +++ b/thorn/Makefile @@ -32,12 +32,14 @@ SRC = src KERNEL = kernel COMMON = common INCLUDE = include +TEST = test # Assemble lists of corresponding source files for assembly, kernel and common SRC_KERNEL = $(wildcard $(SRC)/$(KERNEL)/*.c) ASM_KERNEL = $(wildcard $(SRC)/$(KERNEL)/*.S) SRC_COMMON = $(wildcard $(SRC)/$(COMMON)/*.c) ASM_COMMON = $(wildcard $(SRC)/$(COMMON)/*.S) +TESTS = $(wildcard $(TEST)/*.c) # Assemble list of compiled objects, correspondingly OBJECTS = $(patsubst $(SRC)/$(KERNEL)/%.c, $(BUILD)/$(SRC)/$(KERNEL)/%_c.o, $(SRC_KERNEL)) @@ -79,6 +81,11 @@ $(BUILD)/$(SRC)/$(COMMON)/%_S.o: $(SRC)/$(COMMON)/%.S mkdir -p $(@D) $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< -o $@ +# All test source targets +$(BUILD)/$(TEST)/%_c.o: $(TEST)/%.c + mkdir -p $(@D) + $(ARMGNU)-gcc $(ASMOPS) -MMD -c $< $(OBJECTS) -o $@ + # Compile lists with the dependencies between objects DEP_FILES = $(OBJECTS:%.o=%.d) -include $(DEP_FILES) @@ -105,6 +112,10 @@ flash-Darwin: $(IMAGE_NAME).img sync diskutil unmount $(MNT) +test: $(SRC) $(BUILD)/$(TEST) + # TODO: how to send and run the tests on the PI? + # for test in $(BUID)/$(TEST) ; do ./$$test ; done + resend: reboot send send: $(IMAGE_NAME).img diff --git a/thorn/include/common/minunit.h b/thorn/include/common/minunit.h new file mode 100644 index 0000000..9001db4 --- /dev/null +++ b/thorn/include/common/minunit.h @@ -0,0 +1,122 @@ +/* + * Minimal Testing Framework based on + * https://github.com/siu/minunit + */ + +#ifndef MINUNIT_MINUNIT_H +#define MINUNIT_MINUNIT_H + +#include "common/printf.h" +#include "common/stddef.h" + +/* Misc. counters */ +static int minunit_run = 0; +static int minunit_assert = 0; +static int minunit_fail = 0; +static int minunit_status = 0; + +/* Test setup and teardown function pointers */ +static void (*minunit_setup) (void) = NULL; +static void (*minunit_teardown) (void) = NULL; + +/* Definitions */ +#define MU_TEST(method_name) static void method_name (void) +#define MU_TEST_SUITE(suite_name) static void suite_name (void) + +#define MU__SAFE_BLOCK(block) \ + do { \ + block \ + } while (0) + +#define MU_RUN_SUITE(suite_name) MU__SAFE_BLOCK ( \ + suite_name (); \ + minunit_setup = NULL; \ + minunit_teardown = NULL;) + +/* Configure setup and teardown functions */ +#define MU_SUITE_CONFIGURE(setup_fun, teardown_fun) MU__SAFE_BLOCK ( \ + minunit_setup = setup_fun; \ + minunit_teardown = teardown_fun;) + +/* Test runner */ +#define MU_RUN_TEST(test) MU__SAFE_BLOCK ( \ + if (minunit_setup) (*minunit_setup) (); \ + minunit_status = 0; \ + test (); \ + minunit_run++; \ + if (minunit_status) { \ + minunit_fail++; \ + printf ("F"); \ + } if (minunit_teardown) (*minunit_teardown) ();) + +/* Report */ +#define MU_REPORT() MU__SAFE_BLOCK ( \ + printf ("\r\n\n%d tests, %d assertions, %d failures\r\n", \ + minunit_run, minunit_assert, minunit_fail);) +#define MU_EXIT_CODE minunit_fail + +/* Assertions */ +#define mu_check(test) MU__SAFE_BLOCK ( \ + minunit_assert++; \ + if (!(test)) { \ + printf ("%s failed:\n\t%s:%d: %s", \ + __func__, __FILE__, __LINE__, test); \ + minunit_status = 1; \ + return; \ + } else { \ + printf (".\r\n"); \ + }) + +#define mu_fail(message) MU__SAFE_BLOCK ( \ + minunit_assert++; \ + printf ("%s failed:\n\t%s:%d: %s", \ + __func__, __FILE__, __LINE__, message); \ + minunit_status = 1; \ + return;) + +#define mu_assert(test, message) MU__SAFE_BLOCK ( \ + minunit_assert++; \ + if (!(test)) { \ + printf ("%s failed:\n\t%s:%d: %s", \ + __func__, __FILE__, __LINE__, message); \ + minunit_status = 1; \ + return; \ + } else { \ + printf ("."); \ + }) + +#define mu_assert_int_eq(expected, result) MU__SAFE_BLOCK ( \ + int minunit_tmp_e; \ + int minunit_tmp_r; \ + minunit_assert++; \ + minunit_tmp_e = (expected); \ + minunit_tmp_r = (result); \ + if (minunit_tmp_e != minunit_tmp_r) { \ + printf ("%s failed:\n\t%s:%d: %d expected but was %d", \ + __func__, __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r); \ + minunit_status = 1; \ + return; \ + } else { \ + printf ("."); \ + }) + +// This one requires a strcmp() funktion +/* #define mu_assert_string_eq(expected, result) MU__SAFE_BLOCK ( \ */ +/* const char * minunit_tmp_e = expected; \ */ +/* const char * minunit_tmp_r = result; \ */ +/* minunit_assert++; \ */ +/* if (!minunit_tmp_e) { \ */ +/* minunit_tmp_e = ""; \ */ +/* } if (!minunit_tmp_r) { \ */ +/* minunit_tmp_r = ""; \ */ +/* } if (strcmp (minunit_tmp_e, minunit_tmp_r)) { \ */ +/* printf ("%s failed:\n\t%s:%d: '%s' expected but was '%s'", \ */ +/* __func__, __FILE__, __LINE__, minunit_tmp_e, minunit_tmp_r); \ */ +/* minunit_status = 1; \ */ +/* return; \ */ +/* } else { \ */ +/* printf ("."); \ */ +/* }) */ + + +#endif /* MINUNIT_MINUNIT_H */ diff --git a/thorn/test/test_minunit.h b/thorn/test/test_minunit.h new file mode 100644 index 0000000..9bbc5e4 --- /dev/null +++ b/thorn/test/test_minunit.h @@ -0,0 +1,75 @@ +#include "common/minunit.h" + +static int foo = 0; +static int bar = 0; +/* static const char * foostring = "Thisstring"; */ + +void test_setup (void) { + foo = 7; + bar = 4; +} + +void test_teardown (void) { + /* Nothing */ +} + +MU_TEST (test_check) { + mu_check (foo == 7); +} + +MU_TEST (test_check_fail) { + mu_check (foo != 7); +} + +MU_TEST (test_assert) { + mu_assert (foo == 7, "foo should be 7"); +} + +MU_TEST (test_assert_fail) { + mu_assert (foo != 7, "foo should be <> 7"); +} + +MU_TEST (test_assert_int_eq) { + mu_assert_int_eq (4, bar); +} + +MU_TEST (test_assert_int_eq_fail) { + mu_assert_int_eq (5, bar); +} + + +MU_TEST (test_fail) { + mu_fail ("Fail now!"); +} + +/* MU_TEST (test_string_eq) { */ +/* mu_assert_string_eq ("Thisstring", foostring); */ +/* } */ + +/* MU_TEST (test_string_eq_fail) { */ +/* mu_assert_string_eq ("Thatstring", foostring); */ +/* } */ + + +MU_TEST_SUITE (test_suite) { + MU_SUITE_CONFIGURE (&test_setup, &test_teardown); + + MU_RUN_TEST (test_check); + MU_RUN_TEST (test_assert); + MU_RUN_TEST (test_assert_int_eq); + + MU_RUN_TEST (test_check_fail); + MU_RUN_TEST (test_assert_fail); + MU_RUN_TEST (test_assert_int_eq_fail); + + /* MU_RUN_TEST (test_string_eq); */ + /* MU_RUN_TEST (test_string_eq_fail); */ + + MU_RUN_TEST (test_fail); +} + +int run_tests (void) { + MU_RUN_SUITE (test_suite); + MU_REPORT (); + return MU_EXIT_CODE; +}