diff --git a/README.md b/README.md index 6586efa6..8af7fdf5 100644 --- a/README.md +++ b/README.md @@ -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.4 + revision = v1.1.5 [provide] fossil-test = fossil_test_dep @@ -74,31 +74,85 @@ The Fossil Test CLI provides an efficient way to run and manage tests directly f ### Commands and Options -| Command | Description | -|----------------------------------|-----------------------------------------------------------------------------------------------| -| `--version` | Displays the current version of Fossil Test. | -| `--help` | Shows help message with usage instructions. | -| `--info` | Displays detailed information about the test run. | -| `reverse [enable/disable]` | Enables or disables reverse order of test execution. | -| `repeat=` | Repeats the test suite a specified number of times. | -| `shuffle [enable/disable]` | Enables or disables shuffling of test execution order. | - -### Example Usage - -- Display the version: - ```sh - fossil_cli --version - ``` - -- Enable reverse order of test execution: - ```sh - fossil_cli reverse enable - ``` - -- Repeat the test suite 5 times: - ```sh - fossil_cli repeat=5 - ``` +| Command | Description | Notes | +|----------------------------------|-----------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------| +| `--version` | Displays the current version of Fossil Test. | Useful for verifying the version of the tool in use. | +| `--help` | Shows help message with usage instructions. | Provides a quick reference for all available commands. | +| `--info` | Displays detailed information about the test run. | Includes information such as test count, duration, and configuration. | +| `reverse [enable/disable]` | Enables or disables reverse order of test execution. | Useful for debugging or ensuring the tests don't depend on execution order. | +| `shuffle [enable/disable]` | Enables or disables shuffling of test execution order. | Helps identify order-dependent issues in the test suite. | +| `dry-run [enable/disable]` | Enables or disables dry run mode, showing which tests will execute without running them. | Ideal for verifying test selection criteria before actual execution. | +| `repeat=` | Repeats the test suite a specified number of times. | Handy for stress-testing or reproducing intermittent failures. | + +### Key Notes Summary: +- **Version**: Quickly check the installed version of Fossil Test. +- **Help**: Access usage instructions and command references. +- **Info**: Get detailed insights about the test run, including test count and duration. +- **Reverse and Shuffle**: Help debug issues by manipulating test execution order. +- **Repeat**: Ideal for reliability testing by repeatedly executing tests. +- **Dry Run**: Provides a preview of the test plan without running the tests, useful for preparation and validation. + +### Usage + +To use the Fossil Test CLI, navigate to your project directory and run the desired command. For example, to check the version of Fossil Test, use: + +```sh +fossil-test --version +``` + +To display help information, use: + +```sh +fossil-test --help +``` + +For detailed information about the test run, use: + +```sh +fossil-test --info +``` + +To enable reverse order of test execution, use: + +```sh +fossil-test reverse enable +``` + +To disable reverse order of test execution, use: + +```sh +fossil-test reverse disable +``` + +To enable shuffling of test execution order, use: + +```sh +fossil-test shuffle enable +``` + +To disable shuffling of test execution order, use: + +```sh +fossil-test shuffle disable +``` + +To perform a dry run, use: + +```sh +fossil-test dry-run enable +``` + +To disable dry run mode, use: + +```sh +fossil-test dry-run disable +``` + +To repeat the test suite a specified number of times, use: + +```sh +fossil-test repeat= +``` --- diff --git a/code/logic/fossil/test/testing.h b/code/logic/fossil/test/testing.h index bd2c5a2e..52dad6f9 100644 --- a/code/logic/fossil/test/testing.h +++ b/code/logic/fossil/test/testing.h @@ -49,33 +49,35 @@ extern "C" { #endif /** - * @struct fossil_options - * @brief Structure to hold the configuration options for the test environment. + * @struct fossil_options_t + * @brief Structure to hold various options for fossil testing. * - * This structure contains various fields to manage the configuration options for - * the test environment, including flags to show version and help information, as - * well as options to reverse the order of tests, repeat tests, and shuffle tests. + * This structure contains various flags and parameters that control the behavior of the fossil testing framework. * - * @var fossil_options::show_version - * Flag to show version information. + * @var fossil_options_t::show_version + * Flag to indicate if the version information should be displayed. * - * @var fossil_options::show_help - * Flag to show help information. + * @var fossil_options_t::show_help + * Flag to indicate if the help information should be displayed. * - * @var fossil_options::show_info - * Flag to show additional information. + * @var fossil_options_t::show_info + * Flag to indicate if additional information should be displayed. * - * @var fossil_options::reverse - * Flag to reverse the order of tests. + * @var fossil_options_t::reverse + * Flag to indicate if the order of tests should be reversed. * - * @var fossil_options::repeat_enabled - * Flag to enable repeating tests. + * @var fossil_options_t::repeat_enabled + * Flag to indicate if test repetition is enabled. * - * @var fossil_options::repeat_count - * Number of times to repeat tests. + * @var fossil_options_t::repeat_count + * Number of times to repeat the tests if repetition is enabled. + * + * @var fossil_options_t::shuffle_enabled + * Flag to indicate if the tests should be shuffled. + * + * @var fossil_options_t::dry_run + * Flag to indicate if the tests should be run in dry-run mode (no actual execution). * - * @var fossil_options::shuffle_enabled - * Flag to enable shuffling of tests. */ typedef struct { bool show_version; @@ -85,6 +87,7 @@ typedef struct { bool repeat_enabled; int repeat_count; bool shuffle_enabled; + bool dry_run; } fossil_options_t; /** diff --git a/code/logic/testing.c b/code/logic/testing.c index cde5688f..609b9e55 100644 --- a/code/logic/testing.c +++ b/code/logic/testing.c @@ -282,13 +282,14 @@ const char *timeout_messages[] = { static const char *FOSSIL_TEST_OPTIONS[] = { "--version - Displays the current version of Fossil Test\n", "--help - Shows help message with usage\n", - "--info - Displays detailed information about the test run\n", + "--info - Displays detailed information about the test run\n" }; static const char *FOSSIL_TEST_COMMANDS[] = { "reverse [enable|disable] - Enables or disables reverse order of test execution\n", "repeat [count] - Repeats the test suite a specified number of times\n", "shuffle [enable|disable] - Enables or disables shuffling of test execution order\n", + "dry-run [enable|disable] - Enables or disables dry-run mode\n" }; static const char *FOSSIL_TEST_VERSION = "1.1.4"; // Version of Fossil Test @@ -320,6 +321,7 @@ fossil_options_t init_options(void) { options.repeat_enabled = false; options.repeat_count = 1; options.shuffle_enabled = false; + options.dry_run = false; return options; } @@ -359,8 +361,10 @@ fossil_options_t fossil_options_parse(int argc, char **argv) { } else if (strcmp(argv[i], "reverse") == 0) { if (i + 1 < argc && strcmp(argv[i + 1], "enable") == 0) { options.reverse = true; + i++; } else if (i + 1 < argc && strcmp(argv[i + 1], "disable") == 0) { options.reverse = false; + i++; } } else if (strcmp(argv[i], "repeat") == 0) { options.repeat_enabled = true; @@ -371,8 +375,18 @@ fossil_options_t fossil_options_parse(int argc, char **argv) { } else if (strcmp(argv[i], "shuffle") == 0) { if (i + 1 < argc && strcmp(argv[i + 1], "enable") == 0) { options.shuffle_enabled = true; + i++; } else if (i + 1 < argc && strcmp(argv[i + 1], "disable") == 0) { options.shuffle_enabled = false; + i++; + } + } else if (strcmp(argv[i], "dry-run") == 0) { + if (i + 1 < argc && strcmp(argv[i + 1], "enable") == 0) { + options.dry_run = true; + i++; + } else if (i + 1 < argc && strcmp(argv[i + 1], "disable") == 0) { + options.dry_run = false; + i++; } } } @@ -462,6 +476,10 @@ void shuffle_test_cases(test_case_t **test_cases) { // Creates and returns a new test suite test_suite_t* fossil_test_create_suite(const char *name) { + if (!name) { + return NULL; + } + test_suite_t *suite = (test_suite_t*)malloc(sizeof(test_suite_t)); if (!suite) { return NULL; @@ -610,7 +628,12 @@ void fossil_test_assert_internal(bool condition, const char *message, const char // Run an individual test case void fossil_test_run_case(test_case_t *test_case, fossil_test_env_t *env) { - if (!test_case) { + if (!test_case || !env) { + return; + } + + if (env->options.dry_run) { + puts(FOSSIL_TEST_COLOR_PURPLE "Dry run mode enabled. No tests will be executed." FOSSIL_TEST_COLOR_RESET); return; } @@ -624,23 +647,24 @@ void fossil_test_run_case(test_case_t *test_case, fossil_test_env_t *env) { _ASSERT_COUNT = 0; // Reset assertion count before running the test - if (setjmp(env->env) == 0) { + if (setjmp(env->env) == 0) { // Attempt to run the test case for (int i = 0; i < env->options.repeat_count; i++) { test_case->test_func(); - if (clock() > timeout_limit) { + if (clock() > timeout_limit) { // Timeout check test_case->status = TEST_STATUS_TTIMEOUT; printf(FOSSIL_TEST_COLOR_ORANGE "TIMEOUT: " FOSSIL_TEST_COLOR_BLUE " %s\n" FOSSIL_TEST_COLOR_RESET, test_case->name); break; } } - } else { + } else { // Handle failure test_case->status = TEST_STATUS_FAIL; 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 + // Warn if the test case contains no assertions if (_ASSERT_COUNT == 0) { printf(FOSSIL_TEST_COLOR_YELLOW "WARNING: %s contains no assertions\n" FOSSIL_TEST_COLOR_RESET, test_case->name); } @@ -649,20 +673,24 @@ void fossil_test_run_case(test_case_t *test_case, fossil_test_env_t *env) { fossil_test_case_teardown(test_case); // Log result - if (test_case->status == TEST_STATUS_PASS) { - if (env->options.show_info) { - 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++; - } 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++; + switch (test_case->status) { + case TEST_STATUS_PASS: + if (env->options.show_info) { + 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); + } + break; + case TEST_STATUS_FAIL: + env->fail_count++; + break; + case TEST_STATUS_SKIP: + env->skip_count++; + break; + case TEST_STATUS_TTIMEOUT: + env->timeout_count++; + break; + default: + env->unexpected_count++; + break; } } @@ -671,6 +699,11 @@ void fossil_test_run_all(fossil_test_env_t *env) { return; } + if (env->options.dry_run) { + puts(FOSSIL_TEST_COLOR_PURPLE "Dry run mode enabled. No tests will be executed." FOSSIL_TEST_COLOR_RESET); + return; + } + test_suite_t *current_suite = env->test_suites; while (current_suite) { @@ -680,6 +713,10 @@ void fossil_test_run_all(fossil_test_env_t *env) { } void fossil_test_init(fossil_test_env_t *env, int argc, char **argv) { + if (!env) { + return; + } + env->options = fossil_options_parse(argc, argv); if (env->options.show_version) { version_info(); @@ -701,6 +738,11 @@ void fossil_test_init(fossil_test_env_t *env, int argc, char **argv) { env->end_execution_time = 0.0; env->unexpected_count = 0; env->test_suites = NULL; + + if (env->options.dry_run) { + puts(FOSSIL_TEST_COLOR_PURPLE "Dry run mode enabled. No tests will be executed or evaluated." FOSSIL_TEST_COLOR_RESET); + return; + } } // Function to generate a dynamic message based on the test results @@ -723,6 +765,15 @@ void fossil_test_message(fossil_test_env_t *env) { // Summary function for test results void fossil_test_summary(fossil_test_env_t *env) { + if (!env) { + return; + } + + if (env->options.dry_run) { + puts(FOSSIL_TEST_COLOR_PURPLE "Dry run mode enabled. No tests were executed or evaluated." FOSSIL_TEST_COLOR_RESET); + return; + } + test_suite_t *suite = env->test_suites; while (suite != NULL) { test_case_t *test = suite->tests; diff --git a/meson.build b/meson.build index 558119e2..ee68b76f 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project('Fossil Test', 'c', 'cpp', meson_version: '>=1.3.0', license: 'MPL-2.0', - version: '1.1.4', + version: '1.1.5', default_options: ['c_std=c11,c18', 'cpp_std=c++20']) subdir('code')