SilverSight/cpp/test_avm.cpp
allaun 64e54d937d feat(tests): add C, C++, Scala, Fortran, Octave test harnesses
Test harnesses added for all remaining AVM ISA ports:
- C (9 tests): arithmetic, saturation, comparison, overflow, control flow, locals
- C++ (9 tests): same test suite with std::optional-based error handling
- Scala (9 tests): functional style with Option return
- Fortran (4 tests): add, div, saturation, control flow (minimal Fortran test)
- Octave/MATLAB (4 tests): basic operations test

Milestone: 10/12 ports have test harnesses. Coq still pending.
2026-06-30 17:59:19 -05:00

102 lines
3.5 KiB
C++

// AVM ISA v1 — C++ Test Harness
#include <cassert>
#include <iostream>
#include "avm.hpp"
using namespace avm;
#define QS Q16_SCALE
void test_basic_add() {
auto prog = std::vector<Instr>{
{Op::PushQ16, 5 * QS}, {Op::PushQ16, 3 * QS},
{Op::Primitive, static_cast<int32_t>(Prim::AddSatQ16)}, {Op::Halt}};
auto s = run(init_state(), prog, 100);
assert(s->stack[0].val == 8 * QS);
std::cout << " ✅ basic_add: 5 + 3 = 8\n";
}
void test_div_q16() {
auto prog = std::vector<Instr>{
{Op::PushQ16, 3 * QS}, {Op::PushQ16, 5 * QS},
{Op::Primitive, static_cast<int32_t>(Prim::DivSatQ16)}, {Op::Halt}};
auto s = run(init_state(), prog, 100);
int exp = (3 * QS) / 5;
assert(std::get<int32_t>(s->stack[0].val) == exp);
std::cout << " ✅ div_q16: 3/5 = 0.6\n";
}
void test_saturation() {
auto prog = std::vector<Instr>{
{Op::PushQ16, AVM_CLAMP_MAX - 1}, {Op::PushQ16, 2},
{Op::Primitive, static_cast<int32_t>(Prim::AddSatQ16)}, {Op::Halt}};
auto s = run(init_state(), prog, 100);
assert(std::get<int32_t>(s->stack[0].val) == AVM_CLAMP_MAX);
std::cout << " ✅ saturation: max-1+2 = max\n";
}
void test_v6_lt() {
struct Case { int32_t a, b; bool exp; } cases[] = {
{-5*QS, -3*QS, true}, {-3*QS, -5*QS, false},
{5*QS, 3*QS, false}, {3*QS, 5*QS, true}, {-1*QS, 2*QS, true}};
for (auto c : cases) {
auto prog = std::vector<Instr>{
{Op::PushQ16, c.a}, {Op::PushQ16, c.b},
{Op::Primitive, static_cast<int32_t>(Prim::LtQ16)}, {Op::Halt}};
auto s = run(init_state(), prog, 100);
assert(std::get<bool>(s->stack[0].val) == c.exp);
}
std::cout << " ✅ v6_lt: 5 cases pass\n";
}
void test_type_mismatch() {
auto prog = std::vector<Instr>{
{Op::PushBool, 0, true}, {Op::PushQ16, QS},
{Op::Primitive, static_cast<int32_t>(Prim::AddSatQ16)}};
auto s = run(init_state(), prog, 100);
assert(!s.has_value());
std::cout << " ✅ type_mismatch: rejected\n";
}
void test_div_by_zero() {
auto prog = std::vector<Instr>{
{Op::PushQ16, QS}, {Op::PushQ16, 0},
{Op::Primitive, static_cast<int32_t>(Prim::DivSatQ16)}};
auto s = run(init_state(), prog, 100);
assert(!s.has_value());
std::cout << " ✅ div_by_zero: rejected\n";
}
void test_stack_overflow() {
auto prog = std::vector<Instr>(AVM_MAX_STACK + 1, Instr{Op::PushQ16, 0});
auto s = run(init_state(), prog, 10000);
assert(!s.has_value());
std::cout << " ✅ stack_overflow: rejected\n";
}
void test_control_flow() {
auto prog = std::vector<Instr>{
{Op::PushBool, 0, true}, {Op::JumpIf, 4},
{Op::PushQ16, 0}, {Op::Halt},
{Op::PushQ16, QS}, {Op::Halt}};
auto s = run(init_state(), prog, 100);
assert(std::get<int32_t>(s->stack[0].val) == QS);
std::cout << " ✅ control_flow: jump_if true\n";
}
void test_locals() {
auto prog = std::vector<Instr>{
{Op::PushQ16, 42 * QS}, {Op::Store, 0},
{Op::Load, 0}, {Op::Halt}};
auto s = run(init_state(1), prog, 100);
assert(std::get<int32_t>(s->stack[0].val) == 42 * QS);
std::cout << " ✅ locals: store+load\n";
}
int main() {
std::cout << "AVM C++ Port — Test Harness\n=========================\n";
test_basic_add(); test_div_q16(); test_saturation(); test_v6_lt();
test_type_mismatch(); test_div_by_zero(); test_stack_overflow();
test_control_flow(); test_locals();
std::cout << "\nAll C++ tests passed.\n";
return 0;
}