unit-tests: implement the unit-testing framework
[oweals/busybox.git] / libbb / bbunit.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * bbunit: Simple unit-testing framework for Busybox.
4  *
5  * Copyright (C) 2014 by Bartosz Golaszewski <bartekgola@gmail.com>
6  *
7  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
8  */
9
10 //kbuild:lib-$(CONFIG_UNIT_TEST) += bbunit.o
11 //applet:IF_UNIT_TEST(APPLET(unit, BB_DIR_USR_BIN, BB_SUID_DROP))
12
13 //usage:#define unit_trivial_usage
14 //usage:       ""
15 //usage:#define unit_full_usage "\n\n"
16 //usage:       "Run the unit-test suite"
17
18 #include "libbb.h"
19
20 #define WANT_TIMING 0
21
22 static llist_t *tests = NULL;
23 static unsigned tests_registered = 0;
24 static int test_retval;
25
26 void bbunit_registertest(struct bbunit_listelem *test)
27 {
28         llist_add_to_end(&tests, test);
29         tests_registered++;
30 }
31
32 void bbunit_settestfailed(void)
33 {
34         test_retval = -1;
35 }
36
37 #if WANT_TIMING
38 static void timeval_diff(struct timeval* res,
39                                 const struct timeval* x,
40                                 const struct timeval* y)
41 {
42         long udiff = x->tv_usec - y->tv_usec;
43
44         res->tv_sec = x->tv_sec - y->tv_sec - (udiff < 0);
45         res->tv_usec = (udiff >= 0 ? udiff : udiff + 1000000);
46 }
47 #endif
48
49 int unit_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) MAIN_EXTERNALLY_VISIBLE;
50 int unit_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
51 {
52         unsigned tests_run = 0;
53         unsigned tests_failed = 0;
54 #if WANT_TIMING
55         struct timeval begin;
56         struct timeval end;
57         struct timeval time_spent;
58         gettimeofday(&begin, NULL);
59 #endif
60
61         bb_error_msg("Running %d test(s)...", tests_registered);
62         for (;;) {
63                 struct bbunit_listelem* el = llist_pop(&tests);
64                 if (!el)
65                         break;
66                 bb_error_msg("Case: [%s]", el->name);
67                 test_retval = 0;
68                 el->testfunc();
69                 if (test_retval < 0) {
70                         bb_error_msg("[ERROR] [%s]: TEST FAILED", el->name);
71                         tests_failed++;
72                 }
73                 tests_run++;
74                 el = el->next;
75         }
76
77 #if WANT_TIMING
78         gettimeofday(&end, NULL);
79         timeval_diff(&time_spent, &end, &begin);
80         bb_error_msg("Elapsed time %u.%06u seconds"
81                         (int)time_spent.tv_sec,
82                         (int)time_spent.tv_usec);
83 #endif
84         if (tests_failed > 0) {
85                 bb_error_msg("[ERROR] %u test(s) FAILED", tests_failed);
86                 return EXIT_FAILURE;
87         }
88         bb_error_msg("All tests passed");
89         return EXIT_SUCCESS;
90 }