2 * Copyright (c) 2014 Vojtech Horky
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
30 * Tests and test suites.
32 * @defgroup tests Tests
33 * Create test suites and test cases.
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:
51 #define PCUT_WITHOUT_COUNTER
54 #ifndef PCUT_WITHOUT_COUNTER
55 #define PCUT_ITEM_COUNTER_INCREMENT
59 /** Default timeout for a single test (in seconds).
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
72 #define PCUT_ITEM_COUNTER __COUNTER__
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)
97 #define PCUT_ITEM_NAME(number) PCUT_ITEM_NAME
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))
108 #define PCUT_ITEM_NAME_PREV(number) PCUT_ITEM_NAME_PREV
111 #ifndef PCUT_WITHOUT_COUNTER
112 #define PCUT_ITEM_EXTRAS_NAME(number) \
113 PCUT_JOIN(pcut_extras_, number)
115 #define PCUT_ITEM_EXTRAS_NAME(number) PCUT_ITEM2_NAME
118 #ifndef PCUT_WITHOUT_COUNTER
119 #define PCUT_ITEM_SETUP_NAME(number) \
120 PCUT_JOIN(pcut_setup_, number)
122 #define PCUT_ITEM_SETUP_NAME(number) PCUT_ITEM3_NAME
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), \
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 }
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)[] = { \
184 static void PCUT_JOIN(test_, testname)(void); \
185 PCUT_ADD_ITEM(number, PCUT_KIND_TEST, \
188 .func = PCUT_JOIN(test_, testname), \
189 .extras = PCUT_ITEM_EXTRAS_NAME(number), \
192 void PCUT_JOIN(test_, testname)(void)
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 * -------------------------
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, \
226 .name = #suitename, \
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)
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.
280 * PCUT_TEST_SUITE(my_suite);
283 * printf("This is executed before each test in this suite.\n");
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.
297 * PCUT_TEST_SUITE(my_suite);
300 * printf("This is executed after each test in this suite.\n");
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 * ----------------------------
320 /** Export test cases from current file.
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), \
332 .kind = PCUT_KIND_SKIP \
335 /** Import test cases from a different file.
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 \
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 * -----------------------------------------
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) = { \
387 .kind = PCUT_KIND_SKIP \
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 \
403 int main(int argc, char *argv[]) { \
404 return pcut_main(&pcut_item_last, argc, argv); \
409 /** Initialize the PCUT testing framework. */
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)