• R/O
  • SSH
  • HTTPS

cstl: Commit


Commit MetaInfo

Revision395 (tree)
Time2010-07-24 22:47:15
Authorkatono

Log Message

ユニットテストライブラリを追加。

Change Summary

Incremental Difference

--- branches/try-vfunc/unittest/UnitTest.h (revision 0)
+++ branches/try-vfunc/unittest/UnitTest.h (revision 395)
@@ -0,0 +1,80 @@
1+#ifndef UNITTEST_H_INCLUDED
2+#define UNITTEST_H_INCLUDED
3+
4+#include <string.h>
5+
6+#ifdef __cplusplus
7+extern "C" {
8+#endif
9+
10+/*
11+ * private
12+ */
13+typedef struct TestAssertion {
14+ int passed_flag;
15+ const char *expr;
16+ const char *file;
17+ size_t line;
18+ struct TestAssertion *next;
19+ struct TestAssertion *prev;
20+} TestAssertion;
21+
22+
23+/*
24+ * public
25+ */
26+#define TEST_SUITE_NULL {0, 0, 0, 0}
27+#define TEST_CASE_NULL {0, 0}
28+
29+typedef struct {
30+ /* public */
31+ const char *name;
32+ void (*test)(void);
33+ /* private */
34+ TestAssertion assertion_list;
35+} TestCase;
36+
37+typedef struct {
38+ /* public */
39+ const char *name;
40+ int (*setup)(void);
41+ int (*teardown)(void);
42+ TestCase *test_cases;
43+} TestSuite;
44+
45+
46+/*
47+ * Unit Test API
48+ */
49+void unittest_run_interactive(const TestSuite *suites);
50+void unittest_run_all(const TestSuite *suites);
51+
52+
53+/*
54+ * Assert Macros
55+ */
56+#define ASSERT(expr) assert_impl(((expr) != 0), "ASSERT(" #expr ")", __FILE__, __LINE__, 0)
57+#define ASSERT_FATAL(expr) assert_impl(((expr) != 0), "ASSERT_FATAL(" #expr ")", __FILE__, __LINE__, 1)
58+#define ASSERT_TRUE(expr) assert_impl(((expr) != 0), "ASSERT_TRUE(" #expr ")", __FILE__, __LINE__, 0)
59+#define ASSERT_TRUE_FATAL(expr) assert_impl(((expr) != 0), "ASSERT_TRUE_FATAL(" #expr ")", __FILE__, __LINE__, 1)
60+#define ASSERT_FALSE(expr) assert_impl(((expr) == 0), "ASSERT_FALSE(" #expr ")", __FILE__, __LINE__, 0)
61+#define ASSERT_FALSE_FATAL(expr) assert_impl(((expr) == 0), "ASSERT_FALSE_FATAL(" #expr ")", __FILE__, __LINE__, 1)
62+#define ASSERT_EQUAL(actual, expected) assert_impl(((actual) == (expected)), "ASSERT_EQUAL(" #actual ", " #expected ")", __FILE__, __LINE__, 0)
63+#define ASSERT_NOT_EQUAL(actual, expected) assert_impl(((actual) != (expected)), "ASSERT_NOT_EQUAL(" #actual ", " #expected ")", __FILE__, __LINE__, 0)
64+#define ASSERT_EQUAL_FATAL(actual, expected) assert_impl(((actual) == (expected)), "ASSERT_EQUAL_FATAL(" #actual ", " #expected ")", __FILE__, __LINE__, 1)
65+#define ASSERT_NOT_EQUAL_FATAL(actual, expected) assert_impl(((actual) != (expected)), "ASSERT_NOT_EQUAL_FATAL(" #actual ", " #expected ")", __FILE__, __LINE__, 1)
66+#define ASSERT_STRING_EQUAL(actual, expected) assert_impl((strcmp((actual), (expected)) == 0), "ASSERT_STRING_EQUAL(" #actual ", " #expected ")", __FILE__, __LINE__, 0)
67+#define ASSERT_STRING_NOT_EQUAL(actual, expected) assert_impl((strcmp((actual), (expected)) != 0), "ASSERT_STRING_NOT_EQUAL(" #actual ", " #expected ")", __FILE__, __LINE__, 0)
68+#define ASSERT_STRING_EQUAL_FATAL(actual, expected) assert_impl((strcmp((actual), (expected)) == 0), "ASSERT_STRING_EQUAL_FATAL(" #actual ", " #expected ")", __FILE__, __LINE__, 1)
69+#define ASSERT_STRING_NOT_EQUAL_FATAL(actual, expected) assert_impl((strcmp((actual), (expected)) != 0), "ASSERT_STRING_NOT_EQUAL_FATAL(" #actual ", " #expected ")", __FILE__, __LINE__, 1)
70+#define ASSERT_FAIL(msg) assert_impl(0, "ASSERT_FAIL(" #msg ")", __FILE__, __LINE__, 0)
71+#define ASSERT_FAIL_FATAL(msg) assert_impl(0, "ASSERT_FAIL_FATAL(" #msg ")", __FILE__, __LINE__, 1)
72+
73+void assert_impl(int passed_flag, const char *expr, const char *file, size_t line, int fatal_flag);
74+
75+
76+#ifdef __cplusplus
77+}
78+#endif
79+
80+#endif /* UNITTEST_H_INCLUDED */
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- branches/try-vfunc/unittest/TestSuite.c (revision 0)
+++ branches/try-vfunc/unittest/TestSuite.c (revision 395)
@@ -0,0 +1,101 @@
1+#include "TestCase.h"
2+#include "TestSuite.h"
3+#include "LibcImpl.h"
4+
5+
6+size_t TestSuite_init(const TestSuite *self)
7+{
8+ size_t i;
9+ for (i = 0; self->test_cases[i].name != 0; i++) {
10+ TestCase_init(&self->test_cases[i]);
11+ }
12+ return i;
13+}
14+
15+size_t TestSuite_cleanup(const TestSuite *self)
16+{
17+ size_t i;
18+ for (i = 0; self->test_cases[i].name != 0; i++) {
19+ TestCase_cleanup(&self->test_cases[i]);
20+ }
21+ return i;
22+}
23+
24+int TestSuite_setup(const TestSuite *self)
25+{
26+ int ret = 0;
27+ if (self->setup) {
28+ ret = self->setup();
29+ }
30+ return ret;
31+}
32+
33+int TestSuite_teardown(const TestSuite *self)
34+{
35+ int ret = 0;
36+ if (self->teardown) {
37+ ret = self->teardown();
38+ }
39+ return ret;
40+}
41+
42+enum TestSuiteErr TestSuite_test(const TestSuite *self, size_t *ncases, size_t *ncases_failed,
43+ size_t *nasserts, size_t *nasserts_failed)
44+{
45+ size_t i;
46+ int err;
47+ *ncases = *ncases_failed = *nasserts = *nasserts_failed = 0;
48+ PRINTF("Suite: %s\n", self->name);
49+ err = TestSuite_setup(self);
50+ if (err) {
51+ PRINTF(" SETUP FAILED: error[%d]\n", err);
52+ PRINTF("\n");
53+ return SETUP_NG;
54+ }
55+ for (i = 0; self->test_cases[i].name != 0; i++) {
56+ size_t na, naf;
57+ TestCase_test(&self->test_cases[i], &na, &naf);
58+ (*nasserts) += na;
59+ (*nasserts_failed) += naf;
60+ if (naf > 0) {
61+ (*ncases_failed)++;
62+ }
63+ }
64+ (*ncases) += i;
65+ err = TestSuite_teardown(self);
66+ if (err) {
67+ PRINTF(" TEARDOWN FAILED: error[%d]\n", err);
68+ PRINTF("\n");
69+ return TEARDOWN_NG;
70+ }
71+ PRINTF("\n");
72+ return SUITE_OK;
73+}
74+
75+enum TestSuiteErr TestSuite_test_selected(const TestSuite *self, int case_idx, size_t *ncases, size_t *ncases_failed,
76+ size_t *nasserts, size_t *nasserts_failed)
77+{
78+ int err;
79+ *ncases = *ncases_failed = *nasserts = *nasserts_failed = 0;
80+ PRINTF("Suite: %s\n", self->name);
81+ err = TestSuite_setup(self);
82+ if (err) {
83+ PRINTF(" SETUP FAILED: error[%d]\n", err);
84+ PRINTF("\n");
85+ return SETUP_NG;
86+ }
87+ TestCase_test(&self->test_cases[case_idx], nasserts, nasserts_failed);
88+ if (*nasserts_failed > 0) {
89+ *ncases_failed = 1;
90+ }
91+ *ncases = 1;
92+ err = TestSuite_teardown(self);
93+ if (err) {
94+ PRINTF(" TEARDOWN FAILED: error[%d]\n", err);
95+ PRINTF("\n");
96+ return TEARDOWN_NG;
97+ }
98+ PRINTF("\n");
99+ return SUITE_OK;
100+}
101+
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- branches/try-vfunc/unittest/LibcImpl.c (revision 0)
+++ branches/try-vfunc/unittest/LibcImpl.c (revision 395)
@@ -0,0 +1,65 @@
1+#include "LibcImpl.h"
2+
3+#ifdef NO_STD_PRINTF
4+#include <stdarg.h>
5+#include <stdio.h>
6+
7+int LibcImpl_printf(const char *format, ...)
8+{
9+ /* NOTE: attention to buffer overflow */
10+ static char buf[1024];
11+ va_list ap;
12+ va_start(ap, format);
13+ vsprintf(buf, format, ap);
14+ va_end(ap);
15+
16+ /* TODO */
17+ /* ex. SCI write */
18+
19+ return 0;
20+}
21+
22+char *LibcImpl_fgets(char *s, int size, void *stream)
23+{
24+ /* TODO */
25+ /* ex. SCI read */
26+
27+ return s;
28+}
29+#endif
30+
31+#ifdef NO_STD_MALLOC
32+#include "UnitTest.h"
33+
34+/* You can change the value of MAX_NUM_ASSERTS. */
35+#define MAX_NUM_ASSERTS 256
36+
37+typedef struct {
38+ TestAssertion obj;
39+ int used_flag;
40+} TestAssertionBlock;
41+
42+static TestAssertionBlock pool[MAX_NUM_ASSERTS];
43+
44+void *LibcImpl_malloc(size_t size)
45+{
46+ size_t i;
47+ TestAssertionBlock *p = pool;
48+ (void) size;
49+ for (i = 0; i < MAX_NUM_ASSERTS; i++) {
50+ if (p[i].used_flag == 0) {
51+ p[i].used_flag = 1;
52+ return &p[i];
53+ }
54+ }
55+ return 0;
56+}
57+
58+void LibcImpl_free(void *ptr)
59+{
60+ if (!ptr) return;
61+ ((TestAssertionBlock *) ptr)->used_flag = 0;
62+}
63+#endif
64+
65+
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- branches/try-vfunc/unittest/TestCase.c (revision 0)
+++ branches/try-vfunc/unittest/TestCase.c (revision 395)
@@ -0,0 +1,115 @@
1+#include "TestCase.h"
2+#include "LibcImpl.h"
3+
4+#define LIST_BEGIN(list) (list)->next
5+#define LIST_END(list) (list)
6+
7+static TestCase *current_case;
8+static jmp_buf fatal_jmp;
9+
10+static TestAssertion *TestAssertion_new(int passed_flag, const char *expr, const char *file, size_t line);
11+static void TestAssertion_delete(TestAssertion *self);
12+static void list_push(TestAssertion *list, TestAssertion *node);
13+static TestAssertion *list_pop(TestAssertion *list);
14+static int list_empty(TestAssertion *list);
15+
16+void TestCase_init(TestCase *self)
17+{
18+ self->assertion_list.next = &self->assertion_list;
19+ self->assertion_list.prev = &self->assertion_list;
20+}
21+
22+void TestCase_cleanup(TestCase *self)
23+{
24+ TestAssertion *list = &self->assertion_list;
25+ while (!list_empty(list)) {
26+ TestAssertion *tmp = list_pop(list);
27+ TestAssertion_delete(tmp);
28+ }
29+}
30+
31+void TestCase_test(TestCase *self, size_t *nasserts, size_t *nasserts_failed)
32+{
33+ int failed_flag = 0;
34+ size_t n = 1;
35+ TestAssertion *pos;
36+ TestAssertion *list = &self->assertion_list;
37+ current_case = self;
38+ *nasserts = 0;
39+ *nasserts_failed = 0;
40+ PRINTF(" Test: %s ... ", self->name);
41+ if (SETJMP(fatal_jmp) == 0) {
42+ self->test();
43+ }
44+ for (pos = LIST_BEGIN(list); pos != LIST_END(list); pos = pos->next) {
45+ (*nasserts)++;
46+ if (!pos->passed_flag) {
47+ (*nasserts_failed)++;
48+ if (!failed_flag) {
49+ failed_flag = 1;
50+ PRINTF("FAILED\n");
51+ }
52+ PRINTF(" %d. %s(%d) %s\n", n, pos->file, pos->line, pos->expr);
53+ n++;
54+ }
55+ }
56+ if (!failed_flag) {
57+ PRINTF("passed\n");
58+ }
59+}
60+
61+void assert_impl(int passed_flag, const char *expr, const char *file, size_t line, int fatal_flag)
62+{
63+ TestAssertion *node = TestAssertion_new(passed_flag, expr, file, line);
64+ if (node) {
65+ list_push(&current_case->assertion_list, node);
66+ }
67+ if (fatal_flag && !passed_flag) {
68+ /* FATAL */
69+ LONGJMP(fatal_jmp, 1);
70+ }
71+}
72+
73+static TestAssertion *TestAssertion_new(int passed_flag, const char *expr, const char *file, size_t line)
74+{
75+ TestAssertion *self = (TestAssertion *) MALLOC(sizeof(TestAssertion));
76+ if (!self) {
77+ PRINTF("malloc failed!!\n");
78+ return 0;
79+ }
80+ self->passed_flag = passed_flag;
81+ self->expr = expr;
82+ self->file = file;
83+ self->line = line;
84+ self->next = self->prev = 0;
85+ return self;
86+}
87+
88+static void TestAssertion_delete(TestAssertion *self)
89+{
90+ if (!self) return;
91+ FREE(self);
92+}
93+
94+static void list_push(TestAssertion *list, TestAssertion *node)
95+{
96+ node->prev = list->prev;
97+ node->next = list;
98+ list->prev->next = node;
99+ list->prev = node;
100+}
101+
102+static TestAssertion *list_pop(TestAssertion *list)
103+{
104+ TestAssertion *node;
105+ node = list->next;
106+ node->prev->next = node->next;
107+ node->next->prev = node->prev;
108+ return node;
109+}
110+
111+static int list_empty(TestAssertion *list)
112+{
113+ return list->next == list;
114+}
115+
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- branches/try-vfunc/unittest/Makefile (revision 0)
+++ branches/try-vfunc/unittest/Makefile (revision 395)
@@ -0,0 +1,30 @@
1+CFLAGS = -Wall -ansi -pedantic-errors -g
2+PROG = libunittest.a
3+OBJS = UnitTest.o\
4+ TestCase.o\
5+ TestSuite.o\
6+ LibcImpl.o\
7+ $(NULL)
8+
9+all: $(PROG)
10+
11+.SUFFIXES: .c .o
12+
13+.c .o:
14+ $(CC) $(CFLAGS) -c $<
15+
16+
17+$(PROG): $(OBJS)
18+ $(AR) rcs $(PROG) $^
19+
20+
21+.PHONY: clean
22+clean:
23+ rm -f *.o *.a
24+
25+UnitTest.o: TestSuite.h LibcImpl.h
26+TestCase.h: UnitTest.h
27+TestCase.o: TestCase.h LibcImpl.h
28+TestSuite.h: UnitTest.h
29+TestSuite.o: TestCase.h TestSuite.h LibcImpl.h
30+LibcImpl.o: LibcImpl.h UnitTest.h
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- branches/try-vfunc/unittest/TestSuite.h (revision 0)
+++ branches/try-vfunc/unittest/TestSuite.h (revision 395)
@@ -0,0 +1,22 @@
1+#ifndef TESTSUITE_H_INCLUDED
2+#define TESTSUITE_H_INCLUDED
3+
4+#include "UnitTest.h"
5+
6+enum TestSuiteErr {
7+ SUITE_OK,
8+ SETUP_NG,
9+ TEARDOWN_NG
10+};
11+
12+size_t TestSuite_init(const TestSuite *self);
13+size_t TestSuite_cleanup(const TestSuite *self);
14+int TestSuite_setup(const TestSuite *self);
15+int TestSuite_teardown(const TestSuite *self);
16+enum TestSuiteErr TestSuite_test(const TestSuite *self, size_t *ncases, size_t *ncases_failed,
17+ size_t *nasserts, size_t *nasserts_failed);
18+enum TestSuiteErr TestSuite_test_selected(const TestSuite *self, int case_idx, size_t *ncases, size_t *ncases_failed,
19+ size_t *nasserts, size_t *nasserts_failed);
20+
21+
22+#endif /* TESTSUITE_H_INCLUDED */
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- branches/try-vfunc/unittest/UnitTest.c (revision 0)
+++ branches/try-vfunc/unittest/UnitTest.c (revision 395)
@@ -0,0 +1,338 @@
1+#include <string.h>
2+#include <stdlib.h>
3+#include "TestSuite.h"
4+#include "LibcImpl.h"
5+
6+static char input_buf[64];
7+static jmp_buf quit_jmp;
8+
9+static size_t suites_total, suites_ran, suites_failed;
10+static size_t tests_total, tests_ran, tests_failed;
11+static size_t asserts_total, asserts_ran, asserts_failed;
12+static size_t setup_failed, teardown_failed;
13+
14+static void clear_values(void)
15+{
16+ suites_total = suites_ran = suites_failed = 0;
17+ tests_total = tests_ran = tests_failed = 0;
18+ asserts_total = asserts_ran = asserts_failed = 0;
19+ setup_failed = teardown_failed = 0;
20+}
21+
22+static void init(const TestSuite *suites)
23+{
24+ size_t i;
25+ clear_values();
26+ for (i = 0; suites[i].name != 0; i++) {
27+ size_t ncases;
28+ ncases = TestSuite_init(&suites[i]);
29+ tests_total += ncases;
30+ }
31+ suites_total += i;
32+}
33+
34+static void cleanup(const TestSuite *suites)
35+{
36+ size_t i;
37+ clear_values();
38+ for (i = 0; suites[i].name != 0; i++) {
39+ size_t ncases;
40+ ncases = TestSuite_cleanup(&suites[i]);
41+ tests_total += ncases;
42+ }
43+ suites_total += i;
44+}
45+
46+static void print_result(void)
47+{
48+ PRINTF("Type Total Ran Passed Failed\n");
49+ PRINTF("suites %7d %7d n/a %7d", suites_total, suites_ran, suites_failed);
50+ if (setup_failed || teardown_failed) {
51+ PRINTF("(setup:%d/teardown:%d)\n", setup_failed, teardown_failed);
52+ } else {
53+ PRINTF("\n");
54+ }
55+ PRINTF("tests %7d %7d %7d %7d\n", tests_total, tests_ran, tests_ran - tests_failed, tests_failed);
56+ PRINTF("asserts %7d %7d %7d %7d\n", asserts_total, asserts_ran, asserts_ran - asserts_failed, asserts_failed);
57+ PRINTF("\n");
58+}
59+
60+static void run_all(const TestSuite *suites)
61+{
62+ size_t i;
63+ for (i = 0; suites[i].name != 0; i++) {
64+ size_t nc, ncf, na, naf;
65+ enum TestSuiteErr ret;
66+ ret = TestSuite_test(&suites[i], &nc, &ncf, &na, &naf);
67+ asserts_total += na;
68+ asserts_ran += na;
69+ asserts_failed += naf;
70+ tests_ran += nc;
71+ tests_failed += ncf;
72+ if (ncf > 0 || ret != SUITE_OK) {
73+ suites_failed++;
74+ if (ret == SETUP_NG) {
75+ setup_failed++;
76+ } else if (ret == TEARDOWN_NG) {
77+ teardown_failed++;
78+ }
79+ }
80+ }
81+ suites_ran = i;
82+ print_result();
83+ cleanup(suites);
84+}
85+
86+static void run_suite_selected(const TestSuite *suites, int suite_idx, int case_idx)
87+{
88+ size_t nc, ncf, na, naf;
89+ enum TestSuiteErr ret;
90+ ret = TestSuite_test_selected(&suites[suite_idx], case_idx, &nc, &ncf, &na, &naf);
91+ asserts_total = na;
92+ asserts_ran = na;
93+ asserts_failed = naf;
94+ tests_ran = nc;
95+ tests_failed = ncf;
96+ if (ncf > 0 || ret != SUITE_OK) {
97+ suites_failed = 1;
98+ if (ret == SETUP_NG) {
99+ setup_failed++;
100+ } else if (ret == TEARDOWN_NG) {
101+ teardown_failed++;
102+ }
103+ }
104+ suites_ran = 1;
105+ print_result();
106+ cleanup(suites);
107+}
108+
109+static void run_suite(const TestSuite *suites, int suite_idx)
110+{
111+ size_t nc, ncf, na, naf;
112+ enum TestSuiteErr ret;
113+ ret = TestSuite_test(&suites[suite_idx], &nc, &ncf, &na, &naf);
114+ asserts_total = na;
115+ asserts_ran = na;
116+ asserts_failed = naf;
117+ tests_ran = nc;
118+ tests_failed = ncf;
119+ if (ncf > 0 || ret != SUITE_OK) {
120+ suites_failed = 1;
121+ if (ret == SETUP_NG) {
122+ setup_failed++;
123+ } else if (ret == TEARDOWN_NG) {
124+ teardown_failed++;
125+ }
126+ }
127+ suites_ran = 1;
128+ print_result();
129+ cleanup(suites);
130+}
131+
132+static void show_list_tests(const TestCase *cases)
133+{
134+ size_t i;
135+ PRINTF("List Tests\n");
136+ PRINTF(" Number Name\n");
137+ for (i = 0; cases[i].name != 0; i++) {
138+ PRINTF(" %-6d %s\n", i + 1, cases[i].name);
139+ }
140+ PRINTF("\n");
141+}
142+
143+static void show_list_suites(const TestSuite *suites)
144+{
145+ size_t i;
146+ PRINTF("List Suites\n");
147+ PRINTF(" Number Name\n");
148+ for (i = 0; suites[i].name != 0; i++) {
149+ PRINTF(" %-6d %s\n", i + 1, suites[i].name);
150+ }
151+ PRINTF("\n");
152+}
153+
154+static int find_test_name(const TestCase *cases, const char *input_str)
155+{
156+ int i;
157+ for (i = 0; cases[i].name != 0; i++) {
158+ if (strcmp(cases[i].name, input_str) == 0) {
159+ break;
160+ }
161+ }
162+ if (cases[i].name == 0) {
163+ return -1;
164+ }
165+ return i;
166+}
167+
168+static int get_ncases(const TestCase *cases)
169+{
170+ int i;
171+ for (i = 0; cases[i].name != 0; i++) ;
172+ return i;
173+}
174+
175+static int find_test_number(const TestCase *cases, const char *input_str)
176+{
177+ int n;
178+ n = atoi(input_str);
179+ if (n <= 0 || get_ncases(cases) + 1 <= n) {
180+ return -1;
181+ }
182+ return n - 1;
183+}
184+
185+static void select_test(const TestSuite *suites, int suite_idx)
186+{
187+ int idx;
188+ char *p;
189+ const TestSuite *suite = &suites[suite_idx];
190+ PRINTF("Enter Test's Number or Name : ");
191+ FGETS(input_buf, sizeof input_buf, stdin);
192+ p = strpbrk(input_buf, "\r\n");
193+ if (p) *p = '\0';
194+
195+ idx = find_test_number(suite->test_cases, input_buf);
196+ if (idx == -1) {
197+ idx = find_test_name(suite->test_cases, input_buf);
198+ if (idx == -1) {
199+ PRINTF("\nTest not found.\n");
200+ return;
201+ }
202+ }
203+ PRINTF("\n");
204+
205+ run_suite_selected(suites, suite_idx, idx);
206+}
207+
208+static int find_suite_name(const TestSuite *suites, const char *input_str)
209+{
210+ int i;
211+ for (i = 0; suites[i].name != 0; i++) {
212+ if (strcmp(suites[i].name, input_str) == 0) {
213+ break;
214+ }
215+ }
216+ if (suites[i].name == 0) {
217+ return -1;
218+ }
219+ return i;
220+}
221+
222+static int get_nsuites(const TestSuite *suites)
223+{
224+ int i;
225+ for (i = 0; suites[i].name != 0; i++) ;
226+ return i;
227+}
228+
229+static int find_suite_number(const TestSuite *suites, const char *input_str)
230+{
231+ int n;
232+ n = atoi(input_str);
233+ if (n <= 0 || get_nsuites(suites) + 1 <= n) {
234+ return -1;
235+ }
236+ return n - 1;
237+}
238+
239+static void select_suite(const TestSuite *suites)
240+{
241+ int idx;
242+ char *p;
243+ const TestSuite *selected_suite;
244+ PRINTF("Enter Suite's Number or Name : ");
245+ FGETS(input_buf, sizeof input_buf, stdin);
246+ p = strpbrk(input_buf, "\r\n");
247+ if (p) *p = '\0';
248+
249+ idx = find_suite_number(suites, input_buf);
250+ if (idx == -1) {
251+ idx = find_suite_name(suites, input_buf);
252+ if (idx == -1) {
253+ PRINTF("\nSuite not found.\n");
254+ return;
255+ }
256+ }
257+
258+ selected_suite = &suites[idx];
259+
260+ PRINTF("\n");
261+ while (1) {
262+ PRINTF("================== Suite : %s ==================\n", selected_suite->name);
263+ PRINTF("(R)un all, (S)elect test, (L)ist tests, (M)ove up, (Q)uit\n");
264+ PRINTF("Enter Command : ");
265+ FGETS(input_buf, sizeof input_buf, stdin);
266+ PRINTF("\n");
267+ switch (input_buf[0]) {
268+ case 'r':
269+ case 'R':
270+ run_suite(suites, idx);
271+ break;
272+ case 's':
273+ case 'S':
274+ select_test(suites, idx);
275+ break;
276+ case 'l':
277+ case 'L':
278+ show_list_tests(selected_suite->test_cases);
279+ break;
280+ case 'm':
281+ case 'M':
282+ return;
283+ case 'q':
284+ case 'Q':
285+ LONGJMP(quit_jmp, 1);
286+ break;
287+ default:
288+ break;
289+ }
290+ PRINTF("\n");
291+ }
292+}
293+
294+void unittest_run_interactive(const TestSuite *suites)
295+{
296+ init(suites);
297+ if (SETJMP(quit_jmp)) {
298+ /* Suite Menu's Quit */
299+ return;
300+ }
301+ while (1) {
302+ PRINTF("****************** Unit Test ******************\n");
303+ PRINTF("(R)un all, (S)elect suite, (L)ist suites, (Q)uit\n");
304+ PRINTF("Enter Command : ");
305+ FGETS(input_buf, sizeof input_buf, stdin);
306+ PRINTF("\n");
307+ switch (input_buf[0]) {
308+ case 'r':
309+ case 'R':
310+ run_all(suites);
311+ break;
312+ case 's':
313+ case 'S':
314+ select_suite(suites);
315+ break;
316+ case 'l':
317+ case 'L':
318+ show_list_suites(suites);
319+ break;
320+ case 'q':
321+ case 'Q':
322+ return;
323+ default:
324+ break;
325+ }
326+ PRINTF("\n");
327+ }
328+}
329+
330+
331+void unittest_run_all(const TestSuite *suites)
332+{
333+ PRINTF("****************** Unit Test ******************\n");
334+ PRINTF("\n");
335+ init(suites);
336+ run_all(suites);
337+}
338+
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- branches/try-vfunc/unittest/LibcImpl.h (revision 0)
+++ branches/try-vfunc/unittest/LibcImpl.h (revision 395)
@@ -0,0 +1,44 @@
1+#ifndef LIBCIMPL_H_INCLUDED
2+#define LIBCIMPL_H_INCLUDED
3+
4+
5+#ifndef NO_STD_PRINTF
6+# include <stdio.h>
7+# define PRINTF printf
8+# define FGETS fgets
9+#else
10+# ifdef stdin
11+# undef stdin
12+# endif
13+# define stdin 0
14+# define PRINTF LibcImpl_printf
15+# define FGETS LibcImpl_fgets
16+int LibcImpl_printf(const char *format, ...);
17+char *LibcImpl_fgets(char *s, int size, void *stream);
18+#endif
19+
20+
21+#ifndef NO_STD_MALLOC
22+# include <stdlib.h>
23+# define MALLOC malloc
24+# define FREE free
25+#else
26+# define MALLOC LibcImpl_malloc
27+# define FREE LibcImpl_free
28+void *LibcImpl_malloc(size_t size);
29+void LibcImpl_free(void *ptr);
30+#endif
31+
32+
33+#ifndef NO_STD_SETJMP
34+# include <setjmp.h>
35+# define SETJMP setjmp
36+# define LONGJMP longjmp
37+#else
38+# define jmp_buf int
39+# define SETJMP(j) ((void)(j), 0)
40+# define LONGJMP(j, v)
41+#endif
42+
43+
44+#endif /* LIBCIMPL_H_INCLUDED */
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- branches/try-vfunc/unittest/TestCase.h (revision 0)
+++ branches/try-vfunc/unittest/TestCase.h (revision 395)
@@ -0,0 +1,12 @@
1+#ifndef TESTCASE_H_INCLUDED
2+#define TESTCASE_H_INCLUDED
3+
4+#include "UnitTest.h"
5+
6+
7+void TestCase_init(TestCase *self);
8+void TestCase_cleanup(TestCase *self);
9+void TestCase_test(TestCase *self, size_t *nasserts, size_t *nasserts_failed);
10+
11+
12+#endif /* TESTCASE_H_INCLUDED */
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- branches/try-vfunc/unittest/sample/test_1.c (revision 0)
+++ branches/try-vfunc/unittest/sample/test_1.c (revision 395)
@@ -0,0 +1,43 @@
1+#include "test.h"
2+
3+int test_1_setup(void)
4+{
5+ return 0;
6+}
7+
8+int test_1_teardown(void)
9+{
10+ return 0;
11+}
12+
13+
14+void test_1_1(void)
15+{
16+ ASSERT_EQUAL(1, 0);
17+ ASSERT_NOT_EQUAL(1, 1);
18+ ASSERT_EQUAL_FATAL(0, 1);
19+ ASSERT(2 == 1);
20+}
21+
22+void test_1_2(void)
23+{
24+ ASSERT(0 == 3);
25+ ASSERT(1 == 1);
26+ ASSERT_STRING_NOT_EQUAL_FATAL("hoge", "hoge");
27+}
28+
29+void test_1_3(void)
30+{
31+ ASSERT_FAIL("hoge");
32+ ASSERT(0 == 0);
33+ ASSERT(1 == 1);
34+ ASSERT(0 == 0);
35+ ASSERT(1 == 1);
36+}
37+
38+TestCase test_1_cases[] = {
39+ { "test_1_1", test_1_1 },
40+ { "test_1_2", test_1_2 },
41+ { "test_1_3", test_1_3 },
42+ TEST_CASE_NULL,
43+};
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- branches/try-vfunc/unittest/sample/test_2.c (revision 0)
+++ branches/try-vfunc/unittest/sample/test_2.c (revision 395)
@@ -0,0 +1,32 @@
1+#include "test.h"
2+
3+
4+void test_2_1(void)
5+{
6+ ASSERT(1 == 1);
7+ ASSERT_FATAL(1 == 1);
8+ ASSERT(2 == 2);
9+}
10+
11+void test_2_2(void)
12+{
13+ ASSERT_TRUE(1);
14+ ASSERT(1 == 1);
15+ ASSERT(1 == 1);
16+}
17+
18+void test_2_3(void)
19+{
20+ ASSERT(0 == 0);
21+ ASSERT(1 == 1);
22+ ASSERT(0 == 0);
23+ ASSERT(1 == 1);
24+}
25+
26+TestCase test_2_cases[] = {
27+ { "test_2_1", test_2_1 },
28+ { "test_2_2", test_2_2 },
29+ { "test_2_3", test_2_3 },
30+ TEST_CASE_NULL,
31+};
32+
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- branches/try-vfunc/unittest/sample/main.c (revision 0)
+++ branches/try-vfunc/unittest/sample/main.c (revision 395)
@@ -0,0 +1,20 @@
1+#include "../UnitTest.h"
2+#include "test.h"
3+
4+TestSuite suites[] = {
5+ { "test_1", test_1_setup, test_1_teardown, test_1_cases },
6+ { "test_2", 0, 0, test_2_cases },
7+ TEST_SUITE_NULL,
8+};
9+
10+
11+int main(int argc, char **argv)
12+{
13+ if (argc >= 2) {
14+ unittest_run_interactive(suites);
15+ } else {
16+ unittest_run_all(suites);
17+ }
18+ return 0;
19+}
20+
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- branches/try-vfunc/unittest/sample/test.h (revision 0)
+++ branches/try-vfunc/unittest/sample/test.h (revision 395)
@@ -0,0 +1,12 @@
1+#ifndef TEST_H
2+#define TEST_H
3+
4+#include "../UnitTest.h"
5+
6+int test_1_setup(void);
7+int test_1_teardown(void);
8+extern TestCase test_1_cases[];
9+
10+extern TestCase test_2_cases[];
11+
12+#endif /* TEST_H */
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
--- branches/try-vfunc/unittest/sample/Makefile (revision 0)
+++ branches/try-vfunc/unittest/sample/Makefile (revision 395)
@@ -0,0 +1,44 @@
1+CFLAGS = -Wall -ansi -pedantic-errors -g
2+PROG = sample
3+OBJS = main.o\
4+ test_1.o\
5+ test_2.o\
6+ ../libunittest.a\
7+ $(NULL)
8+UTOBJS = ../UnitTest.o\
9+ ../TestCase.o\
10+ ../TestSuite.o\
11+ ../LibcImpl.o\
12+ $(NULL)
13+
14+all: $(PROG)
15+
16+.SUFFIXES: .c .o
17+
18+.c .o:
19+ $(CC) $(CFLAGS) -c $<
20+
21+
22+$(PROG): $(OBJS)
23+ $(CC) $(CFLAGS) $(OBJS) -o $@
24+
25+
26+../libunittest.a: $(UTOBJS)
27+ cd .. && $(MAKE)
28+
29+
30+.PHONY: clean
31+clean:
32+ rm -f *.o $(PROG) ../*.o ../*.a
33+
34+main.o: ../UnitTest.h test.h
35+test.h: ../UnitTest.h
36+test_1.o: test.h
37+test_2.o: test.h
38+
39+../UnitTest.o: ../TestSuite.h ../LibcImpl.h
40+../TestCase.h: ../UnitTest.h
41+../TestCase.o: ../TestCase.h ../LibcImpl.h
42+../TestSuite.h: ../UnitTest.h
43+../TestSuite.o: ../TestCase.h ../TestSuite.h ../LibcImpl.h
44+../LibcImpl.o: ../LibcImpl.h ../UnitTest.h
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Show on old repository browser