package jnpf.bizcommon.audit.service.value;
|
|
import jnpf.bizcommon.audit.entity.model.AuditFieldDiffViewVO;
|
|
import java.util.ArrayList;
|
import java.util.Arrays;
|
import java.util.Collections;
|
import java.util.LinkedHashMap;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Set;
|
|
/** userSelect 用户 id → 「真实姓名/账号」的批量解析、控件类型判据与租户边界探针。 */
|
public final class JnpfUserFieldValueResolverProbe {
|
|
private static int passed;
|
private static int failed;
|
|
public static void main(String[] args) {
|
CountingLookup lookup = new CountingLookup();
|
JnpfUserFieldValueResolver resolver = new JnpfUserFieldValueResolver(lookup);
|
|
List<AuditFieldDiffViewVO> fields = Arrays.asList(
|
field("tijiao_ren", "userSelect", "", "u-admin"),
|
field("fuhe_ren", "UserSelect", "u-admin", "u-ys"),
|
field("chouyang_ren", "userSelect", "", "[\"u-ys\",\"u-gone\"]"),
|
// 两个非 userSelect 干扰项刻意用**独有**的值:若用 u-admin 这种已被真实用户
|
// 字段收集过的 id,即便解析器错误地把它们也收进去,Set 去重后条数纹丝不动,
|
// 断言就成了永远转不红的摆设(L077 变体 5/8 同款陷阱)。
|
field("beizhu", "input", "", "u-only-in-beizhu"),
|
field("zhuangtai", "select", "", "u-only-in-zhuangtai"));
|
|
resolver.resolve(new AuditFieldValueContext("lims_ceshi_huichuan", "0", null), fields);
|
|
check("整批只查一次库", lookup.calls == 1, "calls=" + lookup.calls);
|
check("租户边界透传进查询", "0".equals(lookup.lastTenantId), String.valueOf(lookup.lastTenantId));
|
|
// 判据是控件类型不是字段名:非 userSelect 的列即便存着用户 id 也不碰,
|
// 否则会把恰好等于某个用户 id 的普通文本篡改成人名。
|
check("非 userSelect 控件不被解析",
|
fields.get(3).getNewDisplay() == null && fields.get(4).getNewDisplay() == null,
|
fields.get(3).getNewDisplay() + " / " + fields.get(4).getNewDisplay());
|
check("非 userSelect 控件的值不进 ID 收集",
|
lookup.requestedIds.equals(Arrays.asList("u-admin", "u-ys", "u-gone")),
|
lookup.requestedIds.toString());
|
|
check("展示格式为 realName/account", "管理员/admin".equals(fields.get(0).getNewDisplay()),
|
fields.get(0).getNewDisplay());
|
check("控件类型大小写不敏感", "yangsui/ys0001".equals(fields.get(1).getNewDisplay()),
|
fields.get(1).getNewDisplay());
|
check("oldData 与 newData 两侧都解析", "管理员/admin".equals(fields.get(1).getOldDisplay()),
|
fields.get(1).getOldDisplay());
|
check("空值解析成空串而不是「名称暂不可用」", "".equals(fields.get(0).getOldDisplay()),
|
fields.get(0).getOldDisplay());
|
check("多选按请求顺序解析,单项查不到才回落",
|
"yangsui/ys0001、名称暂不可用".equals(fields.get(2).getNewDisplay()),
|
fields.get(2).getNewDisplay());
|
|
// 前序解析器(表专用/字典)已经填过 display 的字段不重复查库——
|
// @Order 建立的优先级靠这个 if 才落得下去。
|
CountingLookup skipLookup = new CountingLookup();
|
AuditFieldDiffViewVO resolved = field("qingyan_ren", "userSelect", "", "u-admin");
|
resolved.setNewDisplay("管理员");
|
new JnpfUserFieldValueResolver(skipLookup).resolve(
|
new AuditFieldValueContext("lims_qingyandan", "0", null),
|
Collections.singletonList(resolved));
|
check("前序解析器已填的 display 不被覆盖,也不触发查库",
|
skipLookup.calls == 0 && "管理员".equals(resolved.getNewDisplay()),
|
skipLookup.calls + " / " + resolved.getNewDisplay());
|
|
// 租户拿不到时宁可不解析,也不做一次无边界的全库查询。
|
CountingLookup blankTenant = new CountingLookup();
|
new JnpfUserFieldValueResolver(blankTenant).resolve(
|
new AuditFieldValueContext("lims_ceshi_huichuan", "", null),
|
Collections.singletonList(field("tijiao_ren", "userSelect", "", "u-admin")));
|
check("空租户 fail-closed(不查库)", blankTenant.calls == 0,
|
String.valueOf(blankTenant.calls));
|
|
check("supports 对任意表恒为 true(userSelect 是平台控件)",
|
resolver.supports("lims_ceshi_huichuan") && resolver.supports("any_table")
|
&& resolver.supports(null),
|
"supports 收窄了适用表");
|
|
// 展示格式装配本身(验收标准「管理员/admin」的直接判据)
|
check("userDisplay 拼 realName/account",
|
"管理员/admin".equals(JnpfUserFieldValueResolver.userDisplay("管理员", "admin")),
|
JnpfUserFieldValueResolver.userDisplay("管理员", "admin"));
|
check("userDisplay 缺账号时不留孤零零斜杠",
|
"管理员".equals(JnpfUserFieldValueResolver.userDisplay("管理员", null))
|
&& "管理员".equals(JnpfUserFieldValueResolver.userDisplay("管理员", " ")),
|
JnpfUserFieldValueResolver.userDisplay("管理员", null));
|
check("userDisplay 缺姓名时退回账号",
|
"admin".equals(JnpfUserFieldValueResolver.userDisplay(null, "admin")),
|
JnpfUserFieldValueResolver.userDisplay(null, "admin"));
|
check("userDisplay 两边都空返回 null(调用方据此不入 map)",
|
JnpfUserFieldValueResolver.userDisplay(null, null) == null,
|
String.valueOf(JnpfUserFieldValueResolver.userDisplay(null, null)));
|
|
// @Order 常量的相对次序即解析优先级;数值写反会让通用解析器抢在表专用之前。
|
check("解析器优先级 表专用 < 字典 < 用户兜底",
|
LimsQingyandanFieldValueResolver.ORDER < JnpfDictionaryFieldValueResolver.ORDER
|
&& JnpfDictionaryFieldValueResolver.ORDER < JnpfUserFieldValueResolver.ORDER,
|
LimsQingyandanFieldValueResolver.ORDER + " / "
|
+ JnpfDictionaryFieldValueResolver.ORDER + " / "
|
+ JnpfUserFieldValueResolver.ORDER);
|
|
System.out.println("=== 用户字段解析断言:" + passed + " 通过 / " + failed + " 失败 ===");
|
System.exit(failed == 0 ? 0 : 1);
|
}
|
|
private static AuditFieldDiffViewVO field(String name, String componentType,
|
String oldData, String newData) {
|
AuditFieldDiffViewVO field = new AuditFieldDiffViewVO();
|
field.setField(name);
|
field.setComponentType(componentType);
|
field.setOldData(oldData);
|
field.setNewData(newData);
|
return field;
|
}
|
|
private static final class CountingLookup implements JnpfUserFieldValueResolver.UserLookup {
|
private int calls;
|
private String lastTenantId;
|
private final List<String> requestedIds = new ArrayList<>();
|
|
@Override
|
public Map<String, String> names(String tenantId, Set<String> ids) {
|
calls++;
|
lastTenantId = tenantId;
|
requestedIds.addAll(ids);
|
Map<String, String> result = new LinkedHashMap<>();
|
result.put("u-admin", "管理员/admin");
|
result.put("u-ys", "yangsui/ys0001");
|
return result; // u-gone 刻意缺席:模拟用户被删/查不到
|
}
|
}
|
|
private static void check(String name, boolean ok, String detail) {
|
if (ok) {
|
passed++;
|
System.out.println(" [PASS] " + name);
|
} else {
|
failed++;
|
System.out.println(" [FAIL] " + name + " -- " + detail);
|
}
|
}
|
|
private JnpfUserFieldValueResolverProbe() {
|
}
|
}
|