package jnpf.bizcommon.audit.service; import jnpf.audit.diff.AuditFieldDiff; import java.util.Arrays; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; /** * 层 0 {@code field_diffs} **展示元数据**的断言探针(D1 前置条件 ④)。 * *

为什么必须有它,且必须是**纯 JVM**:这块的错法是「静默地少一个 key」—— * 端到端跑不出红,只会在前端把字典字段的存储原值当明文渲染出来, * 而那种问题要等到有人盯着页面看才发现。D1 正是这么发现旧实现少了四个键的。 * *

两个方向都要钉住,缺一不可: *

* *

退出码:0 = 全绿 / 1 = 有断言失败。不连库、不起容器。 */ public final class AuditL0FieldMetaProbe { private static int pass = 0; private static int fail = 0; private static void ok(String name) { System.out.println(" [PASS] " + name); pass++; } private static void bad(String name, String detail) { System.out.println(" [FAIL] " + name + " —— " + detail); fail++; } private static void assertContains(String name, String json, String needle) { if (json != null && json.contains(needle)) { ok(name); } else { bad(name, "期望出现 " + needle + ",实际=" + json); } } private static void assertAbsent(String name, String json, String needle) { if (json == null || !json.contains(needle)) { ok(name); } else { bad(name, "期望**不**出现 " + needle + ",实际=" + json); } } private static Map row(Object... kv) { Map m = new LinkedHashMap<>(); for (int i = 0; i < kv.length; i += 2) { m.put(String.valueOf(kv[i]), kv[i + 1]); } return m; } private static Set masked(String... cols) { return new LinkedHashSet<>(Arrays.asList(cols)); } public static void main(String[] args) { System.out.println("=== 层 0 field_diffs 展示元数据(jnpfKey / nameModified)==="); Map before = row("qingyan_leixing", "CP", "beizhu", "旧"); Map after = row("qingyan_leixing", "YL", "beizhu", "新"); // ── A 组:层 1 路径(meta=null)—— 新键必须「整个不出现」 ──────────────────── // 这一组是本次改动唯一的回归面:层 1 没有表单模型、恒传 null, // 若无条件补上 "jnpfKey":null 之类,它的 190 条既有断言会因形状变化而红。 String noMeta = AuditFieldDiff.diff(before, after, masked()); assertAbsent("A1 层1 路径(3 参重载)不出现 jnpfKey 键", noMeta, "jnpfKey"); assertAbsent("A2 层1 路径(3 参重载)不出现 nameModified 键", noMeta, "nameModified"); assertContains("A3 层1 路径 fieldName 仍回落成字段名", noMeta, "\"fieldName\":\"qingyan_leixing\""); String nullMeta = AuditFieldDiff.diff(before, after, masked(), null); assertAbsent("A4 显式传 null meta(4 参重载)同样不出现 jnpfKey", nullMeta, "jnpfKey"); if (noMeta.equals(nullMeta)) { ok("A5 3 参与 4 参传 null 的输出逐字符相同(层1 换重载也不会漂)"); } else { bad("A5 3 参与 4 参传 null 输出应相同", noMeta + " vs " + nullMeta); } // ── B 组:有元数据 —— 键要出现、值要对 ────────────────────────────────── Map meta = new LinkedHashMap<>(); meta.put("qingyan_leixing", new AuditFieldDiff.FieldMeta("请验类型", "select", Boolean.TRUE)); meta.put("beizhu", new AuditFieldDiff.FieldMeta("备注", "textarea", Boolean.FALSE)); String withMeta = AuditFieldDiff.diff(before, after, masked(), meta); assertContains("B1 带 jnpfKey", withMeta, "\"jnpfKey\":\"select\""); assertContains("B2 带 nameModified=true(字典字段前端只显示「已修改」)", withMeta, "\"nameModified\":true"); assertContains("B3 nameModified=false 也如实带上(不是省略)", withMeta, "\"nameModified\":false"); assertContains("B4 中文标签仍然生效", withMeta, "\"fieldName\":\"请验类型\""); // ── C 组:元数据缺项时逐键降级,不整块丢 ─────────────────────────────── Map partial = new LinkedHashMap<>(); partial.put("qingyan_leixing", new AuditFieldDiff.FieldMeta("请验类型", null, null)); String partialJson = AuditFieldDiff.diff(before, after, masked(), partial); assertContains("C1 只有标签时 fieldName 生效", partialJson, "\"fieldName\":\"请验类型\""); assertAbsent("C2 jnpfKey 为 null 时该键不出现(不是 \"jnpfKey\":null)", partialJson, "jnpfKey"); assertAbsent("C3 nameModified 为 null 时该键不出现", partialJson, "nameModified"); // 同一次 diff 里另一个字段完全没登记 → 只影响它自己 assertContains("C4 未登记的字段回落成字段名,不受同批其他字段影响", partialJson, "\"fieldName\":\"beizhu\""); // ── D 组:与脱敏共存 ─────────────────────────────────────────────────── // 两者管的是不同的事:脱敏 = 值不记;nameModified = 值不展示。同时成立时 // 前端显示「已修改」而不是 `***`,语义更准,故**脱敏列上照样带 nameModified**。 Map maskedMeta = new LinkedHashMap<>(); maskedMeta.put("sign_password", new AuditFieldDiff.FieldMeta("签名密码", "password", Boolean.TRUE)); String maskedJson = AuditFieldDiff.diff( row("sign_password", "old"), row("sign_password", "new"), masked("sign_password"), maskedMeta); assertContains("D1 脱敏列的值仍是占位符", maskedJson, "\"oldData\":\"***\""); assertContains("D2 脱敏列照样带 nameModified(脱敏管不记值、它管不展示)", maskedJson, "\"nameModified\":true"); assertContains("D3 脱敏列 type 恒为 1(B5 评审 M-3,存在性也不给)", maskedJson, "\"type\":1"); // ── E 组:子表控件 —— 本层判不了,必须能被识别出来留痕 ────────────────── if (AuditFieldDiff.JNPF_KEY_TABLE.equals("table")) { ok("E1 子表控件常量与前端 DataLogList.vue 的判据字面量一致('table')"); } else { bad("E1 子表控件常量应为 'table'", AuditFieldDiff.JNPF_KEY_TABLE); } System.out.println(); System.out.println("=== 层 0 展示元数据断言:" + pass + " 通过 / " + fail + " 失败 ==="); System.exit(fail == 0 ? 0 : 1); } private AuditL0FieldMetaProbe() { } }