Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
9d1c11f
adding hash
dreamer-coding Jul 29, 2025
9b2848c
updating assume
dreamer-coding Jul 29, 2025
af827a9
small fixes
dreamer-coding Jul 29, 2025
bc2f488
work on timestamps
dreamer-coding Jul 29, 2025
08cfe1c
apply fix for run test
dreamer-coding Jul 29, 2025
e00f72a
casting as size_t
dreamer-coding Jul 29, 2025
b28bf29
update command pallet
dreamer-coding Jul 29, 2025
d040df3
this time
dreamer-coding Jul 29, 2025
3bd54c6
cast to size_t
dreamer-coding Jul 29, 2025
12475a3
resolve format with time
dreamer-coding Jul 29, 2025
85e8b4f
ensure the format is casted for cross-build sake
dreamer-coding Jul 29, 2025
5a48cf8
update case
dreamer-coding Jul 29, 2025
04e1468
mute
dreamer-coding Jul 29, 2025
2530a17
remove volatile
dreamer-coding Jul 29, 2025
70ca9b1
version number update
dreamer-coding Jul 29, 2025
667acf7
using the unused macro
dreamer-coding Jul 29, 2025
4011adc
fix typo
dreamer-coding Jul 29, 2025
2049865
add a todo
dreamer-coding Jul 29, 2025
bade022
Update test.h
dreamer-coding Jul 29, 2025
8a01c04
Update test.c
dreamer-coding Jul 29, 2025
01b9b29
Update common.h
dreamer-coding Jul 29, 2025
07efb02
Update common.c
dreamer-coding Jul 29, 2025
45a9c86
Update test.c
dreamer-coding Jul 29, 2025
09eb9d8
Update test.c
dreamer-coding Jul 29, 2025
d298648
Update common.h
dreamer-coding Jul 29, 2025
cb87a5e
Update common.c
dreamer-coding Jul 29, 2025
1999a9a
resolving output hash param
dreamer-coding Jul 29, 2025
6307807
Update test.c
dreamer-coding Jul 29, 2025
28572a5
Update common.c
dreamer-coding Jul 29, 2025
436af95
Update common.c
dreamer-coding Jul 29, 2025
a6b9dbf
Update test.c
dreamer-coding Jul 29, 2025
d01c9e2
Update test.c
dreamer-coding Jul 29, 2025
a3897e8
Update test.c
dreamer-coding Jul 29, 2025
7949fb0
Update README.md
dreamer-coding Jul 29, 2025
18960fa
Update README.md
dreamer-coding Jul 29, 2025
383fd26
Update test.h
dreamer-coding Jul 29, 2025
8760fb3
Update test.c
dreamer-coding Jul 29, 2025
5915781
Update test.h
dreamer-coding Jul 29, 2025
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
35 changes: 22 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
# ***Pizza Test by Fossil Logic***

**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.

| Feature | Description |
|-----------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|
| **Command-Line Interface (CLI)** | A robust CLI for executing tests, managing test suites, and generating reports, enabling seamless automation and integration workflows. |
| **Support for Multiple Testing Styles** | Fully compatible with Behavior-Driven Development (BDD), Domain-Driven Design (DDD), and Test-Driven Development (TDD) methodologies. |
| **Mocking Capabilities** | Advanced mocking tools to simulate complex dependencies, ensuring isolated and precise unit testing. |
| **Benchmarking Tools** | Integrated benchmarking features to measure execution time, identify bottlenecks, and optimize code performance. |
| **Sanity Kit for Command Tests** | A specialized suite for validating command-line tools and scripts, ensuring consistent behavior across environments. |
| **Customizable Output Themes** | Multiple output themes (e.g., pizza, catch, doctest) to tailor the appearance of test results. |
| **Tag-Based Test Filtering** | Organize and execute tests based on custom tags for better test management. |
| **Detailed Performance Insights** | Comprehensive reporting on test execution times and resource usage to aid in performance optimization. |
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.

---

## 🔑 Key Features

| Feature | Description |
|------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------|
| **Command-Line Interface (CLI)** | A robust CLI for executing tests, managing test suites, and generating reports, enabling seamless automation and CI/CD workflows. |
| **Truthful Intelligence Auditing** | Each test case carries timestamped, hashed metadata for traceability and reproducibility via Jellyfish AI's cryptographic core. |
| **Support for Multiple Testing Styles** | Compatible with Behavior-Driven Development (BDD), Domain-Driven Design (DDD), and Test-Driven Development (TDD) methodologies. |
| **Mocking Capabilities** | Advanced mocking tools to simulate complex dependencies and edge conditions, enabling isolated and deterministic testing. |
| **Benchmarking Tools** | Integrated benchmarking features to measure runtime performance, identify slow paths, and guide optimization. |
| **Sanity Kit for Command Tests** | A specialized module for validating command-line tools, ensuring consistent behavior across platforms and shell environments. |
| **Customizable Output Themes** | Multiple output formats and visual themes (e.g., pizza, catch, doctest) to match your preferred style of feedback. |
| **Tag-Based Test Filtering** | Execute subsets of tests based on custom tags for better test suite organization and faster iteration. |
| **Detailed Performance Insights** | In-depth statistics on execution time, memory usage, and test stability to help improve code performance and reliability. |

---

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.

---

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

[provide]
fossil-test = fossil_test_dep
Expand Down
232 changes: 205 additions & 27 deletions code/logic/common.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
// macro definitions
// *****************************************************************************

#define FOSSIL_PIZZA_VERSION "1.2.5"
#define FOSSIL_PIZZA_VERSION "1.2.6"
#define FOSSIL_PIZZA_AUTHOR "Fossil Logic"
#define FOSSIL_PIZZA_WEBSITE "https://fossillogic.com"

Expand All @@ -36,6 +36,114 @@ int G_PIZZA_REPEAT = 0;
int G_PIZZA_THREADS = 1;
fossil_pizza_cli_theme_t G_PIZZA_THEME = PIZZA_THEME_FOSSIL;

// *****************************************************************************
// Hashing algorithm
// *****************************************************************************

// HASH Algorithm magic

#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
uint64_t get_pizza_time_microseconds(void) {
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
uint64_t t = ((uint64_t)ft.dwHighDateTime << 32) | ft.dwLowDateTime;
return t / 10; // 100-nanosecond intervals to microseconds
}
#else
#include <sys/time.h>
uint64_t get_pizza_time_microseconds(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return (uint64_t)tv.tv_sec * 1000000ULL + tv.tv_usec;
}
#endif

static uint64_t get_pizza_device_salt(void) {
// FNV-1a 64-bit base offset
uint64_t hash = 0xcbf29ce484222325ULL;

// Cross-platform user and home detection
#if defined(_WIN32) || defined(_WIN64)
const char *vars[] = {
getenv("USERNAME"),
getenv("USERPROFILE"),
getenv("COMPUTERNAME")
};
#else
const char *vars[] = {
getenv("USER"),
getenv("HOME"),
getenv("SHELL"),
getenv("HOSTNAME")
};
#endif

// Mix in each variable if it exists
for (size_t v = 0; v < sizeof(vars) / sizeof(vars[0]); ++v) {
const char *val = vars[v];
if (val) {
for (size_t i = 0; val[i]; ++i) {
hash ^= (uint8_t)val[i];
hash *= 0x100000001b3ULL;
}
}
}

return hash;
}

void fossil_pizza_hash(const char *input, const char *output, uint8_t *hash_out) {
const uint64_t PRIME = 0x100000001b3ULL;
static uint64_t SALT = 0;
if (SALT == 0) SALT = get_pizza_device_salt(); // Initialize salt once

uint64_t state1 = 0xcbf29ce484222325ULL ^ SALT;
uint64_t state2 = 0x84222325cbf29ce4ULL ^ ~SALT;

size_t in_len = strlen(input);
size_t out_len = strlen(output);

uint64_t nonce = get_pizza_time_microseconds(); // Microsecond resolution

for (size_t i = 0; i < in_len; ++i) {
state1 ^= (uint8_t)input[i];
state1 *= PRIME;
state1 ^= (state1 >> 27);
state1 ^= (state1 << 33);
}

for (size_t i = 0; i < out_len; ++i) {
state2 ^= (uint8_t)output[i];
state2 *= PRIME;
state2 ^= (state2 >> 29);
state2 ^= (state2 << 31);
}

// Nonce and length entropy
state1 ^= nonce ^ ((uint64_t)in_len << 32);
state2 ^= ~nonce ^ ((uint64_t)out_len << 16);

// Mixing rounds
for (int i = 0; i < 6; ++i) {
state1 += (state2 ^ (state1 >> 17));
state2 += (state1 ^ (state2 >> 13));
state1 ^= (state1 << 41);
state2 ^= (state2 << 37);
state1 *= PRIME;
state2 *= PRIME;
}

for (size_t i = 0; i < FOSSIL_PIZZA_HASH_SIZE; ++i) {
uint64_t mixed = (i % 2 == 0) ? state1 : state2;
mixed ^= (mixed >> ((i % 7) + 13));
mixed *= PRIME;
mixed ^= SALT;
hash_out[i] = (uint8_t)((mixed >> (8 * (i % 8))) & 0xFF);
}
}


// *****************************************************************************
// command pallet
// *****************************************************************************
Expand Down Expand Up @@ -80,10 +188,6 @@ static void _show_help(void) {
exit(EXIT_SUCCESS);
}

// TODO support wildcards for test cases under --only
// TODO support regex for test cases under --only
// TODO support listing multiple test cases under --only

static void _show_subhelp_run(void) {
pizza_io_printf("{blue}Run command options:{reset}\n");
pizza_io_printf("{cyan} --fail-fast Stop on the first failure{reset}\n");
Expand All @@ -94,15 +198,6 @@ static void _show_subhelp_run(void) {
exit(EXIT_SUCCESS);
}

// TODO support wildcards for test cases under --test-name
// TODO support regex for test cases under --test-name
// TODO support listing multiple test cases under --test-name
// TODO support wildcards for suite names under --suite-name
// TODO support regex for suite names under --suite-name
// TODO support listing multiple suite names under --suite-name
// TODO support regex for tags under --tag
// TODO support listing multiple tags under --tag

static void _show_subhelp_filter(void) {
pizza_io_printf("{blue}Filter command options:{reset}\n");
pizza_io_printf("{cyan} --test-name <name> Filter by test name{reset}\n");
Expand Down Expand Up @@ -237,7 +332,21 @@ fossil_pizza_pallet_t fossil_pizza_pallet_create(int argc, char** argv) {
pallet.run.fail_fast = 1;
G_PIZZA_FAIL_FAST = 1;
} else if (pizza_io_cstr_compare(argv[j], "--only") == 0 && j + 1 < argc) {
pallet.run.only = argv[++j];
// Support multiple test cases separated by comma, and wildcards
j++;
size_t count = 0;
cstr *test_cases = pizza_io_cstr_split(argv[j], ',', &count);
pallet.run.only = argv[j]; // Store raw string for now
pallet.run.only_cases = test_cases;
pallet.run.only_count = count;
// Wildcard support: mark if any test case contains '*'
pallet.run.only_has_wildcard = 0;
for (size_t k = 0; k < count; k++) {
if (strchr(test_cases[k], '*')) {
pallet.run.only_has_wildcard = 1;
break;
}
}
} else if (pizza_io_cstr_compare(argv[j], "--skip") == 0 && j + 1 < argc) {
pallet.run.skip = argv[++j];
G_PIZZA_SKIP = 1;
Expand All @@ -261,22 +370,69 @@ fossil_pizza_pallet_t fossil_pizza_pallet_create(int argc, char** argv) {
for (int j = i + 1; j < argc; j++) {
if (!is_command) break;
if (pizza_io_cstr_compare(argv[j], "--test-name") == 0 && j + 1 < argc) {
pallet.filter.test_name = argv[++j];
// Support multiple test names separated by comma, and wildcards
j++;
size_t count = 0;
cstr *test_names = pizza_io_cstr_split(argv[j], ',', &count);
pallet.filter.test_name = argv[j]; // Store raw string for now
pallet.filter.test_name_list = test_names;
pallet.filter.test_name_count = count;
// Wildcard support: mark if any test name contains '*'
pallet.filter.test_name_has_wildcard = 0;
for (size_t k = 0; k < count; k++) {
if (strchr(test_names[k], '*')) {
pallet.filter.test_name_has_wildcard = 1;
break;
}
}
} else if (pizza_io_cstr_compare(argv[j], "--suite-name") == 0 && j + 1 < argc) {
pallet.filter.suite_name = argv[++j];
} else if (pizza_io_cstr_compare(argv[j], "--tag") == 0 && j + 1 < argc) {
const char* tag = argv[++j];
int is_valid_tag = 0;
for (int k = 0; VALID_TAGS[k] != null; k++) {
if (pizza_io_cstr_compare(tag, VALID_TAGS[k]) == 0) {
is_valid_tag = 1;
// Support multiple suite names separated by comma, and wildcards
j++;
size_t count = 0;
cstr *suite_names = pizza_io_cstr_split(argv[j], ',', &count);
pallet.filter.suite_name = argv[j]; // Store raw string for now
pallet.filter.suite_name_list = suite_names;
pallet.filter.suite_name_count = count;
// Wildcard support: mark if any suite name contains '*'
pallet.filter.suite_name_has_wildcard = 0;
for (size_t k = 0; k < count; k++) {
if (strchr(suite_names[k], '*')) {
pallet.filter.suite_name_has_wildcard = 1;
break;
}
}
if (is_valid_tag) {
pallet.filter.tag = tag;
} else if (pizza_io_cstr_compare(argv[j], "--tag") == 0 && j + 1 < argc) {
// Support multiple tags separated by comma, and wildcards
j++;
size_t count = 0;
cstr *tags = pizza_io_cstr_split(argv[j], ',', &count);
int valid_count = 0;
for (size_t k = 0; k < count; k++) {
int is_valid_tag = 0;
for (int t = 0; VALID_TAGS[t] != null; t++) {
if (pizza_io_cstr_compare(tags[k], VALID_TAGS[t]) == 0) {
is_valid_tag = 1;
break;
}
}
if (is_valid_tag || strchr(tags[k], '*')) {
valid_count++;
}
}
if (valid_count == (int)count) {
pallet.filter.tag = argv[j]; // Store raw string for now
pallet.filter.tag_list = tags;
pallet.filter.tag_count = count;
// Wildcard support: mark if any tag contains '*'
pallet.filter.tag_has_wildcard = 0;
for (size_t k = 0; k < count; k++) {
if (strchr(tags[k], '*')) {
pallet.filter.tag_has_wildcard = 1;
break;
}
}
} else {
pizza_io_printf("{red}Error: Invalid tag '%s'.{reset}\n", tag);
pizza_io_printf("{red}Error: Invalid tag(s) in '%s'.{reset}\n", argv[j]);
exit(EXIT_FAILURE);
}
} else if (pizza_io_cstr_compare(argv[j], "--help") == 0) {
Expand Down Expand Up @@ -1210,7 +1366,6 @@ pizza_sys_memory_t pizza_sys_memory_init(pizza_sys_memory_t ptr, size_t size, in

void pizza_sys_memory_free(pizza_sys_memory_t ptr) {
if (!ptr) {
fprintf(stderr, "Error: pizza_sys_memory_free() - Pointer is null.\n");
return;
}
free(ptr); // No need for null check, free() already handles null.
Expand Down Expand Up @@ -1971,3 +2126,26 @@ cstr pizza_io_cstr_pad_right(ccstr str, size_t total_length, char pad_char) {
}
return result;
}

bool pizza_io_cstr_append(cstr dest, size_t max_len, cstr src) {
if (!dest || !src || max_len == 0) return false;

// Find current length of dest up to max_len
size_t dest_len = 0;
while (dest_len < max_len && dest[dest_len] != '\0') {
++dest_len;
}

// If no null-terminator found in range, dest is not safe
if (dest_len == max_len) return false;

size_t src_len = strlen(src);

// Make sure there's enough space (including null terminator)
if (dest_len + src_len >= max_len) return false;

memcpy(dest + dest_len, src, src_len);
dest[dest_len + src_len] = '\0';

return true;
}
Loading
Loading