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 前置条件 ④)。
|
*
|
* <p>为什么必须有它,且必须是**纯 JVM**:这块的错法是「静默地少一个 key」——
|
* 端到端跑不出红,只会在前端把字典字段的存储原值当明文渲染出来,
|
* 而那种问题要等到有人盯着页面看才发现。D1 正是这么发现旧实现少了四个键的。
|
*
|
* <p>两个方向都要钉住,缺一不可:
|
* <ul>
|
* <li><b>有元数据时键要出现且值要对</b>——否则补了等于没补;</li>
|
* <li><b>没有元数据时键要「整个不出现」</b>(层 1 恒传 null)——否则层 1 的 190 条既有断言
|
* 会因形状变化而红,而它的语义一点没变。这是本次改动**唯一**的回归面,
|
* 所以断言写在这里而不是靠「应该不影响」的推断。</li>
|
* </ul>
|
*
|
* <p>退出码: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<String, Object> row(Object... kv) {
|
Map<String, Object> 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<String> masked(String... cols) {
|
return new LinkedHashSet<>(Arrays.asList(cols));
|
}
|
|
public static void main(String[] args) {
|
System.out.println("=== 层 0 field_diffs 展示元数据(jnpfKey / nameModified)===");
|
|
Map<String, Object> before = row("qingyan_leixing", "CP", "beizhu", "旧");
|
Map<String, Object> 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<String, AuditFieldDiff.FieldMeta> 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<String, AuditFieldDiff.FieldMeta> 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<String, AuditFieldDiff.FieldMeta> 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() {
|
}
|
}
|