SilverSight/cpp/test_avm.cpp
allaun 6451bfba15 fix(ports): C, C++, Go, Octave test fixes
C: type_mismatch test adjusted for C port (returns default on type error)
C++: variant comparison fixed with val_i/val_b helpers, all tests use proper accessors
Go: added go.mod to repo so go test works from any directory
Octave: test now uses addpath to find AVM class
2026-06-30 18:21:20 -05:00

106 lines
3.6 KiB
C++

// AVM ISA v1 — C++ Test Harness
#include <cassert>
#include <iostream>
#include "avm.hpp"
using namespace avm;
#define QS Q16_SCALE
int32_t val_i(const AnyVal& v) { return std::get<int32_t>(v.val); }
bool val_b(const AnyVal& v) { return std::get<bool>(v.val); }
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.has_value());
assert(val_i(s->stack[0]) == 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(val_i(s->stack[0]) == 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(val_i(s->stack[0]) == 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); // bool variant OK
}
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(val_i(s->stack[0]) == 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(val_i(s->stack[0]) == 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;
}