diff --git a/lib/unittest/all_tests.c b/lib/unittest/all_tests.c index e7bf101d..7467a2f8 100644 --- a/lib/unittest/all_tests.c +++ b/lib/unittest/all_tests.c @@ -14,60 +14,75 @@ #include #include #include +#include -static struct test_case_element *test_case_list = NULL; -static struct test_case_element *failed_test_case_list = NULL; +static struct list_node test_case_list = LIST_INITIAL_VALUE(test_case_list); + +#if WITH_LIB_CONSOLE +#include + +#if RUN_UNITTESTS_AT_BOOT +static void unittest_run_at_boot(uint level) { + const char run_at_boot_script[] = "sleep 5; ut all"; + console_t *con = console_create(false); + if (con) { + console_run_script(con, run_at_boot_script); + // TODO: destroy console afterwards + } +} + +LK_INIT_HOOK(unittest_at_boot, unittest_run_at_boot, LK_INIT_LEVEL_LAST) +#endif +#endif /* * Registers a test case with the unit test framework. */ void unittest_register_test_case(struct test_case_element *elem) { DEBUG_ASSERT(elem); - DEBUG_ASSERT(elem->next == NULL); - elem->next = test_case_list; - test_case_list = elem; + DEBUG_ASSERT(!list_in_list(&elem->node)); + list_add_tail(&test_case_list, &elem->node); } /* * Runs all registered test cases. */ bool run_all_tests(void) { - unsigned int n_tests = 0; + unsigned int n_tests = 0; unsigned int n_success = 0; - unsigned int n_failed = 0; + unsigned int n_failed = 0; + struct list_node failed_test_case_list = LIST_INITIAL_VALUE(failed_test_case_list); bool all_success = true; - struct test_case_element *current = test_case_list; - while (current) { + struct test_case_element *current; + list_for_every_entry(&test_case_list, current, struct test_case_element, node) { if (!current->test_case()) { - current->failed_next = failed_test_case_list; - failed_test_case_list = current; + list_add_tail(&failed_test_case_list, ¤t->failed_node); all_success = false; + n_failed++; + } else { + n_success++; } - current = current->next; n_tests++; } - if (all_success) { - n_success = n_tests; - unittest_printf("SUCCESS! All test cases passed!\n"); - } else { - struct test_case_element *failed = failed_test_case_list; - while (failed) { - struct test_case_element *failed_next = - failed->failed_next; - failed->failed_next = NULL; - failed = failed_next; - n_failed++; - } - n_success = n_tests - n_failed; - failed_test_case_list = NULL; - } + unittest_printf("\n====================================================\n"); + unittest_printf(" CASES: %d SUCCESS: %d FAILED: %d ", + n_tests, n_success, n_failed); + unittest_printf("\n====================================================\n"); - unittest_printf("\n====================================================\n"); - unittest_printf (" CASES: %d SUCCESS: %d FAILED: %d ", - n_tests, n_success, n_failed); - unittest_printf("\n====================================================\n"); + if (all_success) { + unittest_printf("\nSUCCESS! All test cases passed\n"); + } else { + unittest_printf("\nFAILURE! Some test cases failed:\n"); + struct test_case_element *failed; + struct test_case_element *temp; + list_for_every_entry_safe(&failed_test_case_list, failed, temp, struct test_case_element, failed_node) { + unittest_printf(" %s\n", failed->name); + list_delete(&failed->failed_node); + } + unittest_printf("\n"); + } return all_success; } @@ -87,13 +102,15 @@ usage: bool result = run_all_tests(); printf("UNIT TEST: run_all_tests return %u\n", result); } else if (!strcmp(argv[1].str, "list")) { - for (struct test_case_element *current = test_case_list; current; current = current->next) { + struct test_case_element *current; + list_for_every_entry(&test_case_list, current, struct test_case_element, node) { puts(current->name); } } else { // look for unit test that matches the string name bool found_test = false; - for (struct test_case_element *current = test_case_list; current; current = current->next) { + struct test_case_element *current; + list_for_every_entry(&test_case_list, current, struct test_case_element, node) { if (strcmp(argv[1].str, current->name) == 0) { found_test = true; current->test_case(); @@ -112,4 +129,3 @@ usage: STATIC_COMMAND_START STATIC_COMMAND("ut", "run some or all of the unit tests", do_unittests) STATIC_COMMAND_END(unit_tests); - diff --git a/lib/unittest/include/lib/unittest.h b/lib/unittest/include/lib/unittest.h index 5b389ae9..209ff70e 100644 --- a/lib/unittest/include/lib/unittest.h +++ b/lib/unittest/include/lib/unittest.h @@ -54,6 +54,7 @@ * lib/unittest \ */ #include +#include #include #include #include @@ -116,8 +117,8 @@ __END_CDECLS return all_ok; \ } \ static struct test_case_element _##case_name##_element = { \ - .next = NULL, \ - .failed_next = NULL, \ + .node = LIST_INITIAL_CLEARED_VALUE, \ + .failed_node = LIST_INITIAL_CLEARED_VALUE, \ .name = #case_name, \ .test_case = case_name, \ }; \ @@ -387,8 +388,8 @@ __BEGIN_CDECLS * The list of test cases is made up of these elements. */ struct test_case_element { - struct test_case_element *next; - struct test_case_element *failed_next; + struct list_node node; + struct list_node failed_node; const char *name; bool (*test_case)(void); }; diff --git a/lib/unittest/rules.mk b/lib/unittest/rules.mk index 0b034c3e..2d7d18f6 100644 --- a/lib/unittest/rules.mk +++ b/lib/unittest/rules.mk @@ -6,4 +6,9 @@ MODULE_SRCS := \ $(LOCAL_DIR)/unittest.c \ $(LOCAL_DIR)/all_tests.c \ +ifeq (true,$(call TOBOOL,$(RUN_UNITTESTS_AT_BOOT))) +$(info Boot unit tests enabled) +MODULE_DEFINES += RUN_UNITTESTS_AT_BOOT=1 +endif + include make/module.mk diff --git a/makefile b/makefile index a8e9c180..ee7407ed 100644 --- a/makefile +++ b/makefile @@ -27,6 +27,7 @@ export LKINC export BUILDROOT export DEFAULT_PROJECT export TOOLCHAIN_PREFIX +export RUN_UNITTESTS_AT_BOOT # veneer makefile that calls into the engine with lk as the build root # if we're the top level invocation, call ourselves with additional args