Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ To integrate Fossil Test into your project, follow these steps:
# ======================
[wrap-git]
url = https://github.com/fossillogic/fossil-test.git
revision = v1.1.2
revision = v1.1.3

[provide]
fossil-test = fossil_test_dep
Expand Down
33 changes: 22 additions & 11 deletions code/logic/fossil/test/testing.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,22 @@
#define MAX_NAME_LENGTH 256

// Color codes
#define COLOR_RESET "\033[0m"
#define COLOR_PASS "\033[32m" // Green
#define COLOR_FAIL "\033[31m" // Red
#define COLOR_SKIP "\033[33m" // Yellow
#define COLOR_INFO "\033[34m" // Blue
#define COLOR_BDD "\033[35m" // Magenta
#define COLOR_CYAN "\033[36m" // Cyan
#define FOSSIL_TEST_COLOR_RESET "\033[0m" // Reset
#define FOSSIL_TEST_COLOR_GREEN "\033[32m" // Green
#define FOSSIL_TEST_COLOR_RED "\033[31m" // Red
#define FOSSIL_TEST_COLOR_YELLOW "\033[33m" // Yellow
#define FOSSIL_TEST_COLOR_BLUE "\033[34m" // Blue
#define FOSSIL_TEST_COLOR_MAGENTA "\033[35m" // Magenta
#define FOSSIL_TEST_COLOR_CYAN "\033[36m" // Cyan
#define FOSSIL_TEST_COLOR_WHITE "\033[97m" // White
#define FOSSIL_TEST_COLOR_PURPLE "\033[35m" // Purple
#define FOSSIL_TEST_COLOR_ORANGE "\033[38;5;208m" // Orange

#define FOSSIL_TEST_ATTR_BOLD "\033[1m" // Bold
#define FOSSIL_TEST_ATTR_DIM "\033[2m" // Dim
#define FOSSIL_TEST_ATTR_UNDERLINE "\033[4m" // Underline
#define FOSSIL_TEST_ATTR_ITATIC "\033[3m" // Italic


#include <setjmp.h>
#include <stddef.h>
Expand Down Expand Up @@ -54,6 +63,7 @@ typedef enum {
TEST_STATUS_PASS,
TEST_STATUS_FAIL,
TEST_STATUS_SKIP,
TEST_STATUS_EMPTY,
TEST_STATUS_TTIMEOUT
} test_status_t;

Expand Down Expand Up @@ -95,6 +105,7 @@ typedef struct fossil_test_env {
int pass_count;
int fail_count;
int skip_count;
int empty_count;
int timeout_count;
int unexpected_count;
double start_execution_time;
Expand Down Expand Up @@ -229,7 +240,7 @@ void fossil_test_print_stack_trace(stack_frame_t *stack_trace);
#define _FOSSIL_TEST_SKIP(test_name, message) \
test_name##_test_case.status = TEST_STATUS_SKIP; \
test_name##_test_case.failure_message = message; \
printf(COLOR_SKIP "SKIP: %s - %s\n" COLOR_RESET, #test_name, message); \
printf(FOSSIL_TEST_COLOR_YELLOW "SKIP: %s - %s\n" FOSSIL_TEST_COLOR_RESET, #test_name, message); \

/**
* @brief Macro to define a test case.
Expand Down Expand Up @@ -447,7 +458,7 @@ void fossil_test_print_stack_trace(stack_frame_t *stack_trace);
*/
#define _GIVEN(description) \
if (0) { \
printf(COLOR_BDD "Given %s\n" COLOR_RESET, description); \
printf(FOSSIL_TEST_COLOR_MAGENTA "Given %s\n" FOSSIL_TEST_COLOR_RESET, description); \
}

/**
Expand All @@ -460,7 +471,7 @@ void fossil_test_print_stack_trace(stack_frame_t *stack_trace);
*/
#define _WHEN(description) \
if (0) { \
printf(COLOR_BDD "When %s\n" COLOR_RESET, description); \
printf(FOSSIL_TEST_COLOR_MAGENTA "When %s\n" FOSSIL_TEST_COLOR_RESET, description); \
}

/**
Expand All @@ -473,7 +484,7 @@ void fossil_test_print_stack_trace(stack_frame_t *stack_trace);
*/
#define _THEN(description) \
if (0) { \
printf(COLOR_BDD "Then %s\n" COLOR_RESET, description); \
printf(FOSSIL_TEST_COLOR_MAGENTA "Then %s\n" FOSSIL_TEST_COLOR_RESET, description); \
}

#ifdef __cplusplus
Expand Down
149 changes: 81 additions & 68 deletions code/logic/testing.c
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ const char *timeout_messages[] = {
#endif

jmp_buf test_jump_buffer; // This will hold the jump buffer for longjmp
static int _ASSERT_COUNT = 0; // Counter for the number of assertions


// Custom implementation of strdup to avoid warnings on some platforms
Expand Down Expand Up @@ -320,7 +321,7 @@ void usage_info(void) {

void version_info(void) {
printf("Fossil Logic Test Framework\n");
printf("Version: 1.1.2\n");
printf("Version: 1.1.3\n");
printf("Author: Michael Gene Brockus (Dreamer)\n");
printf("License: Mozila Public License 2.0\n");
}
Expand Down Expand Up @@ -457,7 +458,7 @@ void fossil_test_register_suite(fossil_test_env_t *env, test_suite_t *suite) {
suite->next = env->test_suites;
env->test_suites = suite;
if (env->options.show_info) {
printf(COLOR_INFO "Registered test suite: %s\n" COLOR_RESET, suite->name);
printf(FOSSIL_TEST_COLOR_BLUE "Registered test suite: %s\n" FOSSIL_TEST_COLOR_RESET, suite->name);
}
}

Expand Down Expand Up @@ -505,6 +506,53 @@ void fossil_test_case_teardown(test_case_t *test_case) {
}
}

// Run all test cases in a test suite
void fossil_test_run_suite(test_suite_t *suite, fossil_test_env_t *env) {
if (!suite) return;

if (env->options.show_info) {
printf(FOSSIL_TEST_COLOR_BLUE "Running suite: %s\n" FOSSIL_TEST_COLOR_RESET, suite->name);
}

if (env->options.shuffle_enabled){
shuffle_test_cases(&suite->tests);
}

if (env->options.reverse) {
reverse_test_cases(&suite->tests);
}

if (suite->suite_setup_func) {
suite->suite_setup_func();
}

double total_execution_time = 0.0;
test_case_t *current_test = suite->tests;
while (current_test) {
fossil_test_run_case(current_test, env);
total_execution_time += current_test->execution_time;
current_test = current_test->next;
}

if (suite->suite_teardown_func) {
suite->suite_teardown_func();
}

if (env->options.show_info) {
printf(FOSSIL_TEST_COLOR_CYAN "Total execution time for suite %s: %.3f seconds\n" FOSSIL_TEST_COLOR_RESET, suite->name, total_execution_time);
}
}

// Internal function to handle assertions
void fossil_test_assert_internal(bool condition, const char *message, const char *file, int line, const char *func) {
_ASSERT_COUNT++; // Increment the assertion count

if (!condition) {
printf(FOSSIL_TEST_COLOR_RED "Assertion failed: %s (%s:%d in %s)\n" FOSSIL_TEST_COLOR_RESET, message, file, line, func);
longjmp(test_jump_buffer, 1); // Jump back to test case failure handler
}
}

// Run an individual test case
void fossil_test_run_case(test_case_t *test_case, fossil_test_env_t *env) {
if (!test_case) return;
Expand All @@ -517,86 +565,50 @@ void fossil_test_run_case(test_case_t *test_case, fossil_test_env_t *env) {
clock_t test_start_time = clock();
clock_t timeout_limit = test_start_time + 3 * 60 * CLOCKS_PER_SEC; // 3 minutes timeout

_ASSERT_COUNT = 0; // Reset assertion count before running the test

if (setjmp(env->env) == 0) {
for (int i = 0; i < env->options.repeat_count; i++) {
test_case->test_func();
if (clock() > timeout_limit) {
test_case->status = TEST_STATUS_TTIMEOUT;
printf(COLOR_FAIL "TIMEOUT: " COLOR_INFO " %s\n" COLOR_RESET, test_case->name);
printf(FOSSIL_TEST_COLOR_ORANGE "TIMEOUT: " FOSSIL_TEST_COLOR_BLUE " %s\n" FOSSIL_TEST_COLOR_RESET, test_case->name);
break;
}
}
} else {
test_case->status = TEST_STATUS_FAIL;
printf(COLOR_FAIL "FAIL: " COLOR_INFO " %s\n", test_case->name);
printf("Failure Message: %s\n" COLOR_RESET, test_case->failure_message);
printf(FOSSIL_TEST_COLOR_RED "FAIL: " FOSSIL_TEST_COLOR_BLUE " %s\n", test_case->name);
printf("Failure Message: %s\n" FOSSIL_TEST_COLOR_RESET, test_case->failure_message);
}
test_case->execution_time = (double)(clock() - test_start_time) / CLOCKS_PER_SEC;

// Check if the test case is empty
if (_ASSERT_COUNT == 0) {
printf(FOSSIL_TEST_COLOR_YELLOW "WARNING: " FOSSIL_TEST_COLOR_BLUE " %s contains no assertions\n" FOSSIL_TEST_COLOR_RESET, test_case->name);
}

// Run teardown
fossil_test_case_teardown(test_case);

// Log result
if (test_case->status == TEST_STATUS_PASS) {
if (env->options.show_info) {
printf(COLOR_PASS "PASS: " COLOR_INFO " %s (%.3f seconds)\n" COLOR_RESET, test_case->name, test_case->execution_time);
printf(FOSSIL_TEST_COLOR_GREEN "PASS: " FOSSIL_TEST_COLOR_BLUE " %s (%.3f seconds)\n" FOSSIL_TEST_COLOR_RESET, test_case->name, test_case->execution_time);
}
} else if (test_case->status == TEST_STATUS_FAIL) {
env->fail_count++;
} else if (test_case->status == TEST_STATUS_SKIP) {
env->skip_count++;
} else if (test_case->status == TEST_STATUS_TTIMEOUT) {
env->timeout_count++;
} else if (test_case->status == TEST_STATUS_EMPTY) {
env->empty_count++;
} else {
env->unexpected_count++;
}
}

// Run all test cases in a test suite
void fossil_test_run_suite(test_suite_t *suite, fossil_test_env_t *env) {
if (!suite) return;

if (env->options.show_info) {
printf(COLOR_INFO "Running suite: %s\n" COLOR_RESET, suite->name);
}

if (env->options.shuffle_enabled){
shuffle_test_cases(&suite->tests);
}

if (env->options.reverse) {
reverse_test_cases(&suite->tests);
}

if (suite->suite_setup_func) {
suite->suite_setup_func();
}

double total_execution_time = 0.0;
test_case_t *current_test = suite->tests;
while (current_test) {
fossil_test_run_case(current_test, env);
total_execution_time += current_test->execution_time;
current_test = current_test->next;
}

if (suite->suite_teardown_func) {
suite->suite_teardown_func();
}

if (env->options.show_info) {
printf(COLOR_CYAN "Total execution time for suite %s: %.3f seconds\n" COLOR_RESET, suite->name, total_execution_time);
}
}

// Internal function to handle assertions
void fossil_test_assert_internal(bool condition, const char *message, const char *file, int line, const char *func) {
if (!condition) {
printf("Assertion failed: %s (%s:%d in %s)\n", message, file, line, func);
longjmp(test_jump_buffer, 1); // Jump back to test case failure handler
}
}

void fossil_test_run_all(fossil_test_env_t *env) {
test_suite_t *current_suite = env->test_suites;

Expand All @@ -619,6 +631,7 @@ void fossil_test_init(fossil_test_env_t *env, int argc, char **argv) {
env->pass_count = 0;
env->fail_count = 0;
env->skip_count = 0;
env->empty_count = 0;
env->total_tests = 0;
env->timeout_count = 0;
env->start_execution_time = clock();
Expand All @@ -632,16 +645,16 @@ void fossil_test_message(fossil_test_env_t *env) {
// Seed random number generator
srand(time(NULL));

if (env->pass_count == 0 && env->fail_count == 0 && env->skip_count == 0 && env->timeout_count == 0) {
printf(COLOR_INFO "%s\n" COLOR_RESET, sarcastic_messages[rand() % 30]);
if (env->pass_count == 0 && env->fail_count == 0 && env->skip_count == 0 && env->timeout_count == 0 && env->empty_count > 0) {
printf(FOSSIL_TEST_COLOR_YELLOW FOSSIL_TEST_ATTR_ITATIC "%s\n" FOSSIL_TEST_COLOR_RESET, sarcastic_messages[rand() % 30]);
} else if (env->fail_count > 0) {
printf(COLOR_FAIL "%s\n" COLOR_RESET, humorous_messages[rand() % 30]);
printf(FOSSIL_TEST_COLOR_RED FOSSIL_TEST_ATTR_ITATIC "%s\n" FOSSIL_TEST_COLOR_RESET, humorous_messages[rand() % 30]);
} else if (env->pass_count > 0) {
printf(COLOR_PASS "%s\n" COLOR_RESET, great_news_messages[rand() % 30]);
printf(FOSSIL_TEST_COLOR_GREEN FOSSIL_TEST_ATTR_ITATIC "%s\n" FOSSIL_TEST_COLOR_RESET, great_news_messages[rand() % 30]);
} else if (env->timeout_count > 0) {
printf(COLOR_FAIL "%s\n" COLOR_RESET, timeout_messages[rand() % 30]);
printf(FOSSIL_TEST_COLOR_ORANGE FOSSIL_TEST_ATTR_ITATIC "%s\n" FOSSIL_TEST_COLOR_RESET, timeout_messages[rand() % 30]);
} else {
printf(COLOR_INFO "Test results are in. Keep pushing, you're getting there! 💪\n" COLOR_RESET);
printf(FOSSIL_TEST_COLOR_BLUE FOSSIL_TEST_ATTR_ITATIC "Test results are in. Keep pushing, you're getting there! 💪\n" FOSSIL_TEST_COLOR_RESET);
}
}

Expand Down Expand Up @@ -672,25 +685,25 @@ void fossil_test_summary(fossil_test_env_t *env) {
}
env->end_execution_time = clock();

printf(COLOR_INFO "===================================================================" COLOR_RESET);
printf(COLOR_INFO "\nFossil Test Summary:\n" COLOR_RESET);
printf(COLOR_INFO "===================================================================\n" COLOR_RESET);
printf(FOSSIL_TEST_COLOR_BLUE FOSSIL_TEST_ATTR_BOLD "===================================================================" FOSSIL_TEST_COLOR_RESET);
printf(FOSSIL_TEST_COLOR_CYAN FOSSIL_TEST_ATTR_BOLD FOSSIL_TEST_ATTR_ITATIC "\nFossil Test Summary:\n" FOSSIL_TEST_COLOR_RESET);
printf(FOSSIL_TEST_COLOR_BLUE FOSSIL_TEST_ATTR_BOLD "===================================================================\n" FOSSIL_TEST_COLOR_RESET);

printf(COLOR_INFO "Passed: " COLOR_PASS " %d\n" COLOR_RESET, env->pass_count);
printf(COLOR_INFO "Failed: " COLOR_FAIL " %d\n" COLOR_RESET, env->fail_count);
printf(COLOR_INFO "Skipped: " COLOR_SKIP " %d\n" COLOR_RESET, env->skip_count);
printf(COLOR_INFO "Timeout: " COLOR_SKIP " %d\n" COLOR_RESET, env->timeout_count);
printf(COLOR_INFO "Total: %d tests\n" COLOR_RESET, env->pass_count + env->fail_count + env->skip_count);
printf(FOSSIL_TEST_COLOR_CYAN FOSSIL_TEST_ATTR_ITATIC "Passed: " FOSSIL_TEST_COLOR_ORANGE " %d\n" FOSSIL_TEST_COLOR_RESET, env->pass_count);
printf(FOSSIL_TEST_COLOR_CYAN FOSSIL_TEST_ATTR_ITATIC "Failed: " FOSSIL_TEST_COLOR_ORANGE " %d\n" FOSSIL_TEST_COLOR_RESET, env->fail_count);
printf(FOSSIL_TEST_COLOR_CYAN FOSSIL_TEST_ATTR_ITATIC "Skipped:" FOSSIL_TEST_COLOR_ORANGE " %d\n" FOSSIL_TEST_COLOR_RESET, env->skip_count);
printf(FOSSIL_TEST_COLOR_CYAN FOSSIL_TEST_ATTR_ITATIC "Timeout:" FOSSIL_TEST_COLOR_ORANGE " %d\n" FOSSIL_TEST_COLOR_RESET, env->timeout_count);
printf(FOSSIL_TEST_COLOR_CYAN FOSSIL_TEST_ATTR_ITATIC "Total: %d tests\n" FOSSIL_TEST_COLOR_RESET, env->pass_count + env->fail_count + env->skip_count);

// Optionally, you could add the total execution time summary here
double total_execution_time = (double)(env->end_execution_time - env->start_execution_time) / CLOCKS_PER_SEC;
int seconds = (int)total_execution_time;
int milliseconds = (int)((total_execution_time - seconds) * 1000);
int microseconds = (int)((total_execution_time - seconds - milliseconds / 1000.0) * 1000000);

printf(COLOR_INFO "===================================================================\n" COLOR_RESET);
printf(COLOR_INFO "Execution time: (%.2d) seconds, (%.2d) milliseconds, (%.3d) microseconds\n" COLOR_RESET, seconds, milliseconds, microseconds);
printf(COLOR_INFO "===================================================================\n" COLOR_RESET);
printf(FOSSIL_TEST_COLOR_BLUE FOSSIL_TEST_ATTR_BOLD "===================================================================\n" FOSSIL_TEST_COLOR_RESET);
printf(FOSSIL_TEST_COLOR_CYAN FOSSIL_TEST_ATTR_ITATIC "Execution time: (%.2d) seconds, (%.2d) milliseconds, (%.3d) microseconds\n" FOSSIL_TEST_COLOR_RESET, seconds, milliseconds, microseconds);
printf(FOSSIL_TEST_COLOR_BLUE FOSSIL_TEST_ATTR_BOLD "===================================================================\n" FOSSIL_TEST_COLOR_RESET);

fossil_test_message(env);
}
Expand Down
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
project('Fossil Test', 'c', 'cpp',
meson_version: '>=1.3.0',
license: 'MPL-2.0',
version: '1.1.2',
version: '1.1.3',
default_options: ['c_std=c11,c18', 'cpp_std=c++20'])

subdir('code')