Files
LithosAnanake/src/test_runner/test_runner.c
T
Robert Allan JamesandClaude Sonnet 5 1a2ec565e8 Zero C-compiler warnings on all three architectures; fix real restore_vm_state() bug
Maintainability sweep (prompted by "this is getting hard to maintain"):
fixed the remaining three warning classes after the missing-field-
initializers commit -- 2x -Wsign-compare (control_words.c, cast at the
comparison site rather than changing cf_last_mode's type, which
deliberately holds a -999 sentinel outside vm_mode_t's valid range),
2x -Wstringop-truncation (mkcapsule.c, strncpy+manual-null-terminate
replaced with the idiomatic snprintf equivalent), and 26x
-Wunused-parameter (mostly documented stubs, silenced with the repo's
existing (void)param; idiom).

One of the unused-parameter warnings was not a deliberate stub -- a
real bug. restore_vm_state() (test_common.c) is named, documented, and
called by nine real call sites (acl_words_test.c x8 plus its own
internal use) as "restore saved VM state", but ignored all four of its
parameters and hard-reset to a fixed baseline instead, silently not
restoring what any caller actually saved. Fixed to actually assign the
passed-in dsp/rsp/error/mode. Found while fixing warnings, reported
before touching it, fixed/tested/documented/committed on explicit
instruction.

Verified: all three architectures build with zero C-compiler warnings
(amd64: 3040 -> 0; aarch64's one remaining note is lld-link's own
unrelated linker warning, not a C warning). Full amd64 acceptance boot
post-fix: POST 1003/965/0/0/38 (total/passed/failed/errors/stubs),
"ALL IMPLEMENTED TESTS PASSED!", contract checks (A4'/A1) all passed,
dict_hash=0x24b4279f0670aa3a -- an exact match to this document's own
previously-recorded baseline hash.

.claude/CLAUDE.md corrected to describe the real -Wno-error= exemption
list instead of the "-Wall -Werror" oversimplification. FABRIC-2.md
Section J records the full sweep, including doc-tree staleness findings
flagged but not fixed this pass (docs/lithosananke/ROADMAP.md branch
topology, docs/03-architecture/word-acl/DESIGN.md's Phase 7 claim
contradicting CLAUDE.md, top-level ROADMAP.md's stale StarForth-era
status, the Isabelle pipeline-metrics model mismatch).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-08-18 22:31:57 -04:00

269 lines
10 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 20232025 Robert A. James
All rights reserved.
This file is part of the StarForth project.
Licensed under the StarForth License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
express or implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose, and noninfringement.
See the License for the specific language governing permissions and
limitations under the License.
StarForth — Steady-State Virtual Machine Runtime
Copyright (c) 20232025 Robert A. James
All rights reserved.
This file is part of the StarForth project.
Licensed under the StarForth License, Version 1.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
https://github.com/star.4th@proton.me/StarForth/LICENSE.txt
This software is provided "AS IS", WITHOUT WARRANTY OF ANY KIND,
express or implied, including but not limited to the warranties of
merchantability, fitness for a particular purpose, and noninfringement.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "include/test_runner.h"
#include "include/test_contracts.h"
#include "../../include/log.h"
#include <stdint.h>
#ifdef __STARKERNEL__
#include "platform_time.h"
/* Kernel uses sf_monotonic_ns() for timing */
/* strcmp provided by shim.c */
extern int strcmp(const char *a, const char *b);
#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#endif
/** @brief Global statistics for test execution */
#ifdef __STARKERNEL__
/* Ensure visibility for GOT-based access with -fPIC -fvisibility=hidden */
__attribute__((visibility("default")))
#endif
TestStats global_test_stats = {0, 0, 0, 0, 0};
/*
* Same-TU accessor — avoids R_X86_64_REX_GOTPCRELX double-dereference in
* -fPIC PE builds where struct access generates GOT-indirect code that the
* PE linker does not relax.
*/
void test_stats_accumulate(int tests, int pass, int fail, int skip, int error)
{
global_test_stats.total_tests += tests;
global_test_stats.total_pass += pass;
global_test_stats.total_fail += fail;
global_test_stats.total_skip += skip;
global_test_stats.total_error += error;
}
/** @brief Flag indicating if benchmark mode is enabled */
static int benchmark_mode = 0;
/** @brief Number of iterations for benchmark tests */
static int benchmark_iterations = 1000;
/**
* @brief Get current time in nanoseconds
*
* Uses platform-specific timing: sf_monotonic_ns() on kernel, clock() on hosted.
*
* @return Current time in nanoseconds, or 0 on error
*/
static uint64_t get_time_ns(void) {
#ifdef __STARKERNEL__
return sf_monotonic_ns();
#else
clock_t t = clock();
if (t == (clock_t)(-1)) {
return 0; /* Error case */
}
/* Convert to nanoseconds: (clock_ticks / CLOCKS_PER_SEC) * 1,000,000,000 */
return (uint64_t)((double) t / CLOCKS_PER_SEC * 1000000000.0);
#endif
}
/* Test modules in POST (Power-On Self Test) order:
* 1. Unit tests (foundational math/algorithms) run FIRST
* 2. Dictionary tests (FORTH word validation) run after POST passes
*/
static TestModule test_modules[] = {
/* === Dictionary Tests: FORTH-79 Word Validation === */
{"Stack Words", NULL, 0, run_stack_words_tests}, /* Module 5 */
{"Return Stack Words", NULL, 0, run_return_stack_words_tests}, /* Module 6 */
{"Memory Words", NULL, 0, run_memory_words_tests}, /* Module 7 */
{"Arithmetic Words", NULL, 0, run_arithmetic_words_tests}, /* Module 8 */
{"Logical Words", NULL, 0, run_logical_words_tests}, /* Module 9 */
{"Mixed Arithmetic Words", NULL, 0, run_mixed_arithmetic_words_tests}, /* Module 10 */
{"Double Words", NULL, 0, run_double_words_tests}, /* Module 11 */
{"Format Words", NULL, 0, run_format_words_tests}, /* Module 12 */
{"String Words", NULL, 0, run_string_words_tests}, /* Module 13 */
{"I/O Words", NULL, 0, run_io_words_tests}, /* Module 14 */
{"Block Words", NULL, 0, run_block_words_tests}, /* Module 15 */
{"Dictionary Words", NULL, 0, run_dictionary_words_tests}, /* Module 16 */
{"Dictionary Manipulation Words", NULL, 0, run_dictionary_manipulation_words_tests}, /* Module 17 */
{"Vocabulary Words", NULL, 0, run_vocabulary_words_tests}, /* Module 18 */
{"System Words", NULL, 0, run_system_words_tests}, /* Module 19 */
{"Defining Words", NULL, 0, run_defining_words_tests}, /* Module 20 */
{"Control Words", NULL, 0, run_control_words_tests}, /* Module 21 */
{"StarForth Words", NULL, 0, run_starforth_words_tests}, /* Module 22 */
{"ACL Words", NULL, 0, run_acl_words_tests}, /* Module 23: Word-Level ACL System */
{"Mama FORTH Words", NULL, 0, run_mama_forth_words_tests}, /* Module 24: Capsule System M7.1 */
{NULL, NULL, 0, NULL} /* End marker */
};
/**
* @brief Enable benchmark mode for test execution
*
* @param iterations Number of times each test should be repeated
*/
void enable_benchmark_mode(int iterations) {
benchmark_mode = 1;
benchmark_iterations = iterations;
log_message(LOG_INFO, "Benchmark mode enabled: %d iterations per module", iterations);
}
/**
* @brief Run all test modules with optional benchmarking
*
* Executes all registered test modules sequentially, collecting statistics
* and/or benchmark data depending on the current mode.
*
* @param vm Pointer to the Forth virtual machine instance
*/
void run_all_tests(VM *vm) {
log_message(LOG_INFO, "Starting comprehensive FORTH-79 modular test suite...");
log_message(LOG_INFO, "==============================================");
/* Reset global statistics */
global_test_stats.total_tests = 0;
global_test_stats.total_pass = 0;
global_test_stats.total_fail = 0;
global_test_stats.total_skip = 0;
global_test_stats.total_error = 0;
contract_reset_violation_count();
/* Run each test module */
for (int i = 0; test_modules[i].module_name != NULL; i++) {
TestModule const*module = &test_modules[i];
log_message(LOG_INFO, "\n=== Testing Module: %s ===", module->module_name);
if (module->run_module_tests != NULL) {
module->run_module_tests(vm);
} else {
log_message(LOG_WARN, "Module %s: No tests implemented yet", module->module_name);
}
}
/* Print test summary */
log_message(LOG_INFO, "FINAL TEST SUMMARY:");
log_message(LOG_INFO, " Total tests run: %d", global_test_stats.total_tests);
log_message(LOG_INFO, " Passed: %d", global_test_stats.total_pass);
log_message(LOG_INFO, " Failed: %d", global_test_stats.total_fail);
log_message(LOG_INFO, " Stubs (not yet implemented): %d", global_test_stats.total_skip);
log_message(LOG_INFO, " Errors: %d", global_test_stats.total_error);
if (global_test_stats.total_fail == 0 && global_test_stats.total_error == 0) {
log_message(LOG_INFO, "ALL IMPLEMENTED TESTS PASSED!");
} else {
log_message(LOG_ERROR, "%d tests FAILED or had ERRORS!",
global_test_stats.total_fail + global_test_stats.total_error);
}
if (contract_get_violation_count() > 0) {
log_message(LOG_ERROR, " Contract violations (A4'/A1): %d *** AXIOM WITNESSES FAILED ***",
contract_get_violation_count());
} else {
log_message(LOG_INFO, " Contract checks (A4'/A1): all passed");
}
log_message(LOG_INFO, "==============================================");
}
/**
* @brief Run tests for a specific module
*
* @param vm Pointer to the Forth virtual machine instance
* @param module_name Name of the module to test
*/
void run_module_tests(VM *vm, const char *module_name) {
for (int i = 0; test_modules[i].module_name != NULL; i++) {
if (strcmp(test_modules[i].module_name, module_name) == 0) {
if (benchmark_mode) {
log_message(LOG_INFO, "Benchmarking module: %s", module_name);
if (test_modules[i].run_module_tests != NULL) {
/* Warmup */
test_modules[i].run_module_tests(vm);
/* Benchmark */
uint64_t start_time = get_time_ns();
for (int iter = 0; iter < benchmark_iterations; iter++) {
test_modules[i].run_module_tests(vm);
}
uint64_t end_time = get_time_ns();
uint64_t total_time = end_time - start_time;
double runs_per_second = (double) benchmark_iterations * 1000000000.0 / total_time;
log_message(LOG_INFO, " %.0f runs/sec | %.1f μs/run",
runs_per_second,
(double) total_time / benchmark_iterations / 1000.0);
} else {
log_message(LOG_WARN, "No tests implemented for module: %s", module_name);
}
} else {
log_message(LOG_INFO, "Running tests for module: %s", module_name);
if (test_modules[i].run_module_tests != NULL) {
test_modules[i].run_module_tests(vm);
} else {
log_message(LOG_WARN, "No tests implemented for module: %s", module_name);
}
}
return;
}
}
log_message(LOG_ERROR, "Unknown test module: %s", module_name);
}
/**
* @brief Run tests for a specific Forth word
*
* Searches all modules for tests related to the specified word and executes them.
*
* @param vm Pointer to the Forth virtual machine instance
* @param word_name Name of the Forth word to test
*/
void run_word_tests(VM *vm, const char *word_name) {
(void)vm;
log_message(LOG_INFO, "Searching for tests for word: %s", word_name);
int found = 0;
for (int i = 0; test_modules[i].module_name != NULL; i++) {
/* This would need to be implemented in each module */
/* For now, just run all tests - individual word testing can be added later */
}
if (!found) {
log_message(LOG_WARN, "No tests found for word: %s", word_name);
}
}