]> git.llucax.com Git - software/mutest.git/blob - mutest.h
Add make release target (for internal use only)
[software/mutest.git] / mutest.h
1 /*
2  * This file is part of mutest, a simple micro unit testing framework for C.
3  *
4  * mutest was written by Leandro Lucarella <llucax@gmail.com> and is released
5  * under the BOLA license, please see the LICENSE file or visit:
6  * http://blitiri.com.ar/p/bola/
7  *
8  * This header file should be included in the source files that will make up
9  * a test suite. It's used for both C and Python implementation, but when
10  * using the Python implementation you should define the MUTEST_PY macro.
11  * If you implement your mu_run_suites() function yourself, you probably will
12  * need to include this header too (see mkmutest).
13  *
14  * Please, read the README file for more details.
15  */
16
17 #include <stdio.h> /* fprintf() */
18
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22
23 /* verbosity level (each level shows all the previous levels too) */
24 enum {
25         MU_QUIET = 0, /* be completely quiet */
26         MU_ERROR,     /* shows errors only */
27         MU_SUMMARY,   /* shows a summary */
28         MU_SUITE,     /* shows test suites progress */
29         MU_CASE,      /* shows test cases progress */
30         MU_CHECK      /* shows the current running check */
31 };
32
33 /* print a message according to the verbosity level */
34 #define mu_print(level, ...) \
35         do { \
36                 if (mutest_verbose_level >= level) { \
37                         if (mutest_verbose_level == MU_ERROR) \
38                                 fprintf(stderr, __VA_ARGS__); \
39                         else \
40                                 fprintf(stdout, __VA_ARGS__); \
41                 } \
42         } while (0)
43
44 /* print an error message */
45 #define mu_printerr(name, action) \
46                 mu_print(MU_ERROR, __FILE__ ":%d: " name " failed, "\
47                                 action " test case\n", __LINE__);
48
49 /* modify the internal state so a failure gets counted */
50 #define mutest_count_err ++mutest_failed_checks; mutest_case_failed = 1;
51
52 /* modify the internal state so a success gets counted */
53 #define mutest_count_suc ++mutest_passed_checks;
54
55 #ifdef __cplusplus
56
57 #include <exception>
58
59 /* print an error message triggered by a C++ exception */
60 #define mu_printex(name, action, ex) \
61                 mu_print(MU_ERROR, __FILE__ ":%d: " name " failed, " \
62                                 "exception thrown (%s), " action \
63                                 " test case\n", __LINE__, ex);
64
65 #define mutest_try try {
66 #define mutest_catch(name, action, final) \
67                 } catch (const std::exception& e) { \
68                         mutest_count_err \
69                         mu_printex(name, action, e.what()); \
70                         final; \
71                 } catch (...) { \
72                         mutest_count_err \
73                         mu_printex(name, action, "[unknown]"); \
74                         final; \
75                 }
76
77 #else /* !__cplusplus */
78
79 #define mutest_try
80 #define mutest_catch(name, action, exp)
81
82 #endif /* __cplusplus */
83
84 /* check that an expression evaluates to true, continue if the check fails */
85 #define mu_check_base(exp, name, action, final) \
86         do { \
87                 mu_print(MU_CHECK, "\t\t* Checking " name "(" #exp ")...\n"); \
88                 mutest_try \
89                         if (exp) mutest_count_suc \
90                         else { \
91                                 mutest_count_err \
92                                 mu_printerr(name "(" #exp ")", action); \
93                                 final; \
94                         } \
95                 mutest_catch(name, action, final) \
96         } while (0)
97
98 /* check that an expression evaluates to true, continue if the check fails */
99 #define mu_check(exp) mu_check_base(exp, "mu_check", "resuming", continue)
100
101 /*
102  * ensure that an expression evaluates to true, abort the current test
103  * case if the check fails
104  */
105 #define mu_ensure(exp) mu_check_base(exp, "mu_ensure", "aborting", return)
106
107 #ifdef __cplusplus
108
109 #define mu_echeck_base(ex, exp, name, action, final) \
110         do { \
111                 mu_print(MU_CHECK, "\t\t* Checking " name "(" #ex ", " #exp \
112                                 ")...\n"); \
113                 try { \
114                         exp; \
115                         mutest_count_err \
116                         mu_printerr(name "(" #ex ", " #exp ")", \
117                                         "no exception thrown, " action); \
118                         final; \
119                 } catch (const ex& e) { \
120                         mutest_count_suc \
121                 } catch (const std::exception& e) { \
122                         mutest_count_err \
123                         mu_printex(name "(" #ex ", " #exp ")", action, \
124                                         e.what()); \
125                         final; \
126                 } catch (...) { \
127                         mutest_count_err \
128                         mu_printex(name "(" #ex ", " #exp ")", action, \
129                                         "[unknown]"); \
130                         final; \
131                 } \
132         } while (0)
133
134 /*
135  * check that an expression throws a particular exception, continue if the
136  * check fails
137  */
138 #define mu_echeck(ex, exp) \
139         mu_echeck_base(ex, exp, "mu_echeck", "resuming", continue)
140
141 /*
142  * ensure that an expression throws a particular exception, abort the current
143  * test case if the check fails
144  */
145 #define mu_eensure(ex, exp) \
146         mu_echeck_base(ex, exp, "mu_eensure", "aborting", return)
147
148 #endif /* __cplusplus */
149
150 #ifndef MUTEST_PY /* we are using the C implementation */
151
152 /*
153  * this function implements the test suites execution, you should generate
154  * a module with this function using mkmutest, or take a look to that script
155  * if you want to implement your own customized version */
156 void mu_run_suites();
157
158 /* macro for running a single initialization function */
159 #ifndef mu_run_init
160 #define mu_run_init(name) \
161         { \
162                 int name(); \
163                 int r; \
164                 mu_print(MU_CASE, "\t+ Executing initialization function " \
165                                 "'" #name "'...\n"); \
166                 if ((r = name())) { \
167                         mu_print(MU_ERROR, "%s:" #name ": initialization " \
168                                         "function failed (returned %d), " \
169                                         "skipping test suite...\n", \
170                                         mutest_suite_name, r); \
171                         ++mutest_skipped_suites; \
172                         break; \
173                 } \
174         } do { } while (0)
175 #endif /* mu_run_init */
176
177 /* macro for running a single test case */
178 #ifndef mu_run_case
179 #define mu_run_case(name) \
180         do { \
181                 mu_print(MU_CASE, "\t* Executing test case '" #name "'...\n");\
182                 mutest_case_name = #name; \
183                 void name(); \
184                 name(); \
185                 if (mutest_case_failed) { \
186                         ++mutest_failed_cases; \
187                         mutest_suite_failed = 1; \
188                 } else ++mutest_passed_cases; \
189                 mutest_case_failed = 0; \
190         } while (0)
191 #endif /* mu_run_case */
192
193 /* macro for running a single termination function */
194 #ifndef mu_run_term
195 #define mu_run_term(name) \
196         do { \
197                 mu_print(MU_CASE, "\t- Executing termination function '" \
198                                 #name "'...\n"); \
199                 void name(); \
200                 name(); \
201         } while (0)
202 #endif /* mu_run_term */
203
204 /*
205  * mutest exported variables for internal use, do not use directly unless you
206  *  know what you're doing.
207  */
208 extern const char* mutest_suite_name;
209 extern int mutest_failed_suites;
210 extern int mutest_passed_suites;
211 extern int mutest_skipped_suites;
212 extern int mutest_suite_failed;
213 /* test cases */
214 extern const char* mutest_case_name;
215 extern int mutest_failed_cases;
216 extern int mutest_passed_cases;
217 extern int mutest_case_failed;
218 /* checks */
219 extern int mutest_failed_checks;
220 extern int mutest_passed_checks;
221 /* verbosity */
222 extern int mutest_verbose_level;
223
224 #else /* MUTEST_PY is defined, using the Python implementation */
225
226 /* this increments when the "API" changes, it's just for sanity check */
227 int mutest_api_version = 1;
228
229 int mutest_case_failed; /* unused, for C implementation compatibility */
230
231 int mutest_passed_checks;
232 int mutest_failed_checks;
233 void mutest_reset_counters() {
234         mutest_passed_checks = 0;
235         mutest_failed_checks = 0;
236 }
237
238 int mutest_verbose_level = MU_ERROR;
239 void mutest_set_verbose_level(int val) {
240         mutest_verbose_level = val;
241 }
242
243 #endif /* MUTEST_PY */
244
245 #ifdef __cplusplus
246 }
247 #endif
248