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
106 changes: 80 additions & 26 deletions 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.4
revision = v1.1.5

[provide]
fossil-test = fossil_test_dep
Expand All @@ -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=<number>` | 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=<number>` | 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=<number>
```

---

Expand Down
41 changes: 22 additions & 19 deletions code/logic/fossil/test/testing.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -85,6 +87,7 @@ typedef struct {
bool repeat_enabled;
int repeat_count;
bool shuffle_enabled;
bool dry_run;
} fossil_options_t;

/**
Expand Down
91 changes: 71 additions & 20 deletions code/logic/testing.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
Expand All @@ -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++;
}
}
}
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand All @@ -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);
}
Expand All @@ -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;
}
}

Expand All @@ -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) {
Expand All @@ -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();
Expand All @@ -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
Expand All @@ -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;
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.4',
version: '1.1.5',
default_options: ['c_std=c11,c18', 'cpp_std=c++20'])

subdir('code')
Loading