Skip to content

Commit 28c74d1

Browse files
Merge pull request #19 from dreamer-coding/enhance_scanning
Enhance scanning and introspection for assertion info
2 parents 7ef43eb + 8469095 commit 28c74d1

File tree

5 files changed

+101
-10
lines changed

5 files changed

+101
-10
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# ***Fossil Test: Unit Testing/Mocking Framework*** - `C/C++`
1+
# ***Fossil Test: Unit Testing/Mocking Framework*** - `C, C++`
22

33
**Overview:**
44
Fossil Test is a robust unit testing and mocking framework developed by Fossil Logic, designed to facilitate the creation of high-quality test cases across any C or C++ project. The framework supports both Behavior-Driven Development (BDD) and Test-Driven Development (TDD) styles, providing a flexible and comprehensive solution for ensuring software reliability and correctness.
@@ -40,7 +40,7 @@ Before getting started, make sure you have the following installed:
4040
# ======================
4141
[wrap-git]
4242
url = https://github.com/fossillogic/fossil-test.git
43-
revision = v1.0.1
43+
revision = v1.0.2
4444

4545
[provide]
4646
fossil-test = fossil_test_dep

code/include/fossil/unittest/internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,8 @@ typedef struct {
224224
bool shoudl_timeout; /**< Flag indicating whether the test case should timeout (1 for true, 0 for false). */
225225
bool should_fail; /**< Flag indicating whether the test case should fail (1 for true, 0 for false). */
226226
bool has_assert; /**< Flag indicating if an assertion occurred (1 for true, 0 for false). */
227+
bool same_assert; /**< Flag indicating if the test case is the same (1 for true, 0 for false). */
228+
int32_t num_asserts; /**< Number of assertions that occurred. */
227229
int32_t line; /**< Line number where the assertion occurred. */
228230
char *func; /**< Function name where the assertion occurred. */
229231
char *file; /**< File name where the assertion occurred. */

code/source/unittest/console.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ Organization: Fossil Logic
1717

1818
static const char* FOSSIL_TEST_NAME = "Fossil Test";
1919
static const char* FOSSIL_TEST_AUTH = "Michael Gene Brockus (Dreamer)";
20-
static const char* FOSSIL_TEST_VERSION = "1.0.1";
20+
static const char* FOSSIL_TEST_VERSION = "1.0.2";
2121
static const char* FOSSIL_TEST_INFO = "Fossil Test is a next-generation unit testing/mockup framework for C/C++.";
2222

2323
// ==============================================================================
@@ -402,11 +402,17 @@ void fossil_test_io_unittest_then(char *description) {
402402

403403
void fossil_test_io_unittest_step(xassert_info *assume) {
404404
if (_CLI.verbose_level == 2) {
405-
fossil_test_cout("blue", "has assert: ");
405+
fossil_test_cout("blue", "has assert : ");
406406
fossil_test_cout("cyan", " -> %s\n", assume->has_assert ? COLOR_GREEN "has assertions" COLOR_RESET : COLOR_RED "missing assertions" COLOR_RESET);
407+
fossil_test_cout("blue", "asserts used: ");
408+
fossil_test_cout("cyan", COLOR_GREEN "%3i\n" COLOR_RESET , assume->num_asserts);
407409
} else if (_CLI.verbose_level == 1) {
408-
fossil_test_cout("blue", "[intro] has_assert: ");
410+
fossil_test_cout("blue", "[intro] has_assert : ");
409411
fossil_test_cout("cyan", "%s\n", assume->has_assert ? COLOR_GREEN "yes" COLOR_RESET : COLOR_RED "no" COLOR_RESET);
412+
fossil_test_cout("blue", "[intro] same_assert: ");
413+
fossil_test_cout("cyan", "%s\n", assume->same_assert ? COLOR_RED "yes" COLOR_RESET : COLOR_GREEN "no" COLOR_RESET);
414+
fossil_test_cout("blue", "[intro] num_asserts: ");
415+
fossil_test_cout("cyan", COLOR_GREEN "%3i\n" COLOR_RESET , assume->num_asserts);
410416
}
411417
}
412418

code/source/unittest/unittest.c

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,21 @@ Organization: Fossil Logic
1616
#include "fossil/unittest/commands.h"
1717
#include <stdarg.h>
1818

19+
#define MAX_ASSERT_HISTORY 100
20+
21+
typedef struct {
22+
bool expression;
23+
xassert_type_t behavior;
24+
char* message;
25+
char* file;
26+
int line;
27+
unsigned long fingerprint;
28+
char* func;
29+
} assert_history_t;
30+
31+
static assert_history_t assert_history[MAX_ASSERT_HISTORY];
32+
static int assert_history_count = 0;
33+
1934
fossil_env_t _TEST_ENV;
2035
xassert_info _ASSERT_INFO;
2136

@@ -391,6 +406,8 @@ void fossil_test_run_testcase(fossil_test_t *test) {
391406
_ASSERT_INFO.has_assert = false;
392407
_ASSERT_INFO.should_fail = false;
393408
_ASSERT_INFO.shoudl_timeout = false;
409+
_ASSERT_INFO.num_asserts = 0;
410+
_ASSERT_INFO.same_assert = false;
394411

395412
if (_TEST_ENV.rule.skipped && strcmp(test->marks, "skip") == 0) {
396413
return;
@@ -707,18 +724,84 @@ void fossil_test_assert_impl_expect(bool expression, xassert_info *assume) {
707724
}
708725
} // end of func
709726

710-
void _fossil_test_assert_class(bool expression, xassert_type_t behavor, char* message, char* file, int line, char* func) {
727+
bool is_assert_in_history(bool expression, xassert_type_t behavior, char* message, char* file, int line, char* func) {
728+
for (int i = 0; i < assert_history_count; i++) {
729+
if (assert_history[i].expression == expression &&
730+
assert_history[i].behavior == behavior &&
731+
strcmp(assert_history[i].message, message) == 0 &&
732+
strcmp(assert_history[i].file, file) == 0 &&
733+
assert_history[i].line == line &&
734+
strcmp(assert_history[i].func, func) == 0) {
735+
return true;
736+
}
737+
}
738+
return false;
739+
}
740+
741+
unsigned long generate_fingerprint(bool expression, xassert_type_t behavior, char* message, char* file, int line, char* func) {
742+
unsigned long hash = 5381;
743+
int c;
744+
745+
hash = ((hash << 5) + hash) + expression;
746+
hash = ((hash << 5) + hash) + behavior;
747+
748+
while ((c = *message++))
749+
hash = ((hash << 5) + hash) + c;
750+
751+
while ((c = *file++))
752+
hash = ((hash << 5) + hash) + c;
753+
754+
hash = ((hash << 5) + hash) + line;
755+
756+
while ((c = *func++))
757+
hash = ((hash << 5) + hash) + c;
758+
759+
return hash;
760+
}
761+
762+
bool is_assert_similar_in_history(unsigned long fingerprint) {
763+
for (int i = 0; i < assert_history_count; i++) {
764+
if (assert_history[i].fingerprint == fingerprint) {
765+
return true;
766+
}
767+
}
768+
return false;
769+
}
770+
771+
void _fossil_test_assert_class(bool expression, xassert_type_t behavior, char* message, char* file, int line, char* func) {
772+
unsigned long fingerprint = generate_fingerprint(expression, behavior, message, file, line, func);
773+
774+
if (is_assert_similar_in_history(fingerprint)) {
775+
// Skip the assertion as a similar one has already been executed
776+
_ASSERT_INFO.same_assert = true;
777+
return;
778+
}
779+
711780
_ASSERT_INFO.func = func;
712781
_ASSERT_INFO.file = file;
713782
_ASSERT_INFO.line = line;
714783
_ASSERT_INFO.message = message;
715784

716-
if (behavor == TEST_ASSERT_AS_CLASS_ASSUME) {
785+
if (behavior == TEST_ASSERT_AS_CLASS_ASSUME) {
717786
fossil_test_assert_impl_assume(expression, &_ASSERT_INFO);
718-
} else if (behavor == TEST_ASSERT_AS_CLASS_ASSERT) {
787+
} else if (behavior == TEST_ASSERT_AS_CLASS_ASSERT) {
719788
fossil_test_assert_impl_assert(expression, &_ASSERT_INFO);
720-
} else if (behavor == TEST_ASSERT_AS_CLASS_EXPECT) {
789+
} else if (behavior == TEST_ASSERT_AS_CLASS_EXPECT) {
721790
fossil_test_assert_impl_expect(expression, &_ASSERT_INFO);
722791
}
792+
793+
_ASSERT_INFO.num_asserts++; // increment the number of asserts
723794
_ASSERT_INFO.has_assert = true; // Make note of an assert being added in a given test case
795+
796+
// Add the assertion to the history with its fingerprint
797+
if (assert_history_count < MAX_ASSERT_HISTORY) {
798+
assert_history[assert_history_count].expression = expression;
799+
assert_history[assert_history_count].behavior = behavior;
800+
assert_history[assert_history_count].message = message;
801+
assert_history[assert_history_count].file = file;
802+
assert_history[assert_history_count].line = line;
803+
assert_history[assert_history_count].func = func;
804+
assert_history[assert_history_count].fingerprint = fingerprint;
805+
assert_history_count++;
806+
}
724807
}

meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
project('Fossil Test', 'c', 'cpp',
22
meson_version: '>=1.2.0',
33
license: 'MPL-2.0',
4-
version: '1.0.1',
4+
version: '1.0.2',
55
default_options: ['c_std=c18', 'cpp_std=c++20'])
66

77
subdir('code')

0 commit comments

Comments
 (0)