package jnpf.bizcommon.audit.service.title;
|
|
import java.util.List;
|
|
/**
|
* 表单勾选({@code __config__.biz_log_enabled})解析的纯 JVM 回归网。
|
*
|
* <p><b>为什么不复用 {@code AuditFormRegistry.collectFields}</b>:它递归时把子表 children
|
* 拍平进同一个 map,天生分不出主表/子表;而它被 {@code resolveFieldMetadata} 与
|
* {@code resolveBaselineFields} 两条已验证路径依赖、压着 {@code AuditL0PartialSnapshotProbe}
|
* 的 46 条断言。标题是新语义,另起纯函数,风险隔离。
|
*
|
* <p><b>本组管的错法</b>:顺序被打乱(业务勾 a/c 显示成 c/a)、子表字段混进主表标题、
|
* 布局容器(栅格/标签页)里的字段被漏掉。这三种端到端都只表现为"标题看着不太对",
|
* 没有报错、没有日志,只能靠断言钉死。
|
*
|
* <p>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<String> 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<String> 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);
|
}
|
}
|
}
|