Skip to content

Commit 0de70da

Browse files
Merge pull request #132 from dreamer-coding/main
2 parents 88c7834 + 5915781 commit 0de70da

File tree

8 files changed

+788
-167
lines changed

8 files changed

+788
-167
lines changed

README.md

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,26 @@
11
# ***Pizza Test by Fossil Logic***
22

3-
**Pizza Test** is a comprehensive suite for unit testing, mocking, and benchmarking, designed by Pizza Logic to enhance the reliability, clarity, and performance of **C** and **C++** projects. Supporting methodologies like Behavior-Driven Development (BDD), Domain-Driven Design (DDD), and Test-Driven Development (TDD), it caters to diverse workflows with features such as a robust Command-Line Interface (CLI), advanced mocking tools, integrated benchmarking, and parallel test execution. With additional capabilities like customizable output themes, tag-based test filtering, and detailed performance insights, **Pizza Test**, alongside **Pizza Mock**, **Pizza Mark**, and **Pizza Sanity Kit** for testing command-line operations, forms a powerful toolkit for building, testing, and optimizing high-quality, maintainable software.
4-
5-
| Feature | Description |
6-
|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|
7-
| **Command-Line Interface (CLI)** | A robust CLI for executing tests, managing test suites, and generating reports, enabling seamless automation and integration workflows. |
8-
| **Support for Multiple Testing Styles** | Fully compatible with Behavior-Driven Development (BDD), Domain-Driven Design (DDD), and Test-Driven Development (TDD) methodologies. |
9-
| **Mocking Capabilities** | Advanced mocking tools to simulate complex dependencies, ensuring isolated and precise unit testing. |
10-
| **Benchmarking Tools** | Integrated benchmarking features to measure execution time, identify bottlenecks, and optimize code performance. |
11-
| **Sanity Kit for Command Tests** | A specialized suite for validating command-line tools and scripts, ensuring consistent behavior across environments. |
12-
| **Customizable Output Themes** | Multiple output themes (e.g., pizza, catch, doctest) to tailor the appearance of test results. |
13-
| **Tag-Based Test Filtering** | Organize and execute tests based on custom tags for better test management. |
14-
| **Detailed Performance Insights** | Comprehensive reporting on test execution times and resource usage to aid in performance optimization. |
3+
Pizza Test is a smart unit testing framework developed by Fossil Logic for C and C++ projects, offering advanced features aimed at systems that demand high traceability, behavioral insight, and truth validation. It is especially well-suited for testing components within the Truthful Intelligence (TI) and Jellyfish AI ecosystems, where deterministic logic, memory integrity, and reasoning transparency are critical.
4+
5+
---
6+
7+
## 🔑 Key Features
8+
9+
| Feature | Description |
10+
|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|
11+
| **Command-Line Interface (CLI)** | A robust CLI for executing tests, managing test suites, and generating reports, enabling seamless automation and CI/CD workflows. |
12+
| **Truthful Intelligence Auditing** | Each test case carries timestamped, hashed metadata for traceability and reproducibility via Jellyfish AI's cryptographic core. |
13+
| **Support for Multiple Testing Styles** | Compatible with Behavior-Driven Development (BDD), Domain-Driven Design (DDD), and Test-Driven Development (TDD) methodologies. |
14+
| **Mocking Capabilities** | Advanced mocking tools to simulate complex dependencies and edge conditions, enabling isolated and deterministic testing. |
15+
| **Benchmarking Tools** | Integrated benchmarking features to measure runtime performance, identify slow paths, and guide optimization. |
16+
| **Sanity Kit for Command Tests** | A specialized module for validating command-line tools, ensuring consistent behavior across platforms and shell environments. |
17+
| **Customizable Output Themes** | Multiple output formats and visual themes (e.g., pizza, catch, doctest) to match your preferred style of feedback. |
18+
| **Tag-Based Test Filtering** | Execute subsets of tests based on custom tags for better test suite organization and faster iteration. |
19+
| **Detailed Performance Insights** | In-depth statistics on execution time, memory usage, and test stability to help improve code performance and reliability. |
20+
21+
---
22+
23+
Pizza Test is a first-class citizen of the **Truthful Intelligence** ecosystem, using **Jellyfish AI** as its foundation for test integrity, learning from outcomes over time, and enabling tamper-proof validation across distributed development environments.
1524

1625
---
1726

@@ -43,7 +52,7 @@ To get started with Pizza Test, ensure you have the following installed:
4352
# ======================
4453
[wrap-git]
4554
url = https://github.com/fossillogic/fossil-test.git
46-
revision = v1.2.5
55+
revision = v1.2.6
4756

4857
[provide]
4958
fossil-test = fossil_test_dep

code/logic/common.c

Lines changed: 205 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
// macro definitions
2020
// *****************************************************************************
2121

22-
#define FOSSIL_PIZZA_VERSION "1.2.5"
22+
#define FOSSIL_PIZZA_VERSION "1.2.6"
2323
#define FOSSIL_PIZZA_AUTHOR "Fossil Logic"
2424
#define FOSSIL_PIZZA_WEBSITE "https://fossillogic.com"
2525

@@ -36,6 +36,114 @@ int G_PIZZA_REPEAT = 0;
3636
int G_PIZZA_THREADS = 1;
3737
fossil_pizza_cli_theme_t G_PIZZA_THEME = PIZZA_THEME_FOSSIL;
3838

39+
// *****************************************************************************
40+
// Hashing algorithm
41+
// *****************************************************************************
42+
43+
// HASH Algorithm magic
44+
45+
#if defined(_WIN32) || defined(_WIN64)
46+
#include <windows.h>
47+
uint64_t get_pizza_time_microseconds(void) {
48+
FILETIME ft;
49+
GetSystemTimeAsFileTime(&ft);
50+
uint64_t t = ((uint64_t)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
51+
return t / 10; // 100-nanosecond intervals to microseconds
52+
}
53+
#else
54+
#include <sys/time.h>
55+
uint64_t get_pizza_time_microseconds(void) {
56+
struct timeval tv;
57+
gettimeofday(&tv, NULL);
58+
return (uint64_t)tv.tv_sec * 1000000ULL + tv.tv_usec;
59+
}
60+
#endif
61+
62+
static uint64_t get_pizza_device_salt(void) {
63+
// FNV-1a 64-bit base offset
64+
uint64_t hash = 0xcbf29ce484222325ULL;
65+
66+
// Cross-platform user and home detection
67+
#if defined(_WIN32) || defined(_WIN64)
68+
const char *vars[] = {
69+
getenv("USERNAME"),
70+
getenv("USERPROFILE"),
71+
getenv("COMPUTERNAME")
72+
};
73+
#else
74+
const char *vars[] = {
75+
getenv("USER"),
76+
getenv("HOME"),
77+
getenv("SHELL"),
78+
getenv("HOSTNAME")
79+
};
80+
#endif
81+
82+
// Mix in each variable if it exists
83+
for (size_t v = 0; v < sizeof(vars) / sizeof(vars[0]); ++v) {
84+
const char *val = vars[v];
85+
if (val) {
86+
for (size_t i = 0; val[i]; ++i) {
87+
hash ^= (uint8_t)val[i];
88+
hash *= 0x100000001b3ULL;
89+
}
90+
}
91+
}
92+
93+
return hash;
94+
}
95+
96+
void fossil_pizza_hash(const char *input, const char *output, uint8_t *hash_out) {
97+
const uint64_t PRIME = 0x100000001b3ULL;
98+
static uint64_t SALT = 0;
99+
if (SALT == 0) SALT = get_pizza_device_salt(); // Initialize salt once
100+
101+
uint64_t state1 = 0xcbf29ce484222325ULL ^ SALT;
102+
uint64_t state2 = 0x84222325cbf29ce4ULL ^ ~SALT;
103+
104+
size_t in_len = strlen(input);
105+
size_t out_len = strlen(output);
106+
107+
uint64_t nonce = get_pizza_time_microseconds(); // Microsecond resolution
108+
109+
for (size_t i = 0; i < in_len; ++i) {
110+
state1 ^= (uint8_t)input[i];
111+
state1 *= PRIME;
112+
state1 ^= (state1 >> 27);
113+
state1 ^= (state1 << 33);
114+
}
115+
116+
for (size_t i = 0; i < out_len; ++i) {
117+
state2 ^= (uint8_t)output[i];
118+
state2 *= PRIME;
119+
state2 ^= (state2 >> 29);
120+
state2 ^= (state2 << 31);
121+
}
122+
123+
// Nonce and length entropy
124+
state1 ^= nonce ^ ((uint64_t)in_len << 32);
125+
state2 ^= ~nonce ^ ((uint64_t)out_len << 16);
126+
127+
// Mixing rounds
128+
for (int i = 0; i < 6; ++i) {
129+
state1 += (state2 ^ (state1 >> 17));
130+
state2 += (state1 ^ (state2 >> 13));
131+
state1 ^= (state1 << 41);
132+
state2 ^= (state2 << 37);
133+
state1 *= PRIME;
134+
state2 *= PRIME;
135+
}
136+
137+
for (size_t i = 0; i < FOSSIL_PIZZA_HASH_SIZE; ++i) {
138+
uint64_t mixed = (i % 2 == 0) ? state1 : state2;
139+
mixed ^= (mixed >> ((i % 7) + 13));
140+
mixed *= PRIME;
141+
mixed ^= SALT;
142+
hash_out[i] = (uint8_t)((mixed >> (8 * (i % 8))) & 0xFF);
143+
}
144+
}
145+
146+
39147
// *****************************************************************************
40148
// command pallet
41149
// *****************************************************************************
@@ -80,10 +188,6 @@ static void _show_help(void) {
80188
exit(EXIT_SUCCESS);
81189
}
82190

83-
// TODO support wildcards for test cases under --only
84-
// TODO support regex for test cases under --only
85-
// TODO support listing multiple test cases under --only
86-
87191
static void _show_subhelp_run(void) {
88192
pizza_io_printf("{blue}Run command options:{reset}\n");
89193
pizza_io_printf("{cyan} --fail-fast Stop on the first failure{reset}\n");
@@ -94,15 +198,6 @@ static void _show_subhelp_run(void) {
94198
exit(EXIT_SUCCESS);
95199
}
96200

97-
// TODO support wildcards for test cases under --test-name
98-
// TODO support regex for test cases under --test-name
99-
// TODO support listing multiple test cases under --test-name
100-
// TODO support wildcards for suite names under --suite-name
101-
// TODO support regex for suite names under --suite-name
102-
// TODO support listing multiple suite names under --suite-name
103-
// TODO support regex for tags under --tag
104-
// TODO support listing multiple tags under --tag
105-
106201
static void _show_subhelp_filter(void) {
107202
pizza_io_printf("{blue}Filter command options:{reset}\n");
108203
pizza_io_printf("{cyan} --test-name <name> Filter by test name{reset}\n");
@@ -237,7 +332,21 @@ fossil_pizza_pallet_t fossil_pizza_pallet_create(int argc, char** argv) {
237332
pallet.run.fail_fast = 1;
238333
G_PIZZA_FAIL_FAST = 1;
239334
} else if (pizza_io_cstr_compare(argv[j], "--only") == 0 && j + 1 < argc) {
240-
pallet.run.only = argv[++j];
335+
// Support multiple test cases separated by comma, and wildcards
336+
j++;
337+
size_t count = 0;
338+
cstr *test_cases = pizza_io_cstr_split(argv[j], ',', &count);
339+
pallet.run.only = argv[j]; // Store raw string for now
340+
pallet.run.only_cases = test_cases;
341+
pallet.run.only_count = count;
342+
// Wildcard support: mark if any test case contains '*'
343+
pallet.run.only_has_wildcard = 0;
344+
for (size_t k = 0; k < count; k++) {
345+
if (strchr(test_cases[k], '*')) {
346+
pallet.run.only_has_wildcard = 1;
347+
break;
348+
}
349+
}
241350
} else if (pizza_io_cstr_compare(argv[j], "--skip") == 0 && j + 1 < argc) {
242351
pallet.run.skip = argv[++j];
243352
G_PIZZA_SKIP = 1;
@@ -261,22 +370,69 @@ fossil_pizza_pallet_t fossil_pizza_pallet_create(int argc, char** argv) {
261370
for (int j = i + 1; j < argc; j++) {
262371
if (!is_command) break;
263372
if (pizza_io_cstr_compare(argv[j], "--test-name") == 0 && j + 1 < argc) {
264-
pallet.filter.test_name = argv[++j];
373+
// Support multiple test names separated by comma, and wildcards
374+
j++;
375+
size_t count = 0;
376+
cstr *test_names = pizza_io_cstr_split(argv[j], ',', &count);
377+
pallet.filter.test_name = argv[j]; // Store raw string for now
378+
pallet.filter.test_name_list = test_names;
379+
pallet.filter.test_name_count = count;
380+
// Wildcard support: mark if any test name contains '*'
381+
pallet.filter.test_name_has_wildcard = 0;
382+
for (size_t k = 0; k < count; k++) {
383+
if (strchr(test_names[k], '*')) {
384+
pallet.filter.test_name_has_wildcard = 1;
385+
break;
386+
}
387+
}
265388
} else if (pizza_io_cstr_compare(argv[j], "--suite-name") == 0 && j + 1 < argc) {
266-
pallet.filter.suite_name = argv[++j];
267-
} else if (pizza_io_cstr_compare(argv[j], "--tag") == 0 && j + 1 < argc) {
268-
const char* tag = argv[++j];
269-
int is_valid_tag = 0;
270-
for (int k = 0; VALID_TAGS[k] != null; k++) {
271-
if (pizza_io_cstr_compare(tag, VALID_TAGS[k]) == 0) {
272-
is_valid_tag = 1;
389+
// Support multiple suite names separated by comma, and wildcards
390+
j++;
391+
size_t count = 0;
392+
cstr *suite_names = pizza_io_cstr_split(argv[j], ',', &count);
393+
pallet.filter.suite_name = argv[j]; // Store raw string for now
394+
pallet.filter.suite_name_list = suite_names;
395+
pallet.filter.suite_name_count = count;
396+
// Wildcard support: mark if any suite name contains '*'
397+
pallet.filter.suite_name_has_wildcard = 0;
398+
for (size_t k = 0; k < count; k++) {
399+
if (strchr(suite_names[k], '*')) {
400+
pallet.filter.suite_name_has_wildcard = 1;
273401
break;
274402
}
275403
}
276-
if (is_valid_tag) {
277-
pallet.filter.tag = tag;
404+
} else if (pizza_io_cstr_compare(argv[j], "--tag") == 0 && j + 1 < argc) {
405+
// Support multiple tags separated by comma, and wildcards
406+
j++;
407+
size_t count = 0;
408+
cstr *tags = pizza_io_cstr_split(argv[j], ',', &count);
409+
int valid_count = 0;
410+
for (size_t k = 0; k < count; k++) {
411+
int is_valid_tag = 0;
412+
for (int t = 0; VALID_TAGS[t] != null; t++) {
413+
if (pizza_io_cstr_compare(tags[k], VALID_TAGS[t]) == 0) {
414+
is_valid_tag = 1;
415+
break;
416+
}
417+
}
418+
if (is_valid_tag || strchr(tags[k], '*')) {
419+
valid_count++;
420+
}
421+
}
422+
if (valid_count == (int)count) {
423+
pallet.filter.tag = argv[j]; // Store raw string for now
424+
pallet.filter.tag_list = tags;
425+
pallet.filter.tag_count = count;
426+
// Wildcard support: mark if any tag contains '*'
427+
pallet.filter.tag_has_wildcard = 0;
428+
for (size_t k = 0; k < count; k++) {
429+
if (strchr(tags[k], '*')) {
430+
pallet.filter.tag_has_wildcard = 1;
431+
break;
432+
}
433+
}
278434
} else {
279-
pizza_io_printf("{red}Error: Invalid tag '%s'.{reset}\n", tag);
435+
pizza_io_printf("{red}Error: Invalid tag(s) in '%s'.{reset}\n", argv[j]);
280436
exit(EXIT_FAILURE);
281437
}
282438
} else if (pizza_io_cstr_compare(argv[j], "--help") == 0) {
@@ -1210,7 +1366,6 @@ pizza_sys_memory_t pizza_sys_memory_init(pizza_sys_memory_t ptr, size_t size, in
12101366

12111367
void pizza_sys_memory_free(pizza_sys_memory_t ptr) {
12121368
if (!ptr) {
1213-
fprintf(stderr, "Error: pizza_sys_memory_free() - Pointer is null.\n");
12141369
return;
12151370
}
12161371
free(ptr); // No need for null check, free() already handles null.
@@ -1971,3 +2126,26 @@ cstr pizza_io_cstr_pad_right(ccstr str, size_t total_length, char pad_char) {
19712126
}
19722127
return result;
19732128
}
2129+
2130+
bool pizza_io_cstr_append(cstr dest, size_t max_len, cstr src) {
2131+
if (!dest || !src || max_len == 0) return false;
2132+
2133+
// Find current length of dest up to max_len
2134+
size_t dest_len = 0;
2135+
while (dest_len < max_len && dest[dest_len] != '\0') {
2136+
++dest_len;
2137+
}
2138+
2139+
// If no null-terminator found in range, dest is not safe
2140+
if (dest_len == max_len) return false;
2141+
2142+
size_t src_len = strlen(src);
2143+
2144+
// Make sure there's enough space (including null terminator)
2145+
if (dest_len + src_len >= max_len) return false;
2146+
2147+
memcpy(dest + dest_len, src, src_len);
2148+
dest[dest_len + src_len] = '\0';
2149+
2150+
return true;
2151+
}

0 commit comments

Comments
 (0)