Pico Headers
Loading...
Searching...
No Matches
pico_unit.h
Go to the documentation of this file.
1
63#ifndef PICO_UNIT_H
64#define PICO_UNIT_H
65
66#include <stdbool.h> /* bool, true, false */
67#include <stddef.h> /* NULL */
68#include <string.h> /* strcmp */
69
70#ifdef __cplusplus
71extern "C" {
72#endif
73
79#define TEST_CASE(name) static bool name(void)
80
90#define REQUIRE(expr) \
91 do { \
92 if (!pu_require((expr) ? true : false, (#expr), __FILE__, __LINE__, \
93 NULL)) \
94 return false; \
95 } while(false)
96
105#define RUN_TEST_CASE(test_fp) (pu_run_test(#test_fp, test_fp))
106
112#define TEST_SUITE(name) void name(void)
113
120#define RUN_TEST_SUITE(suite_fp) pu_run_suite(#suite_fp, suite_fp)
121
125typedef void (*pu_setup_fn)(void);
126
138void pu_setup(pu_setup_fn setup_fp, pu_setup_fn teardown_fp);
139
143void pu_clear_setup(void);
144
148void pu_display_colors(bool enabled);
149
153void pu_display_time(bool enabled);
154
158void pu_display_quiet(bool enabled);
159
163bool pu_is_quiet(void);
164
168void pu_print_stats(void);
169
175bool pu_test_failed(void);
176
177/*
178 * WARNING: These functions are not meant to be called directly. Use the macros
179 * instead.
180 */
181typedef bool (*pu_test_fn)(void);
182typedef void (*pu_suite_fn)(void);
183
187bool pu_require(bool passed,
188 const char* const expr,
189 const char* const file,
190 int line,
191 const char* const fmt, ...);
192
196void pu_run_test(const char* const name, pu_test_fn test_fp);
197
201void pu_run_suite(const char* const name, pu_suite_fn suite_fp);
202
203#ifdef __cplusplus
204}
205#endif
206
207#endif // PICO_UNIT_H
208
209#ifdef PICO_UNIT_IMPLEMENTATION
210
211#include <stdarg.h> /* va_list, va_start, va_end */
212#include <stdio.h> /* printf, fprintf, vfprintf */
213
214#ifndef PICO_UNIT_NO_CLOCK
215#include <time.h> /* clock_t, clock */
216#endif // PICO_UNIT_NO_CLOCK
217
218#define TERM_COLOR_CODE 0x1B
219#define TERM_COLOR_RED "[1;31m"
220#define TERM_COLOR_GREEN "[1;32m"
221#define TERM_COLOR_BOLD "[1m"
222#define TERM_COLOR_RESET "[0m"
223
224static unsigned pu_num_asserts = 0;
225static unsigned pu_num_passed = 0;
226static unsigned pu_num_failed = 0;
227static unsigned pu_num_suites = 0;
228static bool pu_colors = false;
229static bool pu_time = false;
230static bool pu_quiet = false;
231
232static pu_setup_fn pu_setup_fp = NULL;
233static pu_setup_fn pu_teardown_fp = NULL;
234
235#define pu_quiet_printf(...) \
236 do { \
237 if (!pu_quiet) \
238 { \
239 printf(__VA_ARGS__); \
240 } \
241 } while(0)
242
243void
244pu_setup (pu_setup_fn fp_setup, pu_setup_fn fp_teardown)
245{
246 pu_setup_fp = fp_setup;
247 pu_teardown_fp = fp_teardown;
248}
249
250void
251pu_clear_setup (void)
252{
253 pu_setup_fp = NULL;
254 pu_teardown_fp = NULL;
255}
256
257void
258pu_display_colors (bool enabled)
259{
260 pu_colors = enabled;
261}
262
263void
264pu_display_time (bool enabled)
265{
266 pu_time = enabled;
267}
268
269void
270pu_display_quiet (bool enabled)
271{
272 pu_quiet = enabled;
273}
274
275bool
276pu_is_quiet (void)
277{
278 return pu_quiet;
279}
280
281bool
282pu_test_failed(void)
283{
284 return (pu_num_failed != 0);
285}
286
287bool
288pu_require(bool passed,
289 const char* const expr,
290 const char* const file,
291 int line,
292 const char* const fmt, ...)
293{
294 pu_num_asserts++;
295
296 if (passed)
297 {
298 return true;
299 }
300
301 if (pu_colors)
302 {
303 fprintf(stderr, "(%c%sFAILED%c%s: %s (%d): %s)\n",
304 TERM_COLOR_CODE, TERM_COLOR_RED,
305 TERM_COLOR_CODE, TERM_COLOR_RESET,
306 file, line, expr);
307 }
308 else
309 {
310 fprintf(stderr, "(FAILED: %s (%d): %s)\n", file, line, expr);
311 }
312
313 if (fmt)
314 {
315 va_list args;
316 va_start(args, fmt);
317 fprintf(stderr, " note: ");
318 vfprintf(stderr, fmt, args);
319 fprintf(stderr, "\n");
320 va_end(args);
321 }
322
323 return false;
324}
325
326void
327pu_run_test (const char* const name, pu_test_fn test_fp)
328{
329 if (NULL != pu_setup_fp)
330 {
331 pu_setup_fp();
332 }
333
334 pu_quiet_printf("Running: %s ", name);
335
336 #ifndef PICO_UNIT_NO_CLOCK
337
338 clock_t start_time = 0;
339 clock_t end_time = 0;
340
341 if (pu_time)
342 {
343 start_time = clock();
344 }
345
346 #endif // PICO_UNIT_NO_CLOCK
347
348 if (!test_fp())
349 {
350 pu_num_failed++;
351
352 pu_quiet_printf("\n");
353
354 if (NULL != pu_teardown_fp)
355 {
356 pu_teardown_fp();
357 }
358
359 return;
360 }
361
362 #ifndef PICO_UNIT_NO_CLOCK
363
364 if (pu_time)
365 {
366 end_time = clock();
367 }
368
369 #endif // PICO_UNIT_NO_CLOCK
370
371 if (pu_colors)
372 {
373 pu_quiet_printf("(%c%sOK%c%s)", TERM_COLOR_CODE, TERM_COLOR_GREEN,
374 TERM_COLOR_CODE, TERM_COLOR_RESET);
375 }
376 else
377 {
378 pu_quiet_printf("(OK)");
379 }
380
381 #ifndef PICO_UNIT_NO_CLOCK
382
383 if (pu_time)
384 {
385 pu_quiet_printf(" (%f secs)", (double)(end_time - start_time) / CLOCKS_PER_SEC);
386 }
387
388 #endif // PICO_UNIT_NO_CLOCK
389
390 pu_quiet_printf("\n");
391
392 pu_num_passed++;
393
394 if (NULL != pu_teardown_fp)
395 {
396 pu_teardown_fp();
397 }
398}
399
400void
401pu_run_suite (const char* const name, pu_suite_fn suite_fp)
402{
403 pu_quiet_printf("===============================================================\n");
404
405 if (pu_colors)
406 {
407 pu_quiet_printf("%c%sRunning: %s%c%s\n", TERM_COLOR_CODE, TERM_COLOR_BOLD,
408 name,
409 TERM_COLOR_CODE, TERM_COLOR_RESET);
410 }
411 else
412 {
413 pu_quiet_printf("Running: %s\n", name);
414 }
415
416 pu_quiet_printf("---------------------------------------------------------------\n");
417
418 suite_fp();
419 pu_num_suites++;
420}
421
422void
423pu_print_stats (void)
424{
425 pu_quiet_printf("===============================================================\n");
426
427 if (pu_colors)
428 {
429 pu_quiet_printf("Summary: Passed: %c%s%u%c%s "
430 "Failed: %c%s%u%c%s "
431 "Total: %u Suites: %u "
432 "Asserts: %u\n",
433 TERM_COLOR_CODE, TERM_COLOR_GREEN, pu_num_passed,
434 TERM_COLOR_CODE, TERM_COLOR_RESET,
435 TERM_COLOR_CODE, TERM_COLOR_RED, pu_num_failed,
436 TERM_COLOR_CODE, TERM_COLOR_RESET,
437 pu_num_passed + pu_num_failed,
438 pu_num_suites, pu_num_asserts);
439 }
440 else
441 {
442 pu_quiet_printf("Summary: Passed: %u "
443 "Failed: %u "
444 "Total: %u Suites: %u "
445 "Asserts: %u\n",
446 pu_num_passed,
447 pu_num_failed,
448 pu_num_passed + pu_num_failed,
449 pu_num_suites, pu_num_asserts);
450 }
451}
452
453
454#endif // PICO_UNIT_IMPLEMENTATION
455
456/*
457 ----------------------------------------------------------------------------
458 This software is available under two licenses (A) or (B). You may choose
459 either one as you wish:
460 ----------------------------------------------------------------------------
461
462 (A) The zlib License
463
464 Copyright (c) 2021 James McLean
465
466 This software is provided 'as-is', without any express or implied warranty.
467 In no event will the authors be held liable for any damages arising from the
468 use of this software.
469
470 Permission is granted to anyone to use this software for any purpose,
471 including commercial applications, and to alter it and redistribute it
472 freely, subject to the following restrictions:
473
474 1. The origin of this software must not be misrepresented; you must not
475 claim that you wrote the original software. If you use this software in a
476 product, an acknowledgment in the product documentation would be appreciated
477 but is not required.
478
479 2. Altered source versions must be plainly marked as such, and must not be
480 misrepresented as being the original software.
481
482 3. This notice may not be removed or altered from any source distribution.
483
484 ----------------------------------------------------------------------------
485
486 (B) Public Domain (www.unlicense.org)
487
488 This is free and unencumbered software released into the public domain.
489
490 Anyone is free to copy, modify, publish, use, compile, sell, or distribute
491 this software, either in source code form or as a compiled binary, for any
492 purpose, commercial or non-commercial, and by any means.
493
494 In jurisdictions that recognize copyright laws, the author or authors of
495 this software dedicate any and all copyright interest in the software to the
496 public domain. We make this dedication for the benefit of the public at
497 large and to the detriment of our heirs and successors. We intend this
498 dedication to be an overt act of relinquishment in perpetuity of all present
499 and future rights to this software under copyright law.
500
501 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
502 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
503 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
504 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
505 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
506 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
507*/
508
509// EoF
bool pu_is_quiet(void)
Returns whether quiet mode is enabled.
void pu_clear_setup(void)
Disables the setup and teardown functions by setting them to NULL.
bool pu_require(bool passed, const char *const expr, const char *const file, int line, const char *const fmt,...)
Used internally.
bool(* pu_test_fn)(void)
Definition pico_unit.h:181
void(* pu_suite_fn)(void)
Definition pico_unit.h:182
void pu_run_test(const char *const name, pu_test_fn test_fp)
Used internally.
void pu_run_suite(const char *const name, pu_suite_fn suite_fp)
Used internally.
void pu_print_stats(void)
Prints test statistics.
void pu_display_colors(bool enabled)
Turns on terminal colors. NOTE: Off by default.
void(* pu_setup_fn)(void)
Functions that are run before or after a number of unit tests execute.
Definition pico_unit.h:125
void pu_display_time(bool enabled)
Turns on time measurement. NOTE: Off by default.
bool pu_test_failed(void)
Check whether at least one test failed.
void pu_display_quiet(bool enabled)
Turns on quiet mode. Only failures are printed.
void pu_setup(pu_setup_fn setup_fp, pu_setup_fn teardown_fp)
Sets the current setup and teardown functions.