test(tools): 行数组不变式收紧为"18 个全部等于行数"
背景:`AppendRow()`(提交 85aaed5)已经成为新增面板行的唯一入口, 18 个平行数组由它一次补齐。因此旧的宽松判据("13 个必须等长 + 4 个重采样专属列允许为空")不再需要 —— 任何一列短于行数, 就是"有人绕过 AppendRow 手写 push"的直接证据。 改动: * `panels` 检查:改为断言 18 个数组长度**全部**等于 `rowRefs.size()`, 失败时打印全部 18 列的长度便于定位。 * `panelscroll` 检查:同样收紧(大文件 566 行时才会暴露的问题)。 * `Tools/README.md`:同步不变式描述。 文档: * `Documents/Code_Review_Plan.md` 新增 §八(第 36 轮节点与硬约束)。 * `Documents/Code_Review_Progress.md` 新增第 36 轮(两次重构 + 三个搬移陷阱)。 * `Documents/Code_Review_Report.md` 新增 §13(拆分职责表、为何不做完整合并、 失败可见性对比、后续建议)。 * `Documents/agent_mem.md` 新增第 36 轮规则。 验证: * `make release` 全量零 error / 零 warning,产物 **785,408 B**。 * `UnitTests` → checks=260 failed=0;`OffscreenChecks -all` → 6/6 PASS,checks=101 failed=0。 * `panels -mode compare` → 7 个面板像素哈希与几何逐项不变。 * `panelscroll`(MF4 566 行)→ 18 个行数组全部 = 566。
This commit is contained in:
1 parent
85aaed55f6
commit
221f9d2410
6 files changed
+260
-35
No files matched your search
@@ -418,22 +418,23 @@ namespace jdi
|
||||
Expect(inside, std::string("panel inside plot area: ") + PanelKindName(kind));
|
||||
|
||||
// 不变式:`EdgePanelLayout` 的**平行数组长度必须全部等于行数**。
|
||||
// 这 13 个按行平行的 vector 每个分支都要按同一顺序 push 恰好 13 项,
|
||||
// 漏一项就会让某一列读到别的行的矩形("改布局就出错"的典型机制)。
|
||||
// ⚠️ 「重采样」专属的 4 个数组(最大/最小间隔、间隔/频率输入框)在**其它**
|
||||
// 面板里允许为空(没人读),但只要非空就必须同样与行数对齐。
|
||||
// 这 18 个按行平行的 vector 现在由 `AppendRow()` 一次补齐
|
||||
//(新增行的唯一入口),因此**不允许**任何一列短于行数 ——
|
||||
// 短了就说明有分支绕过 `AppendRow` 手写 push("某列读到别人矩形"的根因)。
|
||||
// 成本极低(O(1) 比长度),但能挡住整类错位缺陷。
|
||||
const std::size_t rowCount = layout.rowRefs.size();
|
||||
const std::size_t coreSizes[] = {
|
||||
layout.rowRefs.size(), layout.rowHeaders.size(),
|
||||
layout.rowNameRects.size(), layout.rowTriangles.size(),
|
||||
layout.rowChecks.size(), layout.rowPoints.size(),
|
||||
layout.rowIterations.size(), layout.rowStats.size(),
|
||||
layout.rowLevelTracks.size(), layout.rowLevelValues.size(),
|
||||
layout.rowLevelResets.size(), layout.rowIterTracks.size(),
|
||||
layout.rowIterValues.size(), layout.rowIterResets.size()};
|
||||
const std::size_t parallelSizes[] = {
|
||||
layout.rowRefs.size(), layout.rowHeaders.size(),
|
||||
layout.rowNameRects.size(), layout.rowTriangles.size(),
|
||||
layout.rowChecks.size(), layout.rowPoints.size(),
|
||||
layout.rowIterations.size(), layout.rowStats.size(),
|
||||
layout.rowLevelTracks.size(), layout.rowLevelValues.size(),
|
||||
layout.rowLevelResets.size(), layout.rowIterTracks.size(),
|
||||
layout.rowIterValues.size(), layout.rowIterResets.size(),
|
||||
layout.rowInfoMaxInterval.size(), layout.rowInfoMinInterval.size(),
|
||||
layout.rowIntervalField.size(), layout.rowFrequencyField.size()};
|
||||
bool parallel = true;
|
||||
for (const std::size_t size : coreSizes)
|
||||
for (const std::size_t size : parallelSizes)
|
||||
{
|
||||
if (size != rowCount)
|
||||
{
|
||||
@@ -441,19 +442,7 @@ namespace jdi
|
||||
break;
|
||||
}
|
||||
}
|
||||
const std::size_t resampleSizes[] = {
|
||||
layout.rowInfoMaxInterval.size(), layout.rowInfoMinInterval.size(),
|
||||
layout.rowIntervalField.size(), layout.rowFrequencyField.size()};
|
||||
bool resampleParallel = true;
|
||||
for (const std::size_t size : resampleSizes)
|
||||
{
|
||||
if (size != 0 && size != rowCount)
|
||||
{
|
||||
resampleParallel = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!parallel || !resampleParallel)
|
||||
if (!parallel)
|
||||
{
|
||||
EmitLine("[panels] %s row arrays: refs=%d hdr=%d name=%d tri=%d chk=%d pts=%d it=%d "
|
||||
"stat=%d lvl=%d/%d/%d iter=%d/%d/%d info=%d/%d fld=%d/%d\n",
|
||||
@@ -476,9 +465,7 @@ namespace jdi
|
||||
static_cast<int>(layout.rowIntervalField.size()),
|
||||
static_cast<int>(layout.rowFrequencyField.size()));
|
||||
}
|
||||
Expect(parallel, std::string("row arrays have identical lengths: ") + PanelKindName(kind));
|
||||
Expect(resampleParallel,
|
||||
std::string("resample row arrays empty-or-aligned: ") + PanelKindName(kind));
|
||||
Expect(parallel, std::string("all 18 row arrays match row count: ") + PanelKindName(kind));
|
||||
|
||||
char buffer[160] = {};
|
||||
std::snprintf(buffer, sizeof(buffer), "%s=%016llX,%d,%d,%d,%d\n", PanelKindName(kind),
|
||||
@@ -605,7 +592,8 @@ namespace jdi
|
||||
initial.scrollTrack.Width > 0.0f ? 1 : 0,
|
||||
static_cast<int>(initial.rowRefs.size()));
|
||||
|
||||
// 多信号场景下额外守住"平行数组长度一致"(本轮新增,成本 O(1))。
|
||||
// 多信号场景下额外守住"18 个平行数组长度全部等于行数"
|
||||
//(`AppendRow()` 是新增行的唯一入口 ⇒ 任何一列短了就是绕过它的证据)。
|
||||
{
|
||||
const std::size_t rows = initial.rowRefs.size();
|
||||
const std::size_t sizes[] = {initial.rowHeaders.size(), initial.rowNameRects.size(),
|
||||
@@ -621,14 +609,13 @@ namespace jdi
|
||||
bool aligned = true;
|
||||
for (const std::size_t size : sizes)
|
||||
{
|
||||
// 「重采样」专属数组在其它面板允许为空(见 `panels` 检查的说明)。
|
||||
if (size != rows && size != 0)
|
||||
if (size != rows)
|
||||
{
|
||||
aligned = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Expect(aligned, std::string("row arrays aligned with rows: ") + name);
|
||||
Expect(aligned, std::string("all 18 row arrays match row count: ") + name);
|
||||
}
|
||||
|
||||
if (maxScroll <= 1.0f)
|
||||
|
||||
Reference in new issue
Block a user