diff options
| author | Jonathan Bradley <jcb@pikum.xyz> | 2025-10-16 12:17:13 -0400 |
|---|---|---|
| committer | Jonathan Bradley <jcb@pikum.xyz> | 2025-10-16 13:45:30 -0400 |
| commit | 77c8686edd087a605b69e71c51c9adfe5bd26720 (patch) | |
| tree | c079c39daf8f68f3dfb7caf3089a2d48ba81935e | |
| parent | 22062b43dbfeb78bdabf8f2693fcf880349d9cde (diff) | |
pke: update pk.h to 0.9.4
| -rw-r--r-- | src/pk.h | 217 | ||||
| -rw-r--r-- | tests/pke-test-types.h | 6 |
2 files changed, 215 insertions, 8 deletions
@@ -1,7 +1,7 @@ #ifndef PK_SINGLE_HEADER_FILE_H #define PK_SINGLE_HEADER_FILE_H /******************************************************************************* -* PK Single-Header-Library V0.9.3 +* PK Single-Header-Library V0.9.4 * * Author: Jonathan Bradley * Copyright: © 2024-2025 Jonathan Bradley @@ -289,9 +289,21 @@ * } * ``` * +******************************************************************************** +* pktst.h: define PK_IMPL_TST before including pk.h to enable ad-hoc. +* +* Provides a simple testing framework +* +* Examples: +* ```c +* main() { +* pk_test_run_test_groups(&my_get_test_group_func, 1); +* } +* ``` +* *******************************************************************************/ -#define PK_VERSION "0.9.3" +#define PK_VERSION "0.9.4" #ifdef PK_IMPL_ALL # ifndef PK_IMPL_MEM_TYPES @@ -321,6 +333,9 @@ # ifndef PK_IMPL_FUNCINSTR # define PK_IMPL_FUNCINSTR # endif +# ifndef PK_IMPL_TST +# define PK_IMPL_TST +# endif #endif #ifndef PK_MACROS_H #define PK_MACROS_H @@ -339,6 +354,40 @@ # endif #endif +#define PK_CLR_RESET "\033[0m" +#define PK_CLR_FG_BLACK "\033[30m" +#define PK_CLR_FG_RED "\033[31m" +#define PK_CLR_FG_GREEN "\033[32m" +#define PK_CLR_FG_YELLOW "\033[33m" +#define PK_CLR_FG_BLUE "\033[34m" +#define PK_CLR_FG_MAGENTA "\033[35m" +#define PK_CLR_FG_CYAN "\033[36m" +#define PK_CLR_FG_WHITE "\033[37m" +#define PK_CLR_BG_BLACK "\033[40m" +#define PK_CLR_BG_RED "\033[41m" +#define PK_CLR_BG_GREEN "\033[42m" +#define PK_CLR_BG_YELLOW "\033[43m" +#define PK_CLR_BG_BLUE "\033[44m" +#define PK_CLR_BG_MAGENTA "\033[45m" +#define PK_CLR_BG_CYAN "\033[46m" +#define PK_CLR_BG_WHITE "\033[47m" +#define PK_CLR_FG_BRIGHT_BLACK "\033[90m" +#define PK_CLR_FG_BRIGHT_RED "\033[91m" +#define PK_CLR_FG_BRIGHT_GREEN "\033[92m" +#define PK_CLR_FG_BRIGHT_YELLOW "\033[93m" +#define PK_CLR_FG_BRIGHT_BLUE "\033[94m" +#define PK_CLR_FG_BRIGHT_MAGENTA "\033[95m" +#define PK_CLR_FG_BRIGHT_CYAN "\033[96m" +#define PK_CLR_FG_BRIGHT_WHITE "\033[97m" +#define PK_CLR_BG_BRIGHT_BLACK "\033[100m" +#define PK_CLR_BG_BRIGHT_RED "\033[101m" +#define PK_CLR_BG_BRIGHT_GREEN "\033[102m" +#define PK_CLR_BG_BRIGHT_YELLOW "\033[103m" +#define PK_CLR_BG_BRIGHT_BLUE "\033[104m" +#define PK_CLR_BG_BRIGHT_MAGENTA "\033[105m" +#define PK_CLR_BG_BRIGHT_CYAN "\033[106m" +#define PK_CLR_BG_BRIGHT_WHITE "\033[107m" + #define PK_Q(x) #x #define PK_QUOTE(x) PK_Q(x) #define PK_CONCAT2(x, y) x##y @@ -3495,4 +3544,168 @@ void __cyg_profile_func_exit(void* this_fn, void* call_site) { #endif #endif /* PK_IMPL_FUNCINSTR */ +#ifndef PK_PKTST_H +#define PK_PKTST_H + + +typedef int (pk_test_func)(); +struct pk_test_group; +typedef struct pk_test_group *(pk_test_group_get)(); + +typedef void (pk_test_group_setup)(); +typedef void (pk_test_group_teardown)(); +typedef void (pk_test_setup)(); +typedef void (pk_test_teardown)(); + +struct pk_test { + const char *title; + pk_test_func *func; + int expected_result; +}; + +struct pk_test_group { + const char *title; + pk_test_group_setup *group_setup; + pk_test_group_teardown *group_teardown; + pk_test_setup *test_setup; + pk_test_teardown *test_teardown; + struct pk_test *tests; + unsigned char n_tests; +}; + +void pk_test_run_test_groups(pk_test_group_get **group_get_fns, unsigned long n_groups); + +#if defined(__cplusplus) +#include <iostream> +#define PK_TEST_ASSERT_BODY(expected, value) \ + std::cerr << "[pk-test] "; \ + std::cerr << "(" << __FILE__ << ":" << __LINE__ << ")"; \ + std::cerr << PK_CLR_FG_RED " Failed. " PK_CLR_RESET; \ + std::cerr << "Condition: \""; \ + std::cerr << PK_CLR_FG_BRIGHT_BLUE << #value << PK_CLR_RESET; \ + std::cerr << "\", Expected: \""; \ + std::cerr << PK_CLR_FG_GREEN << (expected) << PK_CLR_RESET; \ + std::cerr << "\", Got: \""; \ + std::cerr << PK_CLR_FG_RED << (value) << PK_CLR_RESET; \ + std::cerr << "\"." << std::endl; +template<typename T> +inline bool flt_equal(T a, T b, T epsilon) { + return abs(a - b) < epsilon; +} +#else /* __cplusplus */ +#include <stdio.h> +#define PK_TEST_ASSERT_BODY(expected, value) \ + fprintf(stderr,"[pk-test] (%s:%i) ", __FILE__, __LINE__); \ + fprintf(stderr,"%s ", PK_CLR_FG_RED "Failed. " PK_CLR_RESET); \ + fprintf(stderr,"Test condition \""); \ + fprintf(stderr,"%s\"\n",PK_CLR_FG_BRIGHT_BLUE #value PK_CLR_RESET); +#endif /* __cplusplus */ + +#define PK_TEST_ASSERT_EQ(expected, value) { \ + if ((value) != (expected)) { \ + PK_TEST_ASSERT_BODY(expected, value) \ + } \ +} +#define PK_TEST_ASSERT_EQ_RET(expected, value) { \ + if ((value) != (expected)) { \ + PK_TEST_ASSERT_BODY(expected, value) \ + return -1; \ + } \ +} +#define PK_TEST_ASSERT_EQ_EXIT(expected, value) { \ + if ((value) != (expected)) { \ + PK_TEST_ASSERT_BODY(expected, value) \ + exit(1); \ + } \ +} +#define PK_TEST_ASSERT_NEQ(expected, value) { \ + if ((value) == (expected)) { \ + PK_TEST_ASSERT_BODY(expected, value) \ + } \ +} +#define PK_TEST_ASSERT_NEQ_RET(expected, value) { \ + if ((value) == (expected)) { \ + PK_TEST_ASSERT_BODY(expected, value) \ + return -1; \ + } \ +} +#define PK_TEST_ASSERT_NEQ_EXIT(expected, value) { \ + if ((value) == (expected)) { \ + PK_TEST_ASSERT_BODY(expected, value) \ + exit(1); \ + } \ +} + +#ifdef PK_IMPL_TST + + +void pk_test_run_test_groups(pk_test_group_get **group_get_fns, unsigned long n_groups) { + int result; + unsigned long i; + unsigned int k, pass_count, total_test_count, total_test_pass_count, test_group_count, test_group_pass_count; + double elapsed_ms, group_ms, total_ms; + pk_tmr func_tmr, total_tmr; + pk_test_group *group; + + fprintf(stdout, "\r\n"); + fprintf(stdout, "[pk-test] Begin..\n"); + fprintf(stdout, "[pk-test] Running %04ld tests..\n", n_groups); + + i = 0; + total_ms = 0; + total_test_count = 0; + total_test_pass_count = 0; + test_group_count = 0; + test_group_pass_count = 0; + pk_tmr_start(total_tmr); + fprintf(stdout, "\r\n"); + for (i = 0; i < n_groups; ++i) { + test_group_count += 1; + pass_count = 0; + group_ms = 0; + group = group_get_fns[i](); + fprintf(stdout, "[pk-test][%s] Begin..\n", group->title); + if (group->group_setup != NULL) (group->group_setup)(); + for (k = 0; k < group->n_tests; ++k) { + total_test_count += 1; + fprintf(stdout, "[pk-test][%s][%s] Begin..\n", group->title, group->tests[k].title); + if (group->test_setup != NULL) (group->test_setup)(); + pk_tmr_start(func_tmr); + result = (group->tests[k].func)(); + pk_tmr_stop(func_tmr); + elapsed_ms = pk_tmr_duration_dbl_mili(func_tmr); + fprintf(stdout, "[pk-test][%s][%s] End.\n", group->title, group->tests[k].title); + group_ms += elapsed_ms; + total_ms += elapsed_ms; + fprintf(stdout, "[pk-test][%s][%s] Elapsed ms: '%f'.\n", group->title, group->tests[k].title, elapsed_ms); + if (result == group->tests[k].expected_result){ + total_test_pass_count += 1; + pass_count += 1; + fprintf(stdout, "[pk-test][%s][%s] %sPassed.%s\n", group->title, group->tests[k].title, PK_CLR_FG_GREEN, PK_CLR_RESET); + } else { + fprintf(stdout, "[pk-test][%s][%s] %sFailed.%s\n", group->title, group->tests[k].title, PK_CLR_FG_RED, PK_CLR_RESET); + fprintf(stdout, "[pk-test][%s][%s] Expected: '" PK_CLR_FG_GREEN "%i" PK_CLR_RESET "', Got: '" PK_CLR_FG_RED "%i" PK_CLR_RESET "'.\n", group->title, group->tests[k].title, group->tests[k].expected_result, result); + } + if (group->test_teardown != NULL) (group->test_teardown)(); + } + if (group->group_teardown != NULL) (group->group_teardown)(); + fprintf(stdout, "[pk-test][%s] End.\n", group->title); + fprintf(stdout, "[pk-test][%s] Tests completed: ( %s%04d%s / %04d ).\n", group->title, pass_count == group->n_tests ? PK_CLR_FG_GREEN : PK_CLR_FG_RED, pass_count, PK_CLR_RESET, group->n_tests); + fprintf(stdout, "[pk-test][%s] Elapsed ms: '%f'.\n\n", group->title, group_ms); + if (pass_count == group->n_tests) { + test_group_pass_count += 1; + } + } + pk_tmr_stop(total_tmr); + + fprintf(stdout, "[pk-test] End.\n"); + fprintf(stdout, "[pk-test] Tests completed: ( %s%04d%s / %04d ).\n", total_test_count == total_test_pass_count ? PK_CLR_FG_GREEN : PK_CLR_FG_RED, total_test_pass_count, PK_CLR_RESET, total_test_count); + fprintf(stdout, "[pk-test] Test groups completed: ( %s%04d%s / %04d ).\n", test_group_count == test_group_pass_count ? PK_CLR_FG_GREEN : PK_CLR_FG_RED, test_group_pass_count, PK_CLR_RESET, test_group_count); + fprintf(stdout, "[pk-test] Elapsed ms: '%f' (test fn sum).\n", total_ms); + fprintf(stdout, "[pk-test] Elapsed ms: '%f' (actual).\n\n", pk_tmr_duration_dbl_mili(total_tmr)); +} + +#endif /* PK_IMPL_TST */ + +#endif /* PK_PKTST_H */ #endif /* PK_SINGLE_HEADER_FILE_H */ diff --git a/tests/pke-test-types.h b/tests/pke-test-types.h index 097d42f..5a9ee24 100644 --- a/tests/pke-test-types.h +++ b/tests/pke-test-types.h @@ -3,7 +3,6 @@ #include <setjmp.h> #include <stdint.h> -#include <cmath> struct pke_test_long_jump { uint8_t expected_exit; @@ -39,9 +38,4 @@ struct pke_test_group { #define PKE_TEST_ASSERT(condition, index) if (!(condition)) { return ++index; } else { ++index; } -template<typename T> -inline bool flt_equal(T a, T b, T epsilon) { - return std::abs(a - b) < epsilon; -} - #endif /* PKE_PKE_TEST_TYPES_H */ |
