summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJonathan Bradley <jcb@pikum.xyz>2025-10-16 12:17:13 -0400
committerJonathan Bradley <jcb@pikum.xyz>2025-10-16 13:45:30 -0400
commit77c8686edd087a605b69e71c51c9adfe5bd26720 (patch)
treec079c39daf8f68f3dfb7caf3089a2d48ba81935e /src
parent22062b43dbfeb78bdabf8f2693fcf880349d9cde (diff)
pke: update pk.h to 0.9.4
Diffstat (limited to 'src')
-rw-r--r--src/pk.h217
1 files changed, 215 insertions, 2 deletions
diff --git a/src/pk.h b/src/pk.h
index f21bc1b..87d829e 100644
--- a/src/pk.h
+++ b/src/pk.h
@@ -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 */