diff --git a/code/logic/fossil/test/mocking.h b/code/logic/fossil/test/mocking.h index d9f83b04..57cf09f4 100644 --- a/code/logic/fossil/test/mocking.h +++ b/code/logic/fossil/test/mocking.h @@ -92,8 +92,8 @@ * @param existing_type The existing type to create an alias for. */ #define _FOSSIL_MOCK_ALIAS(new_type, existing_type) \ - typedef existing_type fossil_mockup_##new_type##_type; \ - fossil_mockup_##new_type##_type fossil_mockup_##new_type(void) + typedef existing_type new_type; \ + new_type fossil_mockup_##new_type(void) /** * @def _FOSSIL_MOCK_STRUCT diff --git a/code/logic/fossil/test/testing.h b/code/logic/fossil/test/testing.h index 2b88a425..bd2c5a2e 100644 --- a/code/logic/fossil/test/testing.h +++ b/code/logic/fossil/test/testing.h @@ -362,7 +362,7 @@ void fossil_test_run_all(fossil_test_env_t *env); #define _FOSSIL_TEST_SKIP(test_name, message) \ test_name##_test_case.status = TEST_STATUS_SKIP; \ test_name##_test_case.failure_message = message; \ - printf(FOSSIL_TEST_COLOR_YELLOW "SKIP: %s - %s\n" FOSSIL_TEST_COLOR_RESET, #test_name, message); \ + printf(FOSSIL_TEST_COLOR_YELLOW "SKIPPED: %s - %s\n" FOSSIL_TEST_COLOR_RESET, #test_name, message); \ /** * @brief Macro to define a test case. diff --git a/code/logic/marking.c b/code/logic/marking.c index a3a1d39a..3fd1e0db 100644 --- a/code/logic/marking.c +++ b/code/logic/marking.c @@ -93,6 +93,11 @@ void assume_duration(double expected, double actual, double unit) { // Marks a test case as timeout with a specified time and prints it to stderr. void fossil_test_benchmark(char* duration_type, double expected, double actual) { + if (duration_type == NULL) { + printf("Error: duration_type is NULL\n"); + return; + } + if (strcmp(duration_type, "minutes") == 0) { assume_duration(expected, actual, 60.0); } else if (strcmp(duration_type, "seconds") == 0) { @@ -119,6 +124,16 @@ void fossil_test_benchmark(char* duration_type, double expected, double actual) } // end of func void fossil_benchmark_init(fossil_benchmark_t* benchmark, const char* name) { + if (benchmark == NULL) { + printf("Error: benchmark is NULL\n"); + return; + } + + if (name == NULL) { + printf("Error: name is NULL\n"); + return; + } + benchmark->name = name; benchmark->num_samples = 0; benchmark->total_duration = 0.0; @@ -128,6 +143,11 @@ void fossil_benchmark_init(fossil_benchmark_t* benchmark, const char* name) { } void fossil_benchmark_start(fossil_benchmark_t* benchmark) { + if (benchmark == NULL) { + printf("Error: benchmark is NULL\n"); + return; + } + if (!benchmark->running) { benchmark->start_time = clock(); benchmark->running = 1; @@ -135,6 +155,11 @@ void fossil_benchmark_start(fossil_benchmark_t* benchmark) { } void fossil_benchmark_stop(fossil_benchmark_t* benchmark) { + if (benchmark == NULL) { + printf("Error: benchmark is NULL\n"); + return; + } + if (benchmark->running) { benchmark->end_time = clock(); double elapsed = ((double)(benchmark->end_time - benchmark->start_time)) / CLOCKS_PER_SEC; @@ -151,22 +176,42 @@ void fossil_benchmark_stop(fossil_benchmark_t* benchmark) { } double fossil_benchmark_elapsed_seconds(const fossil_benchmark_t* benchmark) { + if (benchmark == NULL) { + printf("Error: benchmark is NULL\n"); + return 0.0; + } return benchmark->total_duration; } double fossil_benchmark_min_time(const fossil_benchmark_t* benchmark) { + if (benchmark == NULL) { + printf("Error: benchmark is NULL\n"); + return 0.0; + } return benchmark->min_duration; } double fossil_benchmark_max_time(const fossil_benchmark_t* benchmark) { + if (benchmark == NULL) { + printf("Error: benchmark is NULL\n"); + return 0.0; + } return benchmark->max_duration; } double fossil_benchmark_avg_time(const fossil_benchmark_t* benchmark) { + if (benchmark == NULL) { + printf("Error: benchmark is NULL\n"); + return 0.0; + } return benchmark->num_samples > 0 ? benchmark->total_duration / benchmark->num_samples : 0.0; } void fossil_benchmark_reset(fossil_benchmark_t* benchmark) { + if (benchmark == NULL) { + printf("Error: benchmark is NULL\n"); + return; + } benchmark->num_samples = 0; benchmark->total_duration = 0.0; benchmark->min_duration = DBL_MAX; @@ -174,6 +219,10 @@ void fossil_benchmark_reset(fossil_benchmark_t* benchmark) { } void fossil_benchmark_report(const fossil_benchmark_t* benchmark) { + if (benchmark == NULL) { + printf("Error: benchmark is NULL\n"); + return; + } printf("\033[1;36mBenchmark : %s\n", benchmark->name); printf("\033[1;32mTotal Time: %.6f seconds\n", fossil_benchmark_elapsed_seconds(benchmark)); printf("\033[1;32mMin Time : %.6f seconds\n", fossil_benchmark_min_time(benchmark)); @@ -182,10 +231,25 @@ void fossil_benchmark_report(const fossil_benchmark_t* benchmark) { } void fossil_scoped_benchmark_init(scoped_benchmark_t* scoped_benchmark, fossil_benchmark_t* benchmark) { + if (scoped_benchmark == NULL) { + printf("Error: scoped_benchmark is NULL\n"); + return; + } + + if (benchmark == NULL) { + printf("Error: benchmark is NULL\n"); + return; + } + scoped_benchmark->benchmark = benchmark; fossil_benchmark_start(scoped_benchmark->benchmark); } void fossil_scoped_benchmark_destroy(scoped_benchmark_t* scoped_benchmark) { + if (scoped_benchmark == NULL) { + printf("Error: scoped_benchmark is NULL\n"); + return; + } + fossil_benchmark_stop(scoped_benchmark->benchmark); } diff --git a/code/logic/mocking.c b/code/logic/mocking.c index 2781b731..1b7d2a17 100644 --- a/code/logic/mocking.c +++ b/code/logic/mocking.c @@ -19,12 +19,19 @@ extern char *_custom_fossil_test_strdup(const char *str); void fossil_mock_init(MockCallList *list) { + if (!list) { + return; + } list->head = NULL; list->tail = NULL; list->size = 0; } void fossil_mock_destroy(MockCallList *list) { + if (!list) { + return; + } + MockCall *current = list->head; while (current) { MockCall *next = current->next; @@ -36,15 +43,47 @@ void fossil_mock_destroy(MockCallList *list) { free(current); current = next; } + list->head = NULL; + list->tail = NULL; + list->size = 0; } void fossil_mock_add_call(MockCallList *list, const char *function_name, char **arguments, int num_args) { + if (!list || !function_name || !arguments) { + return; + } + MockCall *call = (MockCall *)malloc(sizeof(MockCall)); + if (!call) { + return; + } + call->function_name = _custom_fossil_test_strdup(function_name); + if (!call->function_name) { + free(call); + return; + } + call->arguments = (char **)malloc(num_args * sizeof(char *)); + if (!call->arguments) { + free(call->function_name); + free(call); + return; + } + for (int i = 0; i < num_args; ++i) { call->arguments[i] = _custom_fossil_test_strdup(arguments[i]); + if (!call->arguments[i]) { + for (int j = 0; j < i; ++j) { + free(call->arguments[j]); + } + free(call->arguments); + free(call->function_name); + free(call); + return; + } } + call->num_args = num_args; call->next = NULL; @@ -58,6 +97,10 @@ void fossil_mock_add_call(MockCallList *list, const char *function_name, char ** } void fossil_mock_print(MockCallList *list) { + if (!list) { + return; + } + MockCall *current = list->head; while (current) { printf("Function: %s\n", current->function_name); diff --git a/code/logic/testing.c b/code/logic/testing.c index cd80f7d1..cde5688f 100644 --- a/code/logic/testing.c +++ b/code/logic/testing.c @@ -586,13 +586,13 @@ void fossil_test_assert_internal(bool condition, const char *message, const char _ASSERT_COUNT++; // Increment the assertion count if (!condition) { - // Check if the current assertion is the same as the last one - if (last_message && strcmp(last_message, message) == 0 && + // Check if the current assertion is the same or similar to the last one + if (last_message && strstr(message, last_message) != NULL && last_file && strcmp(last_file, file) == 0 && last_line == line && last_func && strcmp(last_func, func) == 0) { anomaly_count++; - printf(FOSSIL_TEST_COLOR_YELLOW "Duplicate assertion detected: %s (%s:%d in %s) [Anomaly Count: %d]\n" FOSSIL_TEST_COLOR_RESET, message, file, line, func, anomaly_count); + printf(FOSSIL_TEST_COLOR_YELLOW "Duplicate or similar assertion detected: %s (%s:%d in %s) [Anomaly Count: %d]\n" FOSSIL_TEST_COLOR_RESET, message, file, line, func, anomaly_count); } else { anomaly_count = 0; // Reset anomaly count for new assertion printf(FOSSIL_TEST_COLOR_RED "Assertion failed: %s (%s:%d in %s)\n" FOSSIL_TEST_COLOR_RESET, message, file, line, func); @@ -635,14 +635,14 @@ void fossil_test_run_case(test_case_t *test_case, fossil_test_env_t *env) { } } else { test_case->status = TEST_STATUS_FAIL; - printf(FOSSIL_TEST_COLOR_RED "FAIL: " FOSSIL_TEST_COLOR_BLUE " %s\n", test_case->name); + printf(FOSSIL_TEST_COLOR_RED "FAILED: " 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); + printf(FOSSIL_TEST_COLOR_YELLOW "WARNING: %s contains no assertions\n" FOSSIL_TEST_COLOR_RESET, test_case->name); } // Run teardown @@ -651,7 +651,7 @@ void fossil_test_run_case(test_case_t *test_case, fossil_test_env_t *env) { // Log result if (test_case->status == TEST_STATUS_PASS) { if (env->options.show_info) { - 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); + printf(FOSSIL_TEST_COLOR_GREEN "PASSED: " 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++; diff --git a/code/tests/cases/test_bdd.c b/code/tests/cases/test_bdd.c index 31ff1970..4cb60fa7 100644 --- a/code/tests/cases/test_bdd.c +++ b/code/tests/cases/test_bdd.c @@ -158,6 +158,63 @@ FOSSIL_TEST_CASE(xbdd_invalid_login) { } } // end of case +FOSSIL_TEST_CASE(xbdd_insufficient_balance) { + GIVEN("a user's account with insufficient balance") { + // Set up the context + float accountBalance = 100.0; + float withdrawalAmount = 200.0; + + WHEN("the user requests a withdrawal of $200") { + // Perform the withdrawal action + bool withdrawalSuccess = false; + if (accountBalance >= withdrawalAmount) { + accountBalance -= withdrawalAmount; + withdrawalSuccess = true; + } + + THEN("the withdrawal should fail and balance should remain unchanged") { + // Check the expected outcome + FOSSIL_TEST_ASSUME(!withdrawalSuccess, "Withdrawal should not succeed"); + FOSSIL_TEST_ASSUME(accountBalance == 100.0, "Account balance should remain unchanged"); + } + } + } +} // end of case + +FOSSIL_TEST_CASE(xbdd_add_multiple_items_to_cart) { + GIVEN("a user with an empty shopping cart") { + // Set up the context + int cartItemCount = 0; + + WHEN("the user adds three products to the cart") { + // Perform the action of adding products + cartItemCount += 3; + + THEN("the cart item count should increase by 3") { + // Check the expected outcome + FOSSIL_TEST_ASSUME(cartItemCount == 3, "Cart item count should have increased by 3"); + } + } + } +} // end of case + +FOSSIL_TEST_CASE(xbdd_remove_item_from_cart) { + GIVEN("a user with a shopping cart containing 2 items") { + // Set up the context + int cartItemCount = 2; + + WHEN("the user removes one product from the cart") { + // Perform the action of removing a product + cartItemCount--; + + THEN("the cart item count should decrease by 1") { + // Check the expected outcome + FOSSIL_TEST_ASSUME(cartItemCount == 1, "Cart item count should have decreased by 1"); + } + } + } +} // end of case + // * * * * * * * * * * * * * * * * * * * * * * * * // * Fossil Logic Test Pool // * * * * * * * * * * * * * * * * * * * * * * * * @@ -167,6 +224,9 @@ FOSSIL_TEST_GROUP(c_bdd_test_cases) { FOSSIL_TEST_ADD(bdd_suite, xbdd_empty_cart); FOSSIL_TEST_ADD(bdd_suite, xbdd_valid_login); FOSSIL_TEST_ADD(bdd_suite, xbdd_invalid_login); + FOSSIL_TEST_ADD(bdd_suite, xbdd_insufficient_balance); + FOSSIL_TEST_ADD(bdd_suite, xbdd_add_multiple_items_to_cart); + FOSSIL_TEST_ADD(bdd_suite, xbdd_remove_item_from_cart); FOSSIL_TEST_REGISTER(bdd_suite); } // end of group diff --git a/code/tests/cases/test_bdd.cpp b/code/tests/cases/test_bdd.cpp index 2681db75..dfb49322 100644 --- a/code/tests/cases/test_bdd.cpp +++ b/code/tests/cases/test_bdd.cpp @@ -159,6 +159,63 @@ FOSSIL_TEST_CASE(cpp_xbdd_invalid_login) { } } // end of case +FOSSIL_TEST_CASE(cpp_xbdd_insufficient_balance) { + GIVEN("a user's account with insufficient balance") { + // Set up the context + float accountBalance = 100.0; + float withdrawalAmount = 200.0; + + WHEN("the user requests a withdrawal of $200") { + // Perform the withdrawal action + bool withdrawalSuccess = false; + if (accountBalance >= withdrawalAmount) { + accountBalance -= withdrawalAmount; + withdrawalSuccess = true; + } + + THEN("the withdrawal should fail and balance should remain unchanged") { + // Check the expected outcome + FOSSIL_TEST_ASSUME(!withdrawalSuccess, "Withdrawal should not succeed"); + FOSSIL_TEST_ASSUME(accountBalance == 100.0, "Account balance should remain unchanged"); + } + } + } +} // end of case + +FOSSIL_TEST_CASE(cpp_xbdd_add_multiple_items_to_cart) { + GIVEN("a user with an empty shopping cart") { + // Set up the context + int cartItemCount = 0; + + WHEN("the user adds three products to the cart") { + // Perform the action of adding products + cartItemCount += 3; + + THEN("the cart item count should increase by 3") { + // Check the expected outcome + FOSSIL_TEST_ASSUME(cartItemCount == 3, "Cart item count should have increased by 3"); + } + } + } +} // end of case + +FOSSIL_TEST_CASE(cpp_xbdd_remove_item_from_cart) { + GIVEN("a user with a shopping cart containing 2 items") { + // Set up the context + int cartItemCount = 2; + + WHEN("the user removes one product from the cart") { + // Perform the action of removing a product + cartItemCount--; + + THEN("the cart item count should decrease by 1") { + // Check the expected outcome + FOSSIL_TEST_ASSUME(cartItemCount == 1, "Cart item count should have decreased by 1"); + } + } + } +} // end of case + // * * * * * * * * * * * * * * * * * * * * * * * * // * Fossil Logic Test Pool // * * * * * * * * * * * * * * * * * * * * * * * * @@ -168,6 +225,9 @@ FOSSIL_TEST_GROUP(cpp_bdd_test_cases) { FOSSIL_TEST_ADD(cpp_bdd_suite, cpp_xbdd_empty_cart); FOSSIL_TEST_ADD(cpp_bdd_suite, cpp_xbdd_valid_login); FOSSIL_TEST_ADD(cpp_bdd_suite, cpp_xbdd_invalid_login); + FOSSIL_TEST_ADD(cpp_bdd_suite, cpp_xbdd_insufficient_balance); + FOSSIL_TEST_ADD(cpp_bdd_suite, cpp_xbdd_add_multiple_items_to_cart); + FOSSIL_TEST_ADD(cpp_bdd_suite, cpp_xbdd_remove_item_from_cart); FOSSIL_TEST_REGISTER(cpp_bdd_suite); } // end of group diff --git a/code/tests/cases/test_mock.c b/code/tests/cases/test_mock.c new file mode 100644 index 00000000..64973ca0 --- /dev/null +++ b/code/tests/cases/test_mock.c @@ -0,0 +1,176 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * Date: 07/01/2024 + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include +#include + + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Utilites +// * * * * * * * * * * * * * * * * * * * * * * * * +// Setup steps for things like test fixtures and +// mock objects are set here. +// * * * * * * * * * * * * * * * * * * * * * * * * + +// Define the test suite and add test cases +FOSSIL_TEST_SUITE(c_mock_suite); + +// Setup function for the test suite +FOSSIL_SETUP(c_mock_suite) { + // Setup code here +} + +// Teardown function for the test suite +FOSSIL_TEARDOWN(c_mock_suite) { + // Teardown code here +} + +FOSSIL_MOCK_ALIAS(MockInt, int); + +// Example of creating a mock struct using the macro +FOSSIL_MOCK_STRUCT(MockStruct) { + int a; + char b; +} MockStruct; + +// Example of creating a mock function using the macro +FOSSIL_MOCK_FUNC(int, mock_function, int a, int b) { + return a + b; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Cases +// * * * * * * * * * * * * * * * * * * * * * * * * +// The test cases below are provided as samples, showcasing +// Domain-Driven Design (DDD) usage in the Fossil Logic project. +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST_CASE(c_mock_call_list_initialization) { + // Example of initializing a MockCallList + MockCallList list; + fossil_mock_init(&list); + + // Test cases + FOSSIL_TEST_ASSUME(list.head == NULL, "MockCallList head should be NULL after initialization"); + FOSSIL_TEST_ASSUME(list.tail == NULL, "MockCallList tail should be NULL after initialization"); + FOSSIL_TEST_ASSUME(list.size == 0, "MockCallList size should be 0 after initialization"); +} // end case + +FOSSIL_TEST_CASE(c_mock_call_list_addition) { + // Example of adding a MockCall to a MockCallList + MockCallList list; + fossil_mock_init(&list); + char *args[] = {"arg1", "arg2"}; + fossil_mock_add_call(&list, "test_function", args, 2); + + // Test cases + FOSSIL_TEST_ASSUME(list.size == 1, "MockCallList size should be 1 after adding a call"); + FOSSIL_TEST_ASSUME(strcmp(list.head->function_name, "test_function") == 0, "Function name should be 'test_function'"); + FOSSIL_TEST_ASSUME(list.head->num_args == 2, "Number of arguments should be 2"); + FOSSIL_TEST_ASSUME(strcmp(list.head->arguments[0], "arg1") == 0, "First argument should be 'arg1'"); + FOSSIL_TEST_ASSUME(strcmp(list.head->arguments[1], "arg2") == 0, "Second argument should be 'arg2'"); +} // end case + +FOSSIL_TEST_CASE(c_mock_call_list_destruction) { + // Example of destroying a MockCallList + MockCallList list; + fossil_mock_init(&list); + char *args[] = {"arg1", "arg2"}; + fossil_mock_add_call(&list, "test_function", args, 2); + FOSSIL_TEST_ASSUME(list.size == 1, "MockCallList size should be 1 after adding a call"); + FOSSIL_TEST_ASSUME(strcmp(list.head->function_name, "test_function") == 0, "Function name should be 'test_function'"); + FOSSIL_TEST_ASSUME(list.head->num_args == 2, "Number of arguments should be 2"); + + fossil_mock_destroy(&list); // not allowed to access due to the object being freed +} // end case + +FOSSIL_TEST_CASE(c_mock_call_list_initialization_macro) { + // Example of initializing a MockCallList using the macro + MockCallList list; + MOCK_INIT(list); + + // Test cases + FOSSIL_TEST_ASSUME(list.head == NULL, "MockCallList head should be NULL after initialization"); + FOSSIL_TEST_ASSUME(list.tail == NULL, "MockCallList tail should be NULL after initialization"); + FOSSIL_TEST_ASSUME(list.size == 0, "MockCallList size should be 0 after initialization"); +} // end case + +FOSSIL_TEST_CASE(c_mock_call_list_addition_macro) { + // Example of adding a MockCall to a MockCallList using the macro + MockCallList list; + MOCK_INIT(list); + char *args[] = {"arg1", "arg2"}; + MOCK_ADD_CALL(list, "test_function", args, 2); + + // Test cases + FOSSIL_TEST_ASSUME(list.size == 1, "MockCallList size should be 1 after adding a call"); + FOSSIL_TEST_ASSUME(strcmp(list.head->function_name, "test_function") == 0, "Function name should be 'test_function'"); + FOSSIL_TEST_ASSUME(list.head->num_args == 2, "Number of arguments should be 2"); + FOSSIL_TEST_ASSUME(strcmp(list.head->arguments[0], "arg1") == 0, "First argument should be 'arg1'"); + FOSSIL_TEST_ASSUME(strcmp(list.head->arguments[1], "arg2") == 0, "Second argument should be 'arg2'"); +} // end case + +FOSSIL_TEST_CASE(c_mock_call_list_destruction_macro) { + // Example of destroying a MockCallList using the macro + MockCallList list; + MOCK_INIT(list); + char *args[] = {"arg1", "arg2"}; + MOCK_ADD_CALL(list, "test_function", args, 2); + + FOSSIL_TEST_ASSUME(list.size == 1, "MockCallList size should be 1 after adding a call"); + FOSSIL_TEST_ASSUME(strcmp(list.head->function_name, "test_function") == 0, "Function name should be 'test_function'"); + FOSSIL_TEST_ASSUME(list.head->num_args == 2, "Number of arguments should be 2"); + + MOCK_DESTROY(list); // not allowed to access due to the object being freed +} // end case + +FOSSIL_TEST_CASE(c_mock_function_creation) { + // Test cases + FOSSIL_TEST_ASSUME(fossil_mockup_mock_function(2, 3) == 5, "Mock function should return the sum of its arguments"); +} // end case + +FOSSIL_TEST_CASE(c_mock_alias_creation) { + // Example of creating a type alias using the macro + + + // Test cases + MockInt x = 10; + FOSSIL_TEST_ASSUME(x == 10, "Mock alias should behave like the original type"); +} // end case + +FOSSIL_TEST_CASE(c_mock_struct_creation) { + // Test cases + MockStruct instance; + instance.a = 5; + instance.b = 'c'; + FOSSIL_TEST_ASSUME(instance.a == 5, "Mock struct member 'a' should be 5"); + FOSSIL_TEST_ASSUME(instance.b == 'c', "Mock struct member 'b' should be 'c'"); +} // end case + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Pool +// * * * * * * * * * * * * * * * * * * * * * * * * +FOSSIL_TEST_GROUP(c_mock_test_cases) { + FOSSIL_TEST_ADD(c_mock_suite, c_mock_call_list_initialization); + FOSSIL_TEST_ADD(c_mock_suite, c_mock_call_list_addition); + FOSSIL_TEST_ADD(c_mock_suite, c_mock_call_list_destruction); + FOSSIL_TEST_ADD(c_mock_suite, c_mock_call_list_initialization_macro); + FOSSIL_TEST_ADD(c_mock_suite, c_mock_call_list_addition_macro); + FOSSIL_TEST_ADD(c_mock_suite, c_mock_call_list_destruction_macro); + FOSSIL_TEST_ADD(c_mock_suite, c_mock_function_creation); + FOSSIL_TEST_ADD(c_mock_suite, c_mock_alias_creation); + FOSSIL_TEST_ADD(c_mock_suite, c_mock_struct_creation); + + FOSSIL_TEST_REGISTER(c_mock_suite); +} // end of group diff --git a/code/tests/cases/test_mock.cpp b/code/tests/cases/test_mock.cpp new file mode 100644 index 00000000..84311b78 --- /dev/null +++ b/code/tests/cases/test_mock.cpp @@ -0,0 +1,176 @@ +/* + * ----------------------------------------------------------------------------- + * Project: Fossil Logic + * + * This file is part of the Fossil Logic project, which aims to develop high- + * performance, cross-platform applications and libraries. The code contained + * herein is subject to the terms and conditions defined in the project license. + * + * Author: Michael Gene Brockus (Dreamer) + * Date: 07/01/2024 + * + * Copyright (C) 2024 Fossil Logic. All rights reserved. + * ----------------------------------------------------------------------------- + */ +#include +#include +#include + + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Utilites +// * * * * * * * * * * * * * * * * * * * * * * * * +// Setup steps for things like test fixtures and +// mock objects are set here. +// * * * * * * * * * * * * * * * * * * * * * * * * + +// Define the test suite and add test cases +FOSSIL_TEST_SUITE(cpp_mock_suite); + +// Setup function for the test suite +FOSSIL_SETUP(cpp_mock_suite) { + // Setup code here +} + +// Teardown function for the test suite +FOSSIL_TEARDOWN(cpp_mock_suite) { + // Teardown code here +} + +FOSSIL_MOCK_ALIAS(MockInt, int); + +// Example of creating a mock struct using the macro +FOSSIL_MOCK_STRUCT(MockStruct) { + int a; + char b; +}; + +// Example of creating a mock function using the macro +FOSSIL_MOCK_FUNC(int, mock_function, int a, int b) { + return a + b; +} + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Cases +// * * * * * * * * * * * * * * * * * * * * * * * * +// The test cases below are provided as samples, showcasing +// Domain-Driven Design (DDD) usage in the Fossil Logic project. +// * * * * * * * * * * * * * * * * * * * * * * * * + +FOSSIL_TEST_CASE(cpp_mock_call_list_initialization) { + // Example of initializing a MockCallList + MockCallList list; + fossil_mock_init(&list); + + // Test cases + FOSSIL_TEST_ASSUME(list.head == NULL, "MockCallList head should be NULL after initialization"); + FOSSIL_TEST_ASSUME(list.tail == NULL, "MockCallList tail should be NULL after initialization"); + FOSSIL_TEST_ASSUME(list.size == 0, "MockCallList size should be 0 after initialization"); +} // end case + +FOSSIL_TEST_CASE(cpp_mock_call_list_addition) { + // Example of adding a MockCall to a MockCallList + MockCallList list; + fossil_mock_init(&list); + const char* args[] = {"arg1", "arg2"}; + fossil_mock_add_call(&list, "test_function", (char**)args, 2); + + // Test cases + FOSSIL_TEST_ASSUME(list.size == 1, "MockCallList size should be 1 after adding a call"); + //FOSSIL_TEST_ASSUME(list.head->function_name == "test_function", "Function name should be 'test_function'"); + FOSSIL_TEST_ASSUME(list.head->num_args == 2, "Number of arguments should be 2"); + FOSSIL_TEST_ASSUME(std::strcmp(list.head->arguments[0], "arg1") == 0, "First argument should be 'arg1'"); + FOSSIL_TEST_ASSUME(std::strcmp(list.head->arguments[1], "arg2") == 0, "Second argument should be 'arg2'"); +} // end case + +FOSSIL_TEST_CASE(cpp_mock_call_list_destruction) { + // Example of destroying a MockCallList + MockCallList list; + fossil_mock_init(&list); + const char* args[] = {"arg1", "arg2"}; + fossil_mock_add_call(&list, "test_function", (char**)args, 2); + FOSSIL_TEST_ASSUME(list.size == 1, "MockCallList size should be 1 after adding a call"); + FOSSIL_TEST_ASSUME(strcmp(list.head->function_name, "test_function") == 0, "Function name should be 'test_function'"); + FOSSIL_TEST_ASSUME(list.head->num_args == 2, "Number of arguments should be 2"); + + fossil_mock_destroy(&list); // not allowed to access due to the object being freed +} // end case + +FOSSIL_TEST_CASE(cpp_mock_call_list_initialization_macro) { + // Example of initializing a MockCallList using the macro + MockCallList list; + MOCK_INIT(list); + + // Test cases + FOSSIL_TEST_ASSUME(list.head == NULL, "MockCallList head should be NULL after initialization"); + FOSSIL_TEST_ASSUME(list.tail == NULL, "MockCallList tail should be NULL after initialization"); + FOSSIL_TEST_ASSUME(list.size == 0, "MockCallList size should be 0 after initialization"); +} // end case + +FOSSIL_TEST_CASE(cpp_mock_call_list_addition_macro) { + // Example of adding a MockCall to a MockCallList using the macro + MockCallList list; + MOCK_INIT(list); + const char* args[] = {"arg1", "arg2"}; + MOCK_ADD_CALL(list, "test_function", (char**)args, 2); + + // Test cases + FOSSIL_TEST_ASSUME(list.size == 1, "MockCallList size should be 1 after adding a call"); + //FOSSIL_TEST_ASSUME(list.head->function_name == "test_function", "Function name should be 'test_function'"); + FOSSIL_TEST_ASSUME(list.head->num_args == 2, "Number of arguments should be 2"); + FOSSIL_TEST_ASSUME(std::strcmp(list.head->arguments[0], "arg1") == 0, "First argument should be 'arg1'"); + FOSSIL_TEST_ASSUME(std::strcmp(list.head->arguments[1], "arg2") == 0, "Second argument should be 'arg2'"); +} // end case + +FOSSIL_TEST_CASE(cpp_mock_call_list_destruction_macro) { + // Example of destroying a MockCallList using the macro + MockCallList list; + MOCK_INIT(list); + const char* args[] = {"arg1", "arg2"}; + MOCK_ADD_CALL(list, "test_function", (char**)args, 2); + FOSSIL_TEST_ASSUME(list.size == 1, "MockCallList size should be 1 after adding a call"); + FOSSIL_TEST_ASSUME(strcmp(list.head->function_name, "test_function") == 0, "Function name should be 'test_function'"); + FOSSIL_TEST_ASSUME(list.head->num_args == 2, "Number of arguments should be 2"); + + MOCK_DESTROY(list); // not allowed to access due to the object being freed +} // end case + +FOSSIL_TEST_CASE(cpp_mock_function_creation) { + // Test cases + FOSSIL_TEST_ASSUME(fossil_mockup_mock_function(2, 3) == 5, "Mock function should return the sum of its arguments"); +} // end case + +FOSSIL_TEST_CASE(cpp_mock_alias_creation) { + // Example of creating a type alias using the macro + + + // Test cases + MockInt x = 10; + FOSSIL_TEST_ASSUME(x == 10, "Mock alias should behave like the original type"); +} // end case + +FOSSIL_TEST_CASE(cpp_mock_struct_creation) { + // Test cases + MockStruct instance; + instance.a = 5; + instance.b = 'c'; + FOSSIL_TEST_ASSUME(instance.a == 5, "Mock struct member 'a' should be 5"); + FOSSIL_TEST_ASSUME(instance.b == 'c', "Mock struct member 'b' should be 'c'"); +} // end case + +// * * * * * * * * * * * * * * * * * * * * * * * * +// * Fossil Logic Test Pool +// * * * * * * * * * * * * * * * * * * * * * * * * +FOSSIL_TEST_GROUP(cpp_mock_test_cases) { + FOSSIL_TEST_ADD(cpp_mock_suite, cpp_mock_call_list_initialization); + FOSSIL_TEST_ADD(cpp_mock_suite, cpp_mock_call_list_addition); + FOSSIL_TEST_ADD(cpp_mock_suite, cpp_mock_call_list_destruction); + FOSSIL_TEST_ADD(cpp_mock_suite, cpp_mock_call_list_initialization_macro); + FOSSIL_TEST_ADD(cpp_mock_suite, cpp_mock_call_list_addition_macro); + FOSSIL_TEST_ADD(cpp_mock_suite, cpp_mock_call_list_destruction_macro); + FOSSIL_TEST_ADD(cpp_mock_suite, cpp_mock_function_creation); + FOSSIL_TEST_ADD(cpp_mock_suite, cpp_mock_alias_creation); + FOSSIL_TEST_ADD(cpp_mock_suite, cpp_mock_struct_creation); + + FOSSIL_TEST_REGISTER(cpp_mock_suite); +} // end of group diff --git a/code/tests/cases/test_sample.c b/code/tests/cases/test_sample.c index 27d0cc73..5009d8cd 100644 --- a/code/tests/cases/test_sample.c +++ b/code/tests/cases/test_sample.c @@ -74,11 +74,46 @@ FOSSIL_TEST_CASE(test_should_not_run) { FOSSIL_TEST_ASSUME(1 == 0, "This test should not run"); } +// A simple test case to check if input % 2 equals expected_output +FOSSIL_TEST_CASE(test_input_modulo) { + CSampleTestData data = { .input = 5, .expected_output = 1 }; + + int actual_output = data.input % 2; + + FOSSIL_TEST_ASSUME(actual_output == data.expected_output, "Modulo test failed"); +} + +// A simple test case to check if input squared equals expected_output +FOSSIL_TEST_CASE(test_input_square) { + CSampleTestData data = { .input = 3, .expected_output = 9 }; + + int actual_output = data.input * data.input; + + FOSSIL_TEST_ASSUME(actual_output == data.expected_output, "Square test failed"); +} + +// A simple test case to check if input is equal to expected_output +FOSSIL_TEST_CASE(test_input_equal) { + CSampleTestData data = { .input = 7, .expected_output = 7 }; + + int actual_output = data.input; + + FOSSIL_TEST_ASSUME(actual_output == data.expected_output, "Equality test failed"); +} + +FOSSIL_TEST_CASE(test_has_no_assertions) { + // This test has no assertions +} + FOSSIL_TEST_GROUP(c_sample_test_cases) { FOSSIL_TEST_ADD(sample_suite, test_input_increment); FOSSIL_TEST_ADD(sample_suite, test_input_decrement); FOSSIL_TEST_ADD(sample_suite, test_input_double); FOSSIL_TEST_ADD(sample_suite, test_input_half); + FOSSIL_TEST_ADD(sample_suite, test_input_modulo); + FOSSIL_TEST_ADD(sample_suite, test_input_square); + FOSSIL_TEST_ADD(sample_suite, test_input_equal); + FOSSIL_TEST_ADD(sample_suite, test_has_no_assertions); // Should be detected as empty FOSSIL_TEST_SKIP(test_should_not_run, "This test should not run"); diff --git a/code/tests/cases/test_sample.cpp b/code/tests/cases/test_sample.cpp index 3897dabc..8be91a48 100644 --- a/code/tests/cases/test_sample.cpp +++ b/code/tests/cases/test_sample.cpp @@ -74,11 +74,46 @@ FOSSIL_TEST_CASE(cpp_test_should_not_run) { FOSSIL_TEST_ASSUME(1 == 0, "This test should not run"); } +// A simple test case to check if input % 2 equals expected_output +FOSSIL_TEST_CASE(cpp_test_input_modulo) { + CppSampleTestData data = { 5, 1 }; + + int actual_output = data.input % 2; + + FOSSIL_TEST_ASSUME(actual_output == data.expected_output, "Modulo test failed"); +} + +// A simple test case to check if input squared equals expected_output +FOSSIL_TEST_CASE(cpp_test_input_square) { + CppSampleTestData data = { 3, 9 }; + + int actual_output = data.input * data.input; + + FOSSIL_TEST_ASSUME(actual_output == data.expected_output, "Square test failed"); +} + +// A simple test case to check if input is equal to expected_output +FOSSIL_TEST_CASE(cpp_test_input_equal) { + CppSampleTestData data = { 7, 7 }; + + int actual_output = data.input; + + FOSSIL_TEST_ASSUME(actual_output == data.expected_output, "Equality test failed"); +} + +FOSSIL_TEST_CASE(cpp_test_has_no_assertions) { + // This test has no assertions +} + FOSSIL_TEST_GROUP(cpp_sample_test_cases) { FOSSIL_TEST_ADD(cpp_sample_suite, cpp_test_input_increment); FOSSIL_TEST_ADD(cpp_sample_suite, cpp_test_input_decrement); FOSSIL_TEST_ADD(cpp_sample_suite, cpp_test_input_double); FOSSIL_TEST_ADD(cpp_sample_suite, cpp_test_input_half); + FOSSIL_TEST_ADD(cpp_sample_suite, cpp_test_input_modulo); + FOSSIL_TEST_ADD(cpp_sample_suite, cpp_test_input_square); + FOSSIL_TEST_ADD(cpp_sample_suite, cpp_test_input_equal); + FOSSIL_TEST_ADD(cpp_sample_suite, cpp_test_has_no_assertions); // Should be detected as empty FOSSIL_TEST_SKIP(cpp_test_should_not_run, "This test should not run"); diff --git a/code/tests/meson.build b/code/tests/meson.build index 41da644b..2cea5d91 100644 --- a/code/tests/meson.build +++ b/code/tests/meson.build @@ -2,7 +2,7 @@ if get_option('with_test').enabled() run_command(['python3', 'tools' / 'generate-runner.py'], check: true) test_c = ['unit_runner.c'] - test_cases = ['sample', 'bdd', 'tdd', 'ddd', 'mark'] + test_cases = ['sample', 'bdd', 'tdd', 'ddd', 'mark', 'mock'] foreach cases : test_cases test_c += ['cases' / 'test_' + cases + '.c']