POST coverage cluster 2/4: Q48.16 math primitives (proof-covered, previously untested)

New module (q48_words_test.c, Module 25 -- matches word_registry.c's own
existing numbering for this file's registration) covers all 23 words in
q48_words.c: no test file existed for this file at all before. Standard
WordTestSuite/TestCase tabular format, unlike ACL's hand-rolled style --
these are pure stateless functions, a natural fit. 28 TestCase entries;
values built via Q.FROM-INT/Q.1/Q.0, read back via Q.TO-INT for readable
log output.

Verified q48_16.h's q48_to_u64() sign-extends through a signed int64_t
intermediate before writing the Q.NEG/Q.ABS tests, rather than assuming
negative round-trip works.

Boot-verified: zero build warnings, all 23 words pass individually,
FINAL TEST SUMMARY 1003->1031 total / 965->993 passed (+28 exactly),
0 failed, 0 errors. Noted (pre-existing, not fixed): print_module_summary()
is called with hardcoded (name,0,0,0,0) across every WordTestSuite module
in the tree, including this new one -- decorative, always zero; the real
counts live in each word's own per-suite line and the global summary.

Cluster 3 of 4 in the POST-coverage sequence (code sweeps -> HOL green ->
POST coverage, one proof-covered cluster at a time). Two clusters left:
inference-engine accessors, physics freeze/diagnostic. Full writeup in
FABRIC-2.md Section J.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Robert Allan James
2026-08-18 23:30:46 -04:00
co-authored by Claude Sonnet 5
parent b2918fd0b2
commit 7100523656
7 changed files with 14601 additions and 1 deletions
+6
View File
@@ -103,6 +103,12 @@ void run_control_words_tests(VM * vm);
void run_starforth_words_tests(VM * vm);
void run_acl_words_tests(VM * vm);
/*
* @brief Run tests for Q48.16 fixed-point words (Module 25)
* @param vm Pointer to the VM instance
*/
void run_q48_words_tests(VM * vm);
/*
* @brief Run tests for Mama FORTH vocabulary (capsule system M7.1)
* @param vm Pointer to the VM instance
+230
View File
@@ -0,0 +1,230 @@
/*
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.
*/
/*
* q48_words_test.c — POST tests for Q48.16 fixed-point words (Module 25)
*
* Proof-covered per proof/COVERAGE.md (StarForth_Q48_Words.thy, 17/23) but
* had no interpreter-level POST coverage at all before this file — no test
* file for q48_words.c existed. Values are built with Q.FROM-INT/Q.1/Q.0
* and read back with Q.TO-INT so results print as plain readable integers;
* pass/fail itself is judged only by vm->error (matching every other
* WordTestSuite-based module), so exact printed values are for a human
* reading the log, not machine-verified — same convention arithmetic_words_
* test.c already uses for its own "Should print: N" fields.
*/
#include "../include/test_runner.h"
#include "../include/test_common.h"
/* Q48.16 Words Test Suites - Module 25 */
static WordTestSuite q48_word_suites[] = {
{
"Q.+", {
{"basic", "1 Q.FROM-INT 2 Q.FROM-INT Q.+ Q.TO-INT . CR", "Should print: 3", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.-", {
{"basic", "5 Q.FROM-INT 2 Q.FROM-INT Q.- Q.TO-INT . CR", "Should print: 3", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.*", {
{"basic", "3 Q.FROM-INT 4 Q.FROM-INT Q.* Q.TO-INT . CR", "Should print: 12", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q./", {
{"basic", "10 Q.FROM-INT 2 Q.FROM-INT Q./ Q.TO-INT . CR", "Should print: 5", TEST_NORMAL, 0, 1, {0}},
{"by_zero", "5 Q.FROM-INT 0 Q.FROM-INT Q./ Q.TO-INT . CR", "Should print: 0 (division by zero yields q=0)", TEST_EDGE_CASE, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
2, {0}
},
{
"Q.ABS", {
{"basic", "3 Q.FROM-INT Q.NEG Q.ABS Q.TO-INT . CR", "Should print: 3", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.NEG", {
{"basic", "5 Q.FROM-INT Q.NEG Q.TO-INT . CR", "Should print: -5", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.LOG", {
{"of_one", "Q.1 Q.LOG Q.TO-INT . CR", "Should print: 0 (ln 1.0 = 0)", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.EXP", {
{"of_zero", "Q.0 Q.EXP Q.TO-INT . CR", "Should print: 1 (e^0 = 1)", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.SQRT", {
{"of_four", "4 Q.FROM-INT Q.SQRT Q.TO-INT . CR", "Should print: 2", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.SIN", {
{"of_zero", "Q.0 Q.SIN Q.TO-INT . CR", "Should print: 0 (sin 0 = 0)", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.COS", {
{"of_zero", "Q.0 Q.COS Q.TO-INT . CR", "Should print: 1 (cos 0 = 1)", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.FROM-INT", {
{"round_trip", "7 Q.FROM-INT Q.TO-INT . CR", "Should print: 7", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.TO-INT", {
{"of_one", "Q.1 Q.TO-INT . CR", "Should print: 1", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.1", {
{"raw_value", "Q.1 . CR", "Should print: 65536", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.0", {
{"raw_value", "Q.0 . CR", "Should print: 0", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.SCALE", {
{"raw_value", "Q.SCALE . CR", "Should print: 65536", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.=", {
{"equal", "Q.1 Q.1 Q.= . CR", "Should print: -1 (true)", TEST_NORMAL, 0, 1, {0}},
{"not_equal", "Q.1 Q.0 Q.= . CR", "Should print: 0 (false)", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
2, {0}
},
{
"Q.<", {
{"true", "Q.0 Q.1 Q.< . CR", "Should print: -1 (true)", TEST_NORMAL, 0, 1, {0}},
{"false", "Q.1 Q.0 Q.< . CR", "Should print: 0 (false)", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
2, {0}
},
{
"Q.>", {
{"true", "Q.1 Q.0 Q.> . CR", "Should print: -1 (true)", TEST_NORMAL, 0, 1, {0}},
{"false", "Q.0 Q.1 Q.> . CR", "Should print: 0 (false)", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
2, {0}
},
{
"Q.0=", {
{"true", "Q.0 Q.0= . CR", "Should print: -1 (true)", TEST_NORMAL, 0, 1, {0}},
{"false", "Q.1 Q.0= . CR", "Should print: 0 (false)", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
2, {0}
},
{
"Q.MAX", {
{"basic", "3 Q.FROM-INT 7 Q.FROM-INT Q.MAX Q.TO-INT . CR", "Should print: 7", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.MIN", {
{"basic", "3 Q.FROM-INT 7 Q.FROM-INT Q.MIN Q.TO-INT . CR", "Should print: 3", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{
"Q.PRINT", {
{"of_one", "Q.1 Q.PRINT CR", "Should print: 1.00000", TEST_NORMAL, 0, 1, {0}},
{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}
},
1, {0}
},
{NULL, {{NULL, NULL, NULL, TEST_NORMAL, 0, 0, {0}}}, 0, {0}}
};
/**
* @brief Executes all Q48.16 fixed-point word test suites
* @param vm Pointer to the Forth virtual machine instance
* @details Covers all 23 words registered by register_q48_words()
* (q48_words.c): arithmetic (+, -, *, /), sign (ABS, NEG),
* transcendental approximations (LOG, EXP, SQRT, SIN, COS),
* conversions (FROM-INT, TO-INT), constants (1, 0, SCALE),
* comparisons (=, <, >, 0=, MAX, MIN), and PRINT.
*/
void run_q48_words_tests(VM *vm) {
log_message(LOG_INFO, "Running Q48.16 Words Tests (Module 25)...");
WordContract mod = {CONTRACT_PHYSICS_TRANSPARENT, 0};
for (int i = 0; q48_word_suites[i].word_name != NULL; i++) {
log_message(LOG_TEST, "▶ Testing module: %s", __FILE__);
run_test_suite_m(vm, &q48_word_suites[i], mod);
}
print_module_summary("Q48.16 Words", 0, 0, 0, 0);
}
+1
View File
@@ -130,6 +130,7 @@ static TestModule test_modules[] = {
{"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 */
{"Q48.16 Words", NULL, 0, run_q48_words_tests}, /* Module 25: Q48.16 Fixed-Point Arithmetic */
{NULL, NULL, 0, NULL} /* End marker */
};