Stb.h/.cpp V2:
- 头 128B:kOffSlots/kOffValues/kOffNSlots/kOffValuesSize/kOffMeta/kOffMaxStack
- 常量表 8B(无 tag)、槽表行 8B {addr,预留}、static_assert 更新
- StbView:新字段访问器 + slots_bytes + 段校验 6 段(含元数据空段)
Codegen V2:
- 变长指令发射(Codec 位号,emit/E_rr..E_cal/E_slot_off)
- 槽表→值段布局(1/2/4/8 对齐;实例=1 槽表条目指向字段块)
- 常量表位模式去重(LOADK 按 func 解释);字节化跳转回填
- max_stack(调用图 DAG 最长路径 + 环检测递归报错)
- 用户 FB 内联(LOAD_OFF/STORE_OFF 字段访问);内建 FB → CAL fb_id,slot
- 头 128B 拼装(version=2/STATOR2/段序)
配套:main.cpp 常量显示去 tag;codegen_test 临时剥离(阶段 3 重写);
machine_test 修正(72 op + 负例修复)。ctest:10/13 绿(vm/cases 预期内剥离)。
387 lines
19 KiB
C++
387 lines
19 KiB
C++
/**
|
||
* @file machine_test.cpp
|
||
* @brief machine.toml V2 加载与强校验测试(阶段 2)
|
||
* @author
|
||
* @date 2026-08-21
|
||
*/
|
||
|
||
#include <cstdio>
|
||
#include <cstring>
|
||
#include <filesystem>
|
||
#include <string>
|
||
|
||
#include "compiler/MachineConfig.h"
|
||
#include "compiler/Stb.h"
|
||
#include "compiler/TypeInfo.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)
|
||
|
||
// ---- 写临时 toml ----
|
||
|
||
static std::string write_tmp(const char* name, const std::string& content) {
|
||
const std::filesystem::path dir = std::filesystem::temp_directory_path();
|
||
const std::filesystem::path path = dir / name;
|
||
std::FILE* f = std::fopen(path.string().c_str(), "w");
|
||
std::fputs(content.c_str(), f);
|
||
std::fclose(f);
|
||
return path.string();
|
||
}
|
||
|
||
static bool expect_load_err(const char* name, const std::string& content, const char* keyword) {
|
||
const std::string path = write_tmp(name, content);
|
||
compiler::MachineConfig cfg;
|
||
std::string err;
|
||
if (cfg.load(path, &err)) {
|
||
std::printf("FAIL %s: loaded ok\n", name);
|
||
std::remove(path.c_str());
|
||
return false;
|
||
}
|
||
if (err.find("machine error") != 0) {
|
||
std::printf("FAIL %s: want 'machine error', got '%s'\n", name, err.c_str());
|
||
std::remove(path.c_str());
|
||
return false;
|
||
}
|
||
if (err.find(keyword) == std::string::npos) {
|
||
std::printf("FAIL %s: want '%s', got '%s'\n", name, keyword, err.c_str());
|
||
std::remove(path.c_str());
|
||
return false;
|
||
}
|
||
++g_checks;
|
||
std::remove(path.c_str());
|
||
return true;
|
||
}
|
||
|
||
// 合法 type 模板(19 条全集,可注入损坏;缺 DT 时用于"缺全集"负例)
|
||
static const char* kTypesAll =
|
||
"[[type]]\nname = \"BOOL\"\nbase = \"uint8\"\nkind = \"bool\"\nfunc = 0\n"
|
||
"[[type]]\nname = \"BYTE\"\nbase = \"uint8\"\nkind = \"bit\"\nfunc = 0\n"
|
||
"[[type]]\nname = \"WORD\"\nbase = \"uint16\"\nkind = \"bit\"\nfunc = 2\n"
|
||
"[[type]]\nname = \"DWORD\"\nbase = \"uint32\"\nkind = \"bit\"\nfunc = 4\n"
|
||
"[[type]]\nname = \"LWORD\"\nbase = \"uint64\"\nkind = \"bit\"\nfunc = 6\n"
|
||
"[[type]]\nname = \"SINT\"\nbase = \"int8\"\nkind = \"int\"\nfunc = 1\n"
|
||
"[[type]]\nname = \"INT\"\nbase = \"int16\"\nkind = \"int\"\nfunc = 3\n"
|
||
"[[type]]\nname = \"DINT\"\nbase = \"int32\"\nkind = \"int\"\nfunc = 5\n"
|
||
"[[type]]\nname = \"LINT\"\nbase = \"int64\"\nkind = \"int\"\nfunc = 7\n"
|
||
"[[type]]\nname = \"USINT\"\nbase = \"uint8\"\nkind = \"uint\"\nfunc = 0\n"
|
||
"[[type]]\nname = \"UINT\"\nbase = \"uint16\"\nkind = \"uint\"\nfunc = 2\n"
|
||
"[[type]]\nname = \"UDINT\"\nbase = \"uint32\"\nkind = \"uint\"\nfunc = 4\n"
|
||
"[[type]]\nname = \"ULINT\"\nbase = \"uint64\"\nkind = \"uint\"\nfunc = 6\n"
|
||
"[[type]]\nname = \"TIME\"\nbase = \"int64\"\nkind = \"time\"\nfunc = 7\n"
|
||
"[[type]]\nname = \"REAL\"\nbase = \"float32\"\nkind = \"float\"\nfunc = 8\n"
|
||
"[[type]]\nname = \"LREAL\"\nbase = \"float64\"\nkind = \"float\"\nfunc = 9\n"
|
||
"[[type]]\nname = \"DATE\"\nbase = \"uint32\"\nkind = \"date\"\nfunc = 4\n"
|
||
"[[type]]\nname = \"TOD\"\nbase = \"uint32\"\nkind = \"date\"\nfunc = 4\n"
|
||
"[[type]]\nname = \"DT\"\nbase = \"uint64\"\nkind = \"date\"\nfunc = 6\n";
|
||
|
||
// 合法 op 模板(含 CAL 与 RET,可注入损坏)
|
||
static const char* kOpsBasic =
|
||
"[[op]]\nname = \"MOVE\"\nprefix = \"11\"\nop = 0\nfmt = \"RR\"\nfunc = \"width\"\nparams = [\"rd\", \"rs\"]\nenabled = true\n"
|
||
"[[op]]\nname = \"CAL\"\nprefix = \"010101\"\nop = 0\nfmt = \"CAL\"\nfunc = \"none\"\nparams = [\"fb_id\", \"slot\"]\nenabled = true\n"
|
||
"[[op]]\nname = \"RET\"\nprefix = \"10\"\nop = 1\nfmt = \"NONE\"\nfunc = \"none\"\nparams = []\nenabled = true\n";
|
||
|
||
// 合法 fb 模板(15 条全集,可注入损坏)
|
||
static const char* kFbsAll =
|
||
"[[fb]]\nname = \"TON\"\nfb_id = 0\nfields = [[\"in\", \"BOOL\"], [\"pt\", \"TIME\"], [\"q\", \"BOOL\"], [\"et\", \"TIME\"]]\n"
|
||
"[[fb]]\nname = \"TOF\"\nfb_id = 1\nfields = [[\"in\", \"BOOL\"], [\"pt\", \"TIME\"], [\"q\", \"BOOL\"], [\"et\", \"TIME\"]]\n"
|
||
"[[fb]]\nname = \"TP\"\nfb_id = 2\nfields = [[\"in\", \"BOOL\"], [\"pt\", \"TIME\"], [\"q\", \"BOOL\"], [\"et\", \"TIME\"]]\n"
|
||
"[[fb]]\nname = \"CTU\"\nfb_id = 3\nfields = [[\"cu\", \"BOOL\"], [\"r\", \"BOOL\"], [\"pv\", \"INT\"], [\"q\", \"BOOL\"], [\"cv\", \"INT\"]]\n"
|
||
"[[fb]]\nname = \"DCTU\"\nfb_id = 4\nfields = [[\"cu\", \"BOOL\"], [\"r\", \"BOOL\"], [\"pv\", \"DINT\"], [\"q\", \"BOOL\"], [\"cv\", \"DINT\"]]\n"
|
||
"[[fb]]\nname = \"CTD\"\nfb_id = 5\nfields = [[\"cd\", \"BOOL\"], [\"ld\", \"BOOL\"], [\"pv\", \"INT\"], [\"q\", \"BOOL\"], [\"cv\", \"INT\"]]\n"
|
||
"[[fb]]\nname = \"DCTD\"\nfb_id = 6\nfields = [[\"cd\", \"BOOL\"], [\"ld\", \"BOOL\"], [\"pv\", \"DINT\"], [\"q\", \"BOOL\"], [\"cv\", \"DINT\"]]\n"
|
||
"[[fb]]\nname = \"CTUD\"\nfb_id = 7\nfields = [[\"cu\", \"BOOL\"], [\"cd\", \"BOOL\"], [\"r\", \"BOOL\"], [\"lu\", \"BOOL\"], [\"pv\", \"INT\"], [\"qu\", \"BOOL\"], [\"qd\", \"BOOL\"], [\"cv\", \"INT\"]]\n"
|
||
"[[fb]]\nname = \"DCTUD\"\nfb_id = 8\nfields = [[\"cu\", \"BOOL\"], [\"cd\", \"BOOL\"], [\"r\", \"BOOL\"], [\"lu\", \"BOOL\"], [\"pv\", \"DINT\"], [\"qu\", \"BOOL\"], [\"qd\", \"BOOL\"], [\"cv\", \"DINT\"]]\n"
|
||
"[[fb]]\nname = \"R_TRIG\"\nfb_id = 9\nfields = [[\"clk\", \"BOOL\"], [\"q\", \"BOOL\"]]\n"
|
||
"[[fb]]\nname = \"F_TRIG\"\nfb_id = 10\nfields = [[\"clk\", \"BOOL\"], [\"q\", \"BOOL\"]]\n"
|
||
"[[fb]]\nname = \"SR\"\nfb_id = 11\nfields = [[\"S1\", \"BOOL\"], [\"R\", \"BOOL\"], [\"Q1\", \"BOOL\"]]\n"
|
||
"[[fb]]\nname = \"RS\"\nfb_id = 12\nfields = [[\"SET\", \"BOOL\"], [\"RESET1\", \"BOOL\"], [\"Q1\", \"BOOL\"]]\n"
|
||
"[[fb]]\nname = \"PWM\"\nfb_id = 13\nfields = [[\"in\", \"BOOL\"], [\"pt\", \"TIME\"], [\"duty\", \"REAL\"], [\"q\", \"BOOL\"], [\"et\", \"TIME\"]]\n"
|
||
"[[fb]]\nname = \"RTC\"\nfb_id = 14\nfields = [[\"enable\", \"BOOL\"], [\"date\", \"DATE\"], [\"tod\", \"TOD\"]]\n";
|
||
|
||
// ---- 1. 正例:仓库 machine.toml ----
|
||
|
||
static bool test_positive() {
|
||
compiler::MachineConfig cfg;
|
||
std::string err;
|
||
CHECK(cfg.load(std::string(REPO_ROOT) + "/compiler/machine.toml", &err));
|
||
CHECK(cfg.ok());
|
||
CHECK(cfg.model_name() == "STATOR");
|
||
CHECK(cfg.version() == 2);
|
||
|
||
CHECK(cfg.types().size() == 19);
|
||
const compiler::ConfigType* bt = cfg.find_type("BOOL");
|
||
CHECK(bt != nullptr && bt->base == "uint8" && bt->kind == "bool" && bt->func == 0);
|
||
CHECK(cfg.find_type("INT") != nullptr && cfg.find_type("INT")->base == "int16" &&
|
||
cfg.find_type("INT")->kind == "int" && cfg.find_type("INT")->func == 3);
|
||
CHECK(cfg.find_type("REAL") != nullptr && cfg.find_type("REAL")->func == 8);
|
||
CHECK(cfg.find_type("LREAL") != nullptr && cfg.find_type("LREAL")->func == 9);
|
||
CHECK(cfg.find_type("DATE") != nullptr && cfg.find_type("DATE")->func == 4);
|
||
CHECK(cfg.find_type("TOD") != nullptr && cfg.find_type("TOD")->func == 4);
|
||
CHECK(cfg.find_type("DT") != nullptr && cfg.find_type("DT")->func == 6);
|
||
CHECK(cfg.find_type("NOPE") == nullptr);
|
||
|
||
CHECK(cfg.ops().size() == 72);
|
||
const compiler::ConfigOp* move = cfg.find_op("MOVE");
|
||
CHECK(move != nullptr && move->prefix == "11" && move->op == 0 && move->fmt == "RR" &&
|
||
move->func_mode == "width" && move->params.size() == 2);
|
||
const compiler::ConfigOp* load = cfg.find_op("LOAD");
|
||
CHECK(load != nullptr && load->prefix == "010001" && load->fmt == "SLOT" &&
|
||
load->func_mode == "full");
|
||
const compiler::ConfigOp* cal = cfg.find_op("CAL");
|
||
CHECK(cal != nullptr && cal->prefix == "010101" && cal->fmt == "CAL" &&
|
||
cal->func_mode == "none" && cal->params.size() == 2);
|
||
CHECK(cfg.find_op_by_key("11", 0) != nullptr &&
|
||
cfg.find_op_by_key("11", 0)->name == "MOVE");
|
||
CHECK(cfg.find_op_by_key("010001", 1) != nullptr &&
|
||
cfg.find_op_by_key("010001", 1)->name == "STORE");
|
||
CHECK(cfg.op_enabled("11", 0) && cfg.op_enabled("010101", 0));
|
||
CHECK(!cfg.op_enabled("11", 63));
|
||
CHECK(cfg.find_op("NOPE") == nullptr);
|
||
|
||
CHECK(cfg.fbs().size() == 15);
|
||
const compiler::ConfigFb* ton = cfg.find_fb("TON");
|
||
CHECK(ton != nullptr && ton->fb_id == 0 && ton->fields.size() == 4);
|
||
CHECK(cfg.find_fb("DCTU") != nullptr && cfg.find_fb("DCTU")->fb_id == 4 &&
|
||
cfg.find_fb("DCTU")->fields[2].type == "DINT");
|
||
CHECK(cfg.find_fb_by_id(14) != nullptr && cfg.find_fb_by_id(14)->name == "RTC");
|
||
CHECK(cfg.find_fb_by_id(15) == nullptr);
|
||
|
||
// 基元表
|
||
CHECK(compiler::MachineConfig::find_prim("int16") != nullptr);
|
||
const compiler::PrimType* p = compiler::MachineConfig::find_prim("uint8");
|
||
CHECK(p != nullptr && p->width == 1 && !p->is_signed && !p->is_float);
|
||
CHECK(compiler::MachineConfig::find_prim("float64") != nullptr);
|
||
CHECK(compiler::MachineConfig::find_prim("bfloat16") == nullptr);
|
||
return true;
|
||
}
|
||
|
||
// ---- 2. 负例:V2 校验项 ----
|
||
|
||
static bool test_negative() {
|
||
const std::string m = "[meta]\nname = \"STATOR\"\nversion = 2\n";
|
||
// version != 2
|
||
if (!expect_load_err("mc_v2_bad1.toml",
|
||
"[meta]\nname = \"STATOR\"\nversion = 1\n" + std::string(kTypesAll) +
|
||
kOpsBasic + kFbsAll,
|
||
"version must be 2")) {
|
||
return false;
|
||
}
|
||
// type 缺全集(去掉 DT)
|
||
{
|
||
std::string types = kTypesAll;
|
||
const std::string dt = "[[type]]\nname = \"DT\"\nbase = \"uint64\"\nkind = \"date\"\nfunc = 6\n";
|
||
const size_t pos = types.find(dt);
|
||
types.erase(pos, dt.size());
|
||
if (!expect_load_err("mc_v2_bad2.toml", m + types + kOpsBasic + kFbsAll,
|
||
"missing 'DT'")) {
|
||
return false;
|
||
}
|
||
}
|
||
// base 未命中基元
|
||
{
|
||
std::string types = kTypesAll;
|
||
const std::string old = "[[type]]\nname = \"BYTE\"\nbase = \"uint8\"\nkind = \"bit\"\nfunc = 0\n";
|
||
const std::string bad = "[[type]]\nname = \"BYTE\"\nbase = \"bigint\"\nkind = \"bit\"\nfunc = 0\n";
|
||
types.replace(types.find(old), old.size(), bad);
|
||
if (!expect_load_err("mc_v2_bad3.toml", m + types + kOpsBasic + kFbsAll,
|
||
"unknown base")) {
|
||
return false;
|
||
}
|
||
}
|
||
// func 与 base 互锁破坏(INT func=0)
|
||
{
|
||
std::string types = kTypesAll;
|
||
const std::string old = "[[type]]\nname = \"INT\"\nbase = \"int16\"\nkind = \"int\"\nfunc = 3\n";
|
||
const std::string bad = "[[type]]\nname = \"INT\"\nbase = \"int16\"\nkind = \"int\"\nfunc = 0\n";
|
||
types.replace(types.find(old), old.size(), bad);
|
||
if (!expect_load_err("mc_v2_bad4.toml", m + types + kOpsBasic + kFbsAll,
|
||
"func 0 mismatches base")) {
|
||
return false;
|
||
}
|
||
}
|
||
// kind 非法
|
||
{
|
||
std::string types = kTypesAll;
|
||
const std::string old = "[[type]]\nname = \"BOOL\"\nbase = \"uint8\"\nkind = \"bool\"\nfunc = 0\n";
|
||
const std::string bad = "[[type]]\nname = \"BOOL\"\nbase = \"uint8\"\nkind = \"weird\"\nfunc = 0\n";
|
||
types.replace(types.find(old), old.size(), bad);
|
||
if (!expect_load_err("mc_v2_bad5.toml", m + types + kOpsBasic + kFbsAll,
|
||
"bad kind")) {
|
||
return false;
|
||
}
|
||
}
|
||
// prefix 非法
|
||
{
|
||
std::string ops = kOpsBasic;
|
||
const std::string old = "[[op]]\nname = \"MOVE\"\nprefix = \"11\"\nop = 0\nfmt = \"RR\"\nfunc = \"width\"\nparams = [\"rd\", \"rs\"]\nenabled = true\n";
|
||
const std::string bad = "[[op]]\nname = \"MOVE\"\nprefix = \"99\"\nop = 0\nfmt = \"RR\"\nfunc = \"width\"\nparams = [\"rd\", \"rs\"]\nenabled = true\n";
|
||
ops.replace(ops.find(old), old.size(), bad);
|
||
if (!expect_load_err("mc_v2_bad6.toml", m + kTypesAll + ops + kFbsAll,
|
||
"bad prefix")) {
|
||
return false;
|
||
}
|
||
}
|
||
// prefix-fmt 互锁破坏(11 + RRR)
|
||
{
|
||
std::string ops = kOpsBasic;
|
||
const std::string old = "[[op]]\nname = \"MOVE\"\nprefix = \"11\"\nop = 0\nfmt = \"RR\"\nfunc = \"width\"\nparams = [\"rd\", \"rs\"]\nenabled = true\n";
|
||
const std::string bad = "[[op]]\nname = \"MOVE\"\nprefix = \"11\"\nop = 0\nfmt = \"RRR\"\nfunc = \"width\"\nparams = [\"rd\", \"ra\", \"rb\"]\nenabled = true\n";
|
||
ops.replace(ops.find(old), old.size(), bad);
|
||
if (!expect_load_err("mc_v2_bad7.toml", m + kTypesAll + ops + kFbsAll,
|
||
"must pair with fmt")) {
|
||
return false;
|
||
}
|
||
}
|
||
// (prefix, op) 分区内重复
|
||
{
|
||
std::string ops = kOpsBasic;
|
||
ops += "[[op]]\nname = \"DUP\"\nprefix = \"11\"\nop = 0\nfmt = \"RR\"\nfunc = \"width\"\nparams = [\"a\", \"b\"]\nenabled = true\n";
|
||
if (!expect_load_err("mc_v2_bad8.toml", m + kTypesAll + ops + kFbsAll,
|
||
"duplicate (prefix, op)")) {
|
||
return false;
|
||
}
|
||
}
|
||
// func 类别非法
|
||
{
|
||
std::string ops = kOpsBasic;
|
||
const std::string old = "[[op]]\nname = \"MOVE\"\nprefix = \"11\"\nop = 0\nfmt = \"RR\"\nfunc = \"width\"\nparams = [\"rd\", \"rs\"]\nenabled = true\n";
|
||
const std::string bad = "[[op]]\nname = \"MOVE\"\nprefix = \"11\"\nop = 0\nfmt = \"RR\"\nfunc = \"magic\"\nparams = [\"rd\", \"rs\"]\nenabled = true\n";
|
||
ops.replace(ops.find(old), old.size(), bad);
|
||
if (!expect_load_err("mc_v2_bad9.toml", m + kTypesAll + ops + kFbsAll,
|
||
"bad func mode")) {
|
||
return false;
|
||
}
|
||
}
|
||
// params 数量与 fmt 不符(CAL 应为 2)
|
||
{
|
||
std::string ops = kOpsBasic;
|
||
const std::string old = "[[op]]\nname = \"CAL\"\nprefix = \"010101\"\nop = 0\nfmt = \"CAL\"\nfunc = \"none\"\nparams = [\"fb_id\", \"slot\"]\nenabled = true\n";
|
||
const std::string bad = "[[op]]\nname = \"CAL\"\nprefix = \"010101\"\nop = 0\nfmt = \"CAL\"\nfunc = \"none\"\nparams = [\"fb_id\"]\nenabled = true\n";
|
||
ops.replace(ops.find(old), old.size(), bad);
|
||
if (!expect_load_err("mc_v2_bad10.toml", m + kTypesAll + ops + kFbsAll,
|
||
"params count")) {
|
||
return false;
|
||
}
|
||
}
|
||
// fb 缺全集(去掉 RTC)
|
||
{
|
||
std::string fbs = kFbsAll;
|
||
const std::string rtc = "[[fb]]\nname = \"RTC\"\nfb_id = 14\nfields = [[\"enable\", \"BOOL\"], [\"date\", \"DATE\"], [\"tod\", \"TOD\"]]\n";
|
||
fbs.erase(fbs.find(rtc), rtc.size());
|
||
if (!expect_load_err("mc_v2_bad11.toml", m + kTypesAll + kOpsBasic + fbs,
|
||
"missing fb_id 14")) {
|
||
return false;
|
||
}
|
||
}
|
||
// fb 字段类型未知
|
||
{
|
||
std::string fbs = kFbsAll;
|
||
const std::string old = "[[\"in\", \"BOOL\"], [\"pt\", \"TIME\"]";
|
||
const std::string bad = "[[\"in\", \"NOPE\"], [\"pt\", \"TIME\"]";
|
||
fbs.replace(fbs.find(old), old.size(), bad);
|
||
if (!expect_load_err("mc_v2_bad12.toml", m + kTypesAll + kOpsBasic + fbs,
|
||
"unknown field type")) {
|
||
return false;
|
||
}
|
||
}
|
||
// 缺 CAL(op-fb 互锁)
|
||
{
|
||
std::string ops = kOpsBasic;
|
||
const std::string cal = "[[op]]\nname = \"CAL\"\nprefix = \"010101\"\nop = 0\nfmt = \"CAL\"\nfunc = \"none\"\nparams = [\"fb_id\", \"slot\"]\nenabled = true\n";
|
||
ops.erase(ops.find(cal), cal.size());
|
||
if (!expect_load_err("mc_v2_bad13.toml", m + kTypesAll + ops + kFbsAll,
|
||
"op-fb interlock")) {
|
||
return false;
|
||
}
|
||
}
|
||
// 语法错误
|
||
if (!expect_load_err("mc_v2_bad14.toml", "[meta\nname = \"S\"\n", "parse error")) {
|
||
return false;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
// ---- 3. 类型元数据(TypeInfo,V2)----
|
||
|
||
static bool test_type_meta() {
|
||
compiler::MachineConfig cfg;
|
||
std::string err;
|
||
CHECK(cfg.load(std::string(REPO_ROOT) + "/compiler/machine.toml", &err));
|
||
|
||
// BOOL:1 字节、无符号、kind bool、func 0
|
||
const compiler::TypeMeta b = compiler::type_meta(cfg, "BOOL");
|
||
CHECK(b && b.width() == 1 && !b.is_signed() && !b.is_float() && b.func() == 0);
|
||
CHECK(b.kind() == "bool");
|
||
// 大小写不敏感(Linker type_name 是小写)
|
||
const compiler::TypeMeta b2 = compiler::type_meta(cfg, "bool");
|
||
CHECK(b2 && b2.func() == 0 && b2.width() == 1);
|
||
|
||
// INT:2 字节、有符号、kind int、func 3
|
||
const compiler::TypeMeta i = compiler::type_meta(cfg, "int");
|
||
CHECK(i && i.width() == 2 && i.is_signed() && !i.is_float() && i.func() == 3);
|
||
CHECK(i.kind() == "int");
|
||
|
||
// REAL:4 字节、浮点、func 8;TOD:4 字节、func 4
|
||
const compiler::TypeMeta r = compiler::type_meta(cfg, "REAL");
|
||
CHECK(r && r.width() == 4 && r.is_float() && r.func() == 8);
|
||
const compiler::TypeMeta tod = compiler::type_meta(cfg, "TOD");
|
||
CHECK(tod && tod.width() == 4 && tod.func() == 4);
|
||
|
||
// 未定义类型 → 空
|
||
CHECK(!compiler::type_meta(cfg, "NOPE"));
|
||
CHECK(!compiler::type_meta(cfg, ""));
|
||
return true;
|
||
}
|
||
|
||
// ---- 4. SHA-256 已知向量 + 型号标识 ----
|
||
|
||
static bool test_sha256() {
|
||
{
|
||
uint8_t out[compiler::kSha256Size];
|
||
compiler::sha256(nullptr, 0, out);
|
||
const uint8_t want[32] = {0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
|
||
0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
|
||
0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
|
||
0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55};
|
||
CHECK(std::memcmp(out, want, 32) == 0);
|
||
}
|
||
{
|
||
const uint8_t abc[] = {'a', 'b', 'c'};
|
||
uint8_t out[compiler::kSha256Size];
|
||
compiler::sha256(abc, 3, out);
|
||
const uint8_t want[32] = {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
|
||
0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
|
||
0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
|
||
0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad};
|
||
CHECK(std::memcmp(out, want, 32) == 0);
|
||
}
|
||
// 型号标识:STATOR + 2 → "STATOR2" 补 '\0'
|
||
char mid[compiler::kModelIdSize];
|
||
compiler::fill_model_id("STATOR", 2, mid);
|
||
CHECK(std::strncmp(mid, "STATOR2", 7) == 0);
|
||
CHECK(mid[7] == '\0');
|
||
CHECK(mid[31] == '\0');
|
||
return true;
|
||
}
|
||
|
||
int main() {
|
||
if (!test_positive()) return 1;
|
||
if (!test_negative()) return 1;
|
||
if (!test_type_meta()) return 1;
|
||
if (!test_sha256()) return 1;
|
||
std::printf("machine_test: %d checks passed\n", g_checks);
|
||
return 0;
|
||
}
|