package jnpf.bizcommon.audit.service.title;
import java.util.List;
/**
* 表单勾选({@code __config__.biz_log_enabled})解析的纯 JVM 回归网。
*
*
为什么不复用 {@code AuditFormRegistry.collectFields}:它递归时把子表 children
* 拍平进同一个 map,天生分不出主表/子表;而它被 {@code resolveFieldMetadata} 与
* {@code resolveBaselineFields} 两条已验证路径依赖、压着 {@code AuditL0PartialSnapshotProbe}
* 的 46 条断言。标题是新语义,另起纯函数,风险隔离。
*
*
本组管的错法:顺序被打乱(业务勾 a/c 显示成 c/a)、子表字段混进主表标题、
* 布局容器(栅格/标签页)里的字段被漏掉。这三种端到端都只表现为"标题看着不太对",
* 没有报错、没有日志,只能靠断言钉死。
*
*
runner:{@code tasks/audit-title-spec-checks.sh}
*/
public final class AuditTitleSpecProbe {
private static int pass;
private static int fail;
public static void main(String[] args) {
noneEnabled();
mainFieldsKeepFormOrder();
layoutContainersAreTraversed();
subTableIsSeparated();
subTableFieldsNeverLeakIntoMain();
malformedInputDegradesToEmpty();
System.out.println("=== 表单勾选解析断言:" + pass + " 通过 / " + fail + " 失败 ===");
if (fail > 0) {
System.exit(1);
}
}
/** T1 一个都没勾 → EMPTY。这是当前库里 148 份表单的真实状态,必须是安全默认。 */
private static void noneEnabled() {
String json = "{\"fields\":["
+ field("a", "input", false)
+ "," + field("b", "input", false)
+ "]}";
AuditTitleSpec spec = AuditTitleSpecParser.parse(json);
check("T1 一个都没勾 → isEmpty", spec.isEmpty(), "勾选为空时不应产出任何标题字段");
}
/** T2 顺序必须是表单出现顺序,不是字母序——业务勾 a/c 就得是 a/c。 */
private static void mainFieldsKeepFormOrder() {
String json = "{\"fields\":["
+ field("zebra", "input", true)
+ "," + field("apple", "input", true)
+ "," + field("mango", "input", false)
+ "]}";
List main = AuditTitleSpecParser.parse(json).mainFields();
check("T2 只收勾选字段", main.size() == 2, "实际 " + main);
check("T2 保持表单顺序(非字母序)",
"zebra".equals(main.get(0)) && "apple".equals(main.get(1)),
"实际 " + main);
}
/** T3 栅格/标签页这类布局容器的 children 是主表字段,必须继续递归。 */
private static void layoutContainersAreTraversed() {
String json = "{\"fields\":[{\"__config__\":{\"jnpfKey\":\"row\",\"children\":["
+ field("inside", "input", true)
+ "]}}]}";
List main = AuditTitleSpecParser.parse(json).mainFields();
check("T3 布局容器内的勾选字段被收进主表",
main.size() == 1 && "inside".equals(main.get(0)), "实际 " + main);
}
/** T4 子表控件独立成组,带上表名。 */
private static void subTableIsSeparated() {
String json = "{\"fields\":["
+ field("main1", "input", true)
+ ",{\"__vModel__\":\"tableField6da682\",\"__config__\":{\"jnpfKey\":\"table\","
+ "\"tableName\":\"lims_jianyan_xiang\",\"children\":["
+ field("sub1", "input", true)
+ "," + field("sub2", "input", false)
+ "," + field("sub3", "input", true)
+ "]}}]}";
AuditTitleSpec spec = AuditTitleSpecParser.parse(json);
check("T4 主表只有 main1",
spec.mainFields().size() == 1 && "main1".equals(spec.mainFields().get(0)),
"实际 " + spec.mainFields());
check("T4 识别出 1 个子表", spec.subTables().size() == 1,
"实际 " + spec.subTables().size());
AuditTitleSpec.SubTableSpec sub = spec.subTables().get(0);
check("T4 子表 vModel", "tableField6da682".equals(sub.vModel()), "实际 " + sub.vModel());
check("T4 子表表名", "lims_jianyan_xiang".equals(sub.tableName()), "实际 " + sub.tableName());
check("T4 子表勾选字段按顺序",
sub.fields().size() == 2 && "sub1".equals(sub.fields().get(0))
&& "sub3".equals(sub.fields().get(1)),
"实际 " + sub.fields());
}
/** T5 子表字段绝不能出现在主表标题里——否则主表那一行会混进子表的值。 */
private static void subTableFieldsNeverLeakIntoMain() {
String json = "{\"fields\":[{\"__vModel__\":\"tf1\",\"__config__\":{\"jnpfKey\":\"table\","
+ "\"tableName\":\"t_sub\",\"children\":[" + field("leaky", "input", true) + "]}}]}";
AuditTitleSpec spec = AuditTitleSpecParser.parse(json);
check("T5 子表字段不进主表", spec.mainFields().isEmpty(),
"主表混入了子表字段:" + spec.mainFields());
}
/** T6 非法/空输入一律退化成 EMPTY,绝不抛异常——层 0 的 handler 外层虽有兜底,但那会丢整条事件。 */
private static void malformedInputDegradesToEmpty() {
check("T6 null 输入", AuditTitleSpecParser.parse(null).isEmpty(), "应为 EMPTY");
check("T6 空串输入", AuditTitleSpecParser.parse(" ").isEmpty(), "应为 EMPTY");
check("T6 非法 JSON", AuditTitleSpecParser.parse("{not json").isEmpty(), "应为 EMPTY");
check("T6 没有 fields 键", AuditTitleSpecParser.parse("{\"x\":1}").isEmpty(), "应为 EMPTY");
}
private static String field(String vModel, String jnpfKey, boolean enabled) {
return "{\"__vModel__\":\"" + vModel + "\",\"__config__\":{\"jnpfKey\":\"" + jnpfKey
+ "\",\"biz_log_enabled\":" + enabled + "}}";
}
private static void check(String name, boolean ok, String detail) {
if (ok) {
pass++;
System.out.println(" ✅ " + name);
} else {
fail++;
System.out.println(" ❌ " + name + " —— " + detail);
}
}
}