12.9 步骤 6:vm_test 固化(手工映像 + 编译器产物 + 确定性)。
- 手工映像:标量/跳转/数据区、CALL/RET 帧复制(r1/r2 实参 → r0 结果)、自调用 StackOverflow、越界槽 BadSlot、坏常量 BadConst - 编译器产物:用例 01~09/13/15/17/18/20 跑周期断言(TON 第 3 周期 q=1、line1 真值表 4 组) - 用例 06 CycleLimit;确定性:同一 I 序列两遍数据区逐字节一致 - step 单步:停在指令边界、cycle_count/regs 逐步核对 - ctest 10/10(vm_cycles 84 断言)
This commit is contained in:
@@ -78,3 +78,14 @@ target_compile_definitions(codegen_test PRIVATE
|
|||||||
|
|
||||||
add_test(NAME codegen_slice1
|
add_test(NAME codegen_slice1
|
||||||
COMMAND codegen_test)
|
COMMAND codegen_test)
|
||||||
|
|
||||||
|
# VM 测试:手工映像 + 编译器产物 + 定时器 + 确定性(REPO_ROOT 注入源目录绝对路径)
|
||||||
|
add_executable(vm_test
|
||||||
|
./src/vm_test.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(vm_test PRIVATE compiler vm)
|
||||||
|
target_compile_definitions(vm_test PRIVATE
|
||||||
|
REPO_ROOT="${CMAKE_SOURCE_DIR}")
|
||||||
|
|
||||||
|
add_test(NAME vm_cycles
|
||||||
|
COMMAND vm_test)
|
||||||
|
|||||||
@@ -0,0 +1,440 @@
|
|||||||
|
/**
|
||||||
|
* @file vm_test.cpp
|
||||||
|
* @brief VM 测试(12.9):手工映像 + 编译器产物 + 定时器 + 确定性
|
||||||
|
* @author
|
||||||
|
* @date 2026-08-21
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "compiler/Codegen.h"
|
||||||
|
#include "compiler/Linker.h"
|
||||||
|
#include "compiler/Project.h"
|
||||||
|
#include "compiler/Typecheck.h"
|
||||||
|
#include "isa/Encode.h"
|
||||||
|
#include "isa/Image.h"
|
||||||
|
#include "isa/Instr.h"
|
||||||
|
#include "isa/Op.h"
|
||||||
|
#include "vm/Machine.h"
|
||||||
|
|
||||||
|
#ifndef REPO_ROOT
|
||||||
|
#define REPO_ROOT "."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int g_checks = 0;
|
||||||
|
|
||||||
|
#define CHECK(cond) \
|
||||||
|
do { \
|
||||||
|
if (!(cond)) { \
|
||||||
|
std::printf("FAIL %s:%d: %s\n", __FILE__, __LINE__, #cond); \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
++g_checks; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
// ---- 数据区槽访问 ----
|
||||||
|
|
||||||
|
static int64_t slot(const vm::Machine& m, int s) {
|
||||||
|
int64_t v = 0;
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
v |= static_cast<int64_t>(m.data()[s * 8 + i]) << (8 * i);
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void wslot(vm::Machine& m, int s, int64_t v) {
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
m.data()[s * 8 + i] = static_cast<uint8_t>((v >> (8 * i)) & 0xFF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 编译器产物全链路(编译 → 建机 → 跑周期)----
|
||||||
|
|
||||||
|
static bool make_machine(const char* dir, vm::Machine* m, std::string* err) {
|
||||||
|
using namespace compiler;
|
||||||
|
const std::string toml = std::string(REPO_ROOT) + "/" + dir + "/project.toml";
|
||||||
|
Project p;
|
||||||
|
if (!parse_project(toml, &p, err)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::vector<SourceUnit> units;
|
||||||
|
for (const std::string& f : compile_files(p)) {
|
||||||
|
SourceUnit u;
|
||||||
|
if (!load_unit(p.base_dir + "/" + f, &u, err)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
units.push_back(std::move(u));
|
||||||
|
}
|
||||||
|
LinkResult link;
|
||||||
|
if (!link_project(p, units, &link, err)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!check_project(p, units, link, err)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::vector<uint8_t> img;
|
||||||
|
if (!codegen_project(p, units, link, &img, err)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return vm::Machine::create(img, m, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 手工拼映像 ----
|
||||||
|
|
||||||
|
struct HFunc {
|
||||||
|
std::vector<isa::Instr> code;
|
||||||
|
uint32_t nregs = 8;
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::vector<uint8_t> hand_image(const std::vector<isa::ConstEntry>& consts,
|
||||||
|
const std::vector<HFunc>& funcs,
|
||||||
|
uint32_t entry = 0,
|
||||||
|
uint32_t cycle_limit = 100000,
|
||||||
|
const std::vector<uint8_t>& data = {}) {
|
||||||
|
size_t code_total = 0;
|
||||||
|
for (const HFunc& f : funcs) {
|
||||||
|
code_total += f.code.size() * 4;
|
||||||
|
}
|
||||||
|
const uint32_t off_const = 72;
|
||||||
|
const uint32_t off_funcs = off_const + static_cast<uint32_t>(consts.size()) * 12;
|
||||||
|
const uint32_t off_code = off_funcs + static_cast<uint32_t>(funcs.size()) * 12;
|
||||||
|
const uint32_t off_data = off_code + static_cast<uint32_t>(code_total);
|
||||||
|
const uint32_t off_end = off_data + static_cast<uint32_t>(data.size());
|
||||||
|
|
||||||
|
std::vector<uint8_t> b(off_end, 0);
|
||||||
|
auto put32 = [&](size_t o, uint32_t v) {
|
||||||
|
b[o + 0] = static_cast<uint8_t>(v & 0xFFu);
|
||||||
|
b[o + 1] = static_cast<uint8_t>((v >> 8) & 0xFFu);
|
||||||
|
b[o + 2] = static_cast<uint8_t>((v >> 16) & 0xFFu);
|
||||||
|
b[o + 3] = static_cast<uint8_t>((v >> 24) & 0xFFu);
|
||||||
|
};
|
||||||
|
auto put64 = [&](size_t o, uint64_t v) {
|
||||||
|
for (int i = 0; i < 8; ++i) {
|
||||||
|
b[o + i] = static_cast<uint8_t>((v >> (8 * i)) & 0xFFu);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
put32(0, isa::kMagic);
|
||||||
|
put32(4, isa::kVersion);
|
||||||
|
put32(8, cycle_limit);
|
||||||
|
put32(12, 10); // dt_ms
|
||||||
|
put32(24, entry);
|
||||||
|
put32(44, static_cast<uint32_t>(consts.size()));
|
||||||
|
put32(48, static_cast<uint32_t>(funcs.size()));
|
||||||
|
put32(52, off_const);
|
||||||
|
put32(56, off_funcs);
|
||||||
|
put32(60, off_code);
|
||||||
|
put32(64, off_data);
|
||||||
|
put32(68, off_data);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < consts.size(); ++i) {
|
||||||
|
const size_t o = off_const + i * 12;
|
||||||
|
put32(o, static_cast<uint32_t>(consts[i].tag));
|
||||||
|
put64(o + 4, consts[i].value);
|
||||||
|
}
|
||||||
|
size_t acc = 0;
|
||||||
|
for (size_t i = 0; i < funcs.size(); ++i) {
|
||||||
|
const size_t o = off_funcs + i * 12;
|
||||||
|
put32(o, funcs[i].nregs);
|
||||||
|
put32(o + 4, static_cast<uint32_t>(acc));
|
||||||
|
put32(o + 8, static_cast<uint32_t>(funcs[i].code.size()));
|
||||||
|
acc += funcs[i].code.size() * 4;
|
||||||
|
}
|
||||||
|
size_t c = off_code;
|
||||||
|
for (const HFunc& f : funcs) {
|
||||||
|
for (const isa::Instr in : f.code) {
|
||||||
|
put32(c, in);
|
||||||
|
c += 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < data.size(); ++i) {
|
||||||
|
b[off_data + i] = data[i];
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 1. 手工映像:标量 + 跳转 + 数据区 ----
|
||||||
|
|
||||||
|
static bool test_hand_scalar() {
|
||||||
|
// r8 := 5;r9 := r8 + 3;槽 0 ← r9;槽 1 → r10;JT 跳过一条
|
||||||
|
const std::vector<isa::ConstEntry> consts = {
|
||||||
|
{isa::types::Int, 5},
|
||||||
|
{isa::types::Int, 3},
|
||||||
|
{isa::types::Int, 1},
|
||||||
|
};
|
||||||
|
const std::vector<HFunc> funcs = {{
|
||||||
|
{
|
||||||
|
isa::enc_imm(isa::Op::LOADK, 8, 0),
|
||||||
|
isa::enc_rr(isa::Op::MOVE, 9, 8),
|
||||||
|
isa::enc_imm(isa::Op::LOADK, 11, 1),
|
||||||
|
isa::enc_rrr(isa::Op::ADD, 9, 9, 11),
|
||||||
|
isa::enc_slot(isa::Op::STORE_GLOBAL, 9, 0),
|
||||||
|
isa::enc_slot(isa::Op::LOAD_GLOBAL, 10, 0),
|
||||||
|
isa::enc_jc(isa::Op::JT, 9, 1), // r9≠0 → 跳过下一条
|
||||||
|
isa::enc_imm(isa::Op::LOADK, 10, 2),
|
||||||
|
isa::enc_ret(),
|
||||||
|
},
|
||||||
|
12,
|
||||||
|
}};
|
||||||
|
const std::vector<uint8_t> img = hand_image(consts, funcs, 0, 100000,
|
||||||
|
std::vector<uint8_t>(16, 0)); // 2 槽
|
||||||
|
vm::Machine m;
|
||||||
|
std::string err;
|
||||||
|
CHECK(vm::Machine::create(img, &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
CHECK(m.reg(8) == 5);
|
||||||
|
CHECK(m.reg(9) == 8); // 5 + 3
|
||||||
|
CHECK(slot(m, 0) == 8); // 槽 0 收到 8
|
||||||
|
CHECK(m.reg(10) == 8); // 槽 1 读回(JT 跳过覆盖)
|
||||||
|
CHECK(m.cycle_count() == 8);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 2. 手工映像:CALL/RET 帧复制 ----
|
||||||
|
|
||||||
|
static bool test_hand_call() {
|
||||||
|
// fn0(入口):r8=5、r2=7、实参 r1←r8;CALL 1;结果 r0 → r8
|
||||||
|
// fn1:r0 = r1 + r2(r1/r2 来自调用约定区复制)
|
||||||
|
const std::vector<isa::ConstEntry> consts = {
|
||||||
|
{isa::types::Int, 5},
|
||||||
|
{isa::types::Int, 7},
|
||||||
|
};
|
||||||
|
const std::vector<HFunc> funcs = {
|
||||||
|
{{
|
||||||
|
isa::enc_imm(isa::Op::LOADK, 8, 0),
|
||||||
|
isa::enc_imm(isa::Op::LOADK, 2, 1),
|
||||||
|
isa::enc_rr(isa::Op::MOVE, 1, 8),
|
||||||
|
isa::enc_call(1),
|
||||||
|
isa::enc_rr(isa::Op::MOVE, 8, 0),
|
||||||
|
isa::enc_ret(),
|
||||||
|
},
|
||||||
|
12},
|
||||||
|
{{
|
||||||
|
isa::enc_rrr(isa::Op::ADD, 0, 1, 2),
|
||||||
|
isa::enc_ret(),
|
||||||
|
},
|
||||||
|
10},
|
||||||
|
};
|
||||||
|
const std::vector<uint8_t> img = hand_image(consts, funcs);
|
||||||
|
vm::Machine m;
|
||||||
|
std::string err;
|
||||||
|
CHECK(vm::Machine::create(img, &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
CHECK(m.reg(8) == 12); // 5 + 7
|
||||||
|
CHECK(m.call_depth() == 1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 3. 手工映像:自调用 → StackOverflow ----
|
||||||
|
|
||||||
|
static bool test_stack_overflow() {
|
||||||
|
const std::vector<HFunc> funcs = {{
|
||||||
|
{
|
||||||
|
isa::enc_call(0),
|
||||||
|
isa::enc_ret(),
|
||||||
|
},
|
||||||
|
8,
|
||||||
|
}};
|
||||||
|
const std::vector<uint8_t> img = hand_image({}, funcs);
|
||||||
|
vm::Machine m;
|
||||||
|
std::string err;
|
||||||
|
CHECK(vm::Machine::create(img, &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::StackOverflow);
|
||||||
|
CHECK(m.call_depth() == 1); // 周期结束已清栈(留 MAIN)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 4. 手工映像:越界槽 → BadSlot ----
|
||||||
|
|
||||||
|
static bool test_bad_slot() {
|
||||||
|
const std::vector<HFunc> funcs = {{
|
||||||
|
{
|
||||||
|
isa::enc_slot(isa::Op::STORE_GLOBAL, 8, 60000), // 数据区 0 字节
|
||||||
|
isa::enc_ret(),
|
||||||
|
},
|
||||||
|
12,
|
||||||
|
}};
|
||||||
|
const std::vector<uint8_t> img = hand_image({}, funcs);
|
||||||
|
vm::Machine m;
|
||||||
|
std::string err;
|
||||||
|
CHECK(vm::Machine::create(img, &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::BadSlot);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 5. 编译器产物正例 ----
|
||||||
|
|
||||||
|
static bool test_cases_positive() {
|
||||||
|
std::string err;
|
||||||
|
vm::Machine m;
|
||||||
|
|
||||||
|
// 01 空 MAIN
|
||||||
|
CHECK(make_machine("tests/cases/01_empty_main", &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
|
||||||
|
// 02 BOOL 赋值:a=TRUE(r8) b=FALSE(r9)
|
||||||
|
CHECK(make_machine("tests/cases/02_bool_assign", &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
CHECK(m.reg(8) == 1 && m.reg(9) == 0);
|
||||||
|
|
||||||
|
// 03 短路:a=0 b=0 → x=0
|
||||||
|
CHECK(make_machine("tests/cases/03_short_circuit", &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
CHECK(m.reg(10) == 0);
|
||||||
|
|
||||||
|
// 04 IF:sel=0 → out=10
|
||||||
|
CHECK(make_machine("tests/cases/04_if_elsif_else", &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
CHECK(m.reg(9) == 10);
|
||||||
|
|
||||||
|
// 05 WHILE:n=10
|
||||||
|
CHECK(make_machine("tests/cases/05_while_normal", &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
CHECK(m.reg(8) == 10);
|
||||||
|
|
||||||
|
// 07 算术:a=42 b=10 c=32 eq=1
|
||||||
|
CHECK(make_machine("tests/cases/07_int_arith", &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
CHECK(m.reg(8) == 42 && m.reg(9) == 10 && m.reg(10) == 32 && m.reg(11) == 1);
|
||||||
|
|
||||||
|
// 08 TIME 字面量:t1=10 t2=1250
|
||||||
|
CHECK(make_machine("tests/cases/08_time_literal", &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
CHECK(m.reg(8) == 10 && m.reg(9) == 1250);
|
||||||
|
|
||||||
|
// 09 GVL + EXTERNAL:x = G1 初值 5(槽 0)
|
||||||
|
CHECK(make_machine("tests/cases/09_gvl_external", &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
CHECK(m.reg(8) == 5);
|
||||||
|
|
||||||
|
// 13 FUNCTION:x = Add(3,4) = 7
|
||||||
|
CHECK(make_machine("tests/cases/13_function_call", &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
CHECK(m.reg(8) == 7);
|
||||||
|
|
||||||
|
// 15 FB 内联:starter(start=TRUE, stop=FALSE) → q=TRUE
|
||||||
|
CHECK(make_machine("tests/cases/15_fb_instance", &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
CHECK(m.reg(8) == 1);
|
||||||
|
|
||||||
|
// 17 TON:dt=10、pt=30,in 恒真 → 第 3 周期 q=1(槽 2)
|
||||||
|
CHECK(make_machine("tests/cases/17_ton", &m, &err));
|
||||||
|
m.run_cycle();
|
||||||
|
m.run_cycle();
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
CHECK(slot(m, 2) == 1); // t.Q
|
||||||
|
CHECK(slot(m, 3) == 30); // t.ET
|
||||||
|
|
||||||
|
// 18 TOF/CTU:跑一个周期无故障
|
||||||
|
CHECK(make_machine("tests/cases/18_tof_ctu", &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
|
||||||
|
// 20 line1:I 组合 → Q0_0 真值表(槽 0=急停 1=I0_0 2=I0_1 3=Q0_0)
|
||||||
|
CHECK(make_machine("tests/cases/20_line1", &m, &err));
|
||||||
|
struct {
|
||||||
|
int start, stop, es, expect;
|
||||||
|
} table[] = {
|
||||||
|
{1, 0, 0, 1},
|
||||||
|
{1, 1, 0, 0},
|
||||||
|
{0, 0, 0, 0},
|
||||||
|
{1, 0, 1, 0},
|
||||||
|
};
|
||||||
|
for (const auto& t : table) {
|
||||||
|
wslot(m, 0, t.es);
|
||||||
|
wslot(m, 1, t.start);
|
||||||
|
wslot(m, 2, t.stop);
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
CHECK(slot(m, 3) == t.expect);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 6. 用例 06:cycle_limit 打满 ----
|
||||||
|
|
||||||
|
static bool test_cycle_limit() {
|
||||||
|
std::string err;
|
||||||
|
vm::Machine m;
|
||||||
|
CHECK(make_machine("tests/cases/06_while_cycle_limit", &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::CycleLimit);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 7. 确定性:同一 I 序列跑两遍,数据区一致 ----
|
||||||
|
|
||||||
|
static bool test_determinism() {
|
||||||
|
std::string err;
|
||||||
|
vm::Machine a, b;
|
||||||
|
CHECK(make_machine("tests/cases/20_line1", &a, &err));
|
||||||
|
CHECK(make_machine("tests/cases/20_line1", &b, &err));
|
||||||
|
const int seq[4][3] = {{1, 0, 0}, {1, 1, 0}, {0, 0, 0}, {1, 0, 1}};
|
||||||
|
for (int rep = 0; rep < 2; ++rep) {
|
||||||
|
vm::Machine& m = rep ? b : a;
|
||||||
|
for (const auto& s : seq) {
|
||||||
|
wslot(m, 0, s[2]);
|
||||||
|
wslot(m, 1, s[0]);
|
||||||
|
wslot(m, 2, s[1]);
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 两遍结束:数据区逐字节一致(含 starter 实例状态)
|
||||||
|
CHECK(a.data_len() == b.data_len());
|
||||||
|
for (size_t i = 0; i < a.data_len(); ++i) {
|
||||||
|
if (a.data()[i] != b.data()[i]) {
|
||||||
|
std::printf("FAIL determinism byte %zu: %d vs %d\n", i, a.data()[i], b.data()[i]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++g_checks;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 8. step 单步:停在指令边界 ----
|
||||||
|
|
||||||
|
static bool test_step() {
|
||||||
|
std::string err;
|
||||||
|
vm::Machine m;
|
||||||
|
CHECK(make_machine("tests/cases/02_bool_assign", &m, &err));
|
||||||
|
// 3 条指令:LOADK ×2 + RET
|
||||||
|
CHECK(m.step());
|
||||||
|
CHECK(m.cycle_count() == 1 && m.reg(8) == 1);
|
||||||
|
CHECK(m.step());
|
||||||
|
CHECK(m.cycle_count() == 2 && m.reg(9) == 0);
|
||||||
|
CHECK(!m.step()); // RET → 周期结束
|
||||||
|
CHECK(m.cycle_count() == 3);
|
||||||
|
CHECK(!m.step()); // 结束后不再执行
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- 9. 手工映像:坏常量 id → BadConst ----
|
||||||
|
|
||||||
|
static bool test_bad_const() {
|
||||||
|
const std::vector<HFunc> funcs = {{
|
||||||
|
{
|
||||||
|
isa::enc_imm(isa::Op::LOADK, 8, 99), // 常量表为空
|
||||||
|
isa::enc_ret(),
|
||||||
|
},
|
||||||
|
12,
|
||||||
|
}};
|
||||||
|
const std::vector<uint8_t> img = hand_image({}, funcs);
|
||||||
|
vm::Machine m;
|
||||||
|
std::string err;
|
||||||
|
CHECK(vm::Machine::create(img, &m, &err));
|
||||||
|
CHECK(m.run_cycle() == vm::Fault::BadConst);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
if (!test_hand_scalar()) return 1;
|
||||||
|
if (!test_hand_call()) return 1;
|
||||||
|
if (!test_stack_overflow()) return 1;
|
||||||
|
if (!test_bad_slot()) return 1;
|
||||||
|
if (!test_cases_positive()) return 1;
|
||||||
|
if (!test_cycle_limit()) return 1;
|
||||||
|
if (!test_determinism()) return 1;
|
||||||
|
if (!test_step()) return 1;
|
||||||
|
if (!test_bad_const()) return 1;
|
||||||
|
std::printf("vm_test: %d checks passed\n", g_checks);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user