Update PCUT to newest version
[helenos.git] / uspace / lib / pcut / include / pcut / tests.h
blobc3c2d93a540db28d022b8110bd3c44a953bbc5be
1 /*
2 * Copyright (c) 2014 Vojtech Horky
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 /** @file
30 * Tests and test suites.
32 * @defgroup tests Tests
33 * Create test suites and test cases.
34 * @{
36 #ifndef PCUT_TESTS_H_GUARD
37 #define PCUT_TESTS_H_GUARD
39 #include <pcut/datadef.h>
42 * Trick with [] and & copied from
43 * http://bytes.com/topic/c/answers/553555-initializer-element-not-constant#post2159846
44 * because following does not work:
45 * extern int *a;
46 * int *b = a;
50 #ifndef __COUNTER__
51 #define PCUT_WITHOUT_COUNTER
52 #endif
54 #ifndef PCUT_WITHOUT_COUNTER
55 #define PCUT_ITEM_COUNTER_INCREMENT
56 #endif
59 /** Default timeout for a single test (in seconds).
60 * @showinitializer
62 #define PCUT_DEFAULT_TEST_TIMEOUT 3
64 /** Item counter that is expected to be incremented by preprocessor.
66 * Used compiler must support __COUNTER__ for this to work without any
67 * extra preprocessing.
69 #ifdef PCUT_WITHOUT_COUNTER
70 #define PCUT_ITEM_COUNTER PCUT_you_need_to_run_pcut_preprocessor
71 #else
72 #define PCUT_ITEM_COUNTER __COUNTER__
73 #endif
77 * Helper macros
78 * -------------
81 /** @cond devel */
83 /** Join the two arguments on preprocessor level (inner call). */
84 #define PCUT_JOIN_IMPL(a, b) a##b
86 /** Join the two arguments on preprocessor level. */
87 #define PCUT_JOIN(a, b) PCUT_JOIN_IMPL(a, b)
89 /** Produce identifier name for an item with given number.
91 * @param number Item number.
93 #ifndef PCUT_WITHOUT_COUNTER
94 #define PCUT_ITEM_NAME(number) \
95 PCUT_JOIN(pcut_item_, number)
96 #else
97 #define PCUT_ITEM_NAME(number) PCUT_ITEM_NAME
98 #endif
100 /** Produce identifier name for a preceding item.
102 * @param number Number of the current item.
104 #ifndef PCUT_WITHOUT_COUNTER
105 #define PCUT_ITEM_NAME_PREV(number) \
106 PCUT_JOIN(pcut_item_, PCUT_JOIN(PCUT_PREV_, number))
107 #else
108 #define PCUT_ITEM_NAME_PREV(number) PCUT_ITEM_NAME_PREV
109 #endif
111 #ifndef PCUT_WITHOUT_COUNTER
112 #define PCUT_ITEM_EXTRAS_NAME(number) \
113 PCUT_JOIN(pcut_extras_, number)
114 #else
115 #define PCUT_ITEM_EXTRAS_NAME(number) PCUT_ITEM2_NAME
116 #endif
118 #ifndef PCUT_WITHOUT_COUNTER
119 #define PCUT_ITEM_SETUP_NAME(number) \
120 PCUT_JOIN(pcut_setup_, number)
121 #else
122 #define PCUT_ITEM_SETUP_NAME(number) PCUT_ITEM3_NAME
123 #endif
127 /** Create a new item, append it to the list.
129 * @param number Number of this item.
130 * @param itemkind Kind of this item (PCUT_KIND_*).
131 * @param ... Other initializers of the pcut_item_t.
133 #define PCUT_ADD_ITEM(number, itemkind, ...) \
134 static pcut_item_t PCUT_ITEM_NAME(number) = { \
135 .previous = &PCUT_ITEM_NAME_PREV(number), \
136 .next = NULL, \
137 .id = -1, \
138 .kind = itemkind, \
139 __VA_ARGS__ \
142 /** @endcond */
147 * Test-case related macros
148 * ------------------------
151 /** Define test time-out.
153 * Use as argument to PCUT_TEST().
155 * @param time_out Time-out value in seconds.
157 #define PCUT_TEST_SET_TIMEOUT(time_out) \
158 { .type = PCUT_EXTRA_TIMEOUT, .timeout = (time_out) }
160 /** Skip current test.
162 * Use as argument to PCUT_TEST().
164 #define PCUT_TEST_SKIP \
165 { .type = PCUT_EXTRA_SKIP }
168 /** @cond devel */
170 /** Terminate list of extra test options. */
171 #define PCUT_TEST_EXTRA_LAST { .type = PCUT_EXTRA_LAST }
173 /** Define a new test with given name and given item number.
175 * @param testname A valid C identifier name (not quoted).
176 * @param number Number of the item describing this test.
177 * @param ... Extra test properties.
179 #define PCUT_TEST_WITH_NUMBER(testname, number, ...) \
180 PCUT_ITEM_COUNTER_INCREMENT \
181 static pcut_extra_t PCUT_ITEM_EXTRAS_NAME(number)[] = { \
182 __VA_ARGS__ \
183 }; \
184 static void PCUT_JOIN(test_, testname)(void); \
185 PCUT_ADD_ITEM(number, PCUT_KIND_TEST, \
186 .test = { \
187 .name = #testname, \
188 .func = PCUT_JOIN(test_, testname), \
189 .extras = PCUT_ITEM_EXTRAS_NAME(number), \
192 void PCUT_JOIN(test_, testname)(void)
194 /** @endcond */
196 /** Define a new test with given name.
198 * @param name A valid C identifier name (not quoted).
199 * @param ... Extra test properties.
201 #define PCUT_TEST(name, ...) \
202 PCUT_TEST_WITH_NUMBER(name, PCUT_ITEM_COUNTER, ##__VA_ARGS__, PCUT_TEST_EXTRA_LAST)
209 * Test suite related macros
210 * -------------------------
213 /** @cond devel */
215 /** Define and start a new test suite.
217 * @see PCUT_TEST_SUITE
219 * @param suitename Suite name (a valid C identifier).
220 * @param number Item number.
222 #define PCUT_TEST_SUITE_WITH_NUMBER(suitename, number) \
223 PCUT_ITEM_COUNTER_INCREMENT \
224 PCUT_ADD_ITEM(number, PCUT_KIND_TESTSUITE, \
225 .suite = { \
226 .name = #suitename, \
227 .setup = NULL, \
228 .teardown = NULL \
232 /** Define a set-up function for a test suite.
234 * @see PCUT_TEST_BEFORE
236 * @param number Item number.
238 #define PCUT_TEST_BEFORE_WITH_NUMBER(number) \
239 PCUT_ITEM_COUNTER_INCREMENT \
240 static void PCUT_ITEM_SETUP_NAME(number)(void); \
241 PCUT_ADD_ITEM(number, PCUT_KIND_SETUP, \
242 .setup.func = PCUT_ITEM_SETUP_NAME(number) \
244 void PCUT_ITEM_SETUP_NAME(number)(void)
246 /** Define a tear-down function for a test suite.
248 * @see PCUT_TEST_AFTER
250 * @param number Item number.
252 #define PCUT_TEST_AFTER_WITH_NUMBER(number) \
253 PCUT_ITEM_COUNTER_INCREMENT \
254 static void PCUT_ITEM_SETUP_NAME(number)(void); \
255 PCUT_ADD_ITEM(number, PCUT_KIND_TEARDOWN, \
256 .setup.func = PCUT_ITEM_SETUP_NAME(number) \
258 void PCUT_ITEM_SETUP_NAME(number)(void)
260 /** @endcond */
263 /** Define and start a new test suite.
265 * All tests following this macro belong to the new suite
266 * (up to next occurrence of PCUT_TEST_SUITE).
268 * This command shall be used as is without any extra code.
270 * @param name Suite name (a valid C identifier).
272 #define PCUT_TEST_SUITE(name) \
273 PCUT_TEST_SUITE_WITH_NUMBER(name, PCUT_ITEM_COUNTER)
275 /** Define a set-up function for a test suite.
277 * The code of the function immediately follows this macro.
279 * @code
280 * PCUT_TEST_SUITE(my_suite);
282 * PCUT_TEST_BEFORE {
283 * printf("This is executed before each test in this suite.\n");
285 * @endcode
287 * There could be only a single set-up function for each suite.
289 #define PCUT_TEST_BEFORE \
290 PCUT_TEST_BEFORE_WITH_NUMBER(PCUT_ITEM_COUNTER)
292 /** Define a tear-down function for a test suite.
294 * The code of the function immediately follows this macro.
296 * @code
297 * PCUT_TEST_SUITE(my_suite);
299 * PCUT_TEST_AFTER {
300 * printf("This is executed after each test in this suite.\n");
302 * @endcode
304 * There could be only a single tear-down function for each suite.
306 #define PCUT_TEST_AFTER \
307 PCUT_TEST_AFTER_WITH_NUMBER(PCUT_ITEM_COUNTER)
314 * Import/export related macros
315 * ----------------------------
318 /** @cond devel */
320 /** Export test cases from current file.
322 * @see PCUT_EXPORT
324 * @param identifier Identifier of this block of tests.
325 * @param number Item number.
327 #define PCUT_EXPORT_WITH_NUMBER(identifier, number) \
328 PCUT_ITEM_COUNTER_INCREMENT \
329 pcut_item_t pcut_exported_##identifier = { \
330 .previous = &PCUT_ITEM_NAME_PREV(number), \
331 .next = NULL, \
332 .kind = PCUT_KIND_SKIP \
335 /** Import test cases from a different file.
337 * @see PCUT_EXPORT
339 * @param identifier Identifier of the tests to import.
340 * @param number Item number.
342 #define PCUT_IMPORT_WITH_NUMBER(identifier, number) \
343 PCUT_ITEM_COUNTER_INCREMENT \
344 extern pcut_item_t pcut_exported_##identifier; \
345 PCUT_ADD_ITEM(number, PCUT_KIND_NESTED, \
346 .nested.last = &pcut_exported_##identifier \
349 /** @endcond */
351 /** Export test cases from current file.
353 * @param identifier Identifier of this block of tests.
355 #define PCUT_EXPORT(identifier) \
356 PCUT_EXPORT_WITH_NUMBER(identifier, PCUT_ITEM_COUNTER)
358 /** Import test cases from a different file.
360 * @param identifier Identifier of the tests to import.
361 * (previously exported with PCUT_EXPORT).
363 #define PCUT_IMPORT(identifier) \
364 PCUT_IMPORT_WITH_NUMBER(identifier, PCUT_ITEM_COUNTER)
371 * PCUT initialization and invocation macros
372 * -----------------------------------------
375 /** @cond devel */
377 /** Initialize the PCUT testing framework with a first item.
379 * @param first_number Number of the first item.
381 #define PCUT_INIT_WITH_NUMBER(first_number) \
382 PCUT_ITEM_COUNTER_INCREMENT \
383 static pcut_item_t PCUT_ITEM_NAME(first_number) = { \
384 .previous = NULL, \
385 .next = NULL, \
386 .id = -1, \
387 .kind = PCUT_KIND_SKIP \
388 }; \
389 PCUT_TEST_SUITE(Default);
391 int pcut_main(pcut_item_t *last, int argc, char *argv[]);
393 /** Insert code to run all the tests.
395 * @param number Item number.
397 #define PCUT_MAIN_WITH_NUMBER(number) \
398 PCUT_ITEM_COUNTER_INCREMENT \
399 static pcut_item_t pcut_item_last = { \
400 .previous = &PCUT_ITEM_NAME_PREV(number), \
401 .kind = PCUT_KIND_SKIP \
402 }; \
403 int main(int argc, char *argv[]) { \
404 return pcut_main(&pcut_item_last, argc, argv); \
407 /** @endcond */
409 /** Initialize the PCUT testing framework. */
410 #define PCUT_INIT \
411 PCUT_INIT_WITH_NUMBER(PCUT_ITEM_COUNTER)
413 /** Insert code to run all the tests. */
414 #define PCUT_MAIN() \
415 PCUT_MAIN_WITH_NUMBER(PCUT_ITEM_COUNTER)
419 * @}
422 #endif