Files
schemaCheck/src/test/java/com/codechecker/cache/diff/SchemaDifferTest.java
dongzi 14f9f1fce7
All checks were successful
序列化结构检查 / serialization-schema-check (push) Has been skipped
feat: 1、Vo包装识别增强 2、去除 位置&类型 的色块
2026-07-15 15:45:35 +08:00

151 lines
7.1 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package com.codechecker.cache.diff;
import com.codechecker.cache.schema.FieldSchema;
import com.codechecker.cache.schema.JsonType;
import com.codechecker.cache.schema.TypeSchema;
import org.junit.jupiter.api.Test;
import java.util.List;
import java.util.stream.Collectors;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
class SchemaDifferTest {
@Test
void detectsWrapperMoveAndAddition() {
TypeSchema oldS = new TypeSchema("TenantVO");
oldS.add(new FieldSchema("dbName", JsonType.STRING, "String"));
oldS.add(new FieldSchema("linkList", JsonType.ARRAY, "List"));
oldS.add(new FieldSchema("linkList[]", JsonType.OBJECT, "TenantLinkModel"));
oldS.add(new FieldSchema("linkList[].id", JsonType.STRING, "String"));
TypeSchema newS = new TypeSchema("CacheEnvelope");
newS.add(new FieldSchema("vo", JsonType.OBJECT, "TenantVO"));
newS.add(new FieldSchema("vo.dbName", JsonType.STRING, "String"));
newS.add(new FieldSchema("vo.linkList", JsonType.ARRAY, "List"));
newS.add(new FieldSchema("vo.linkList[]", JsonType.OBJECT, "TenantLinkModel"));
newS.add(new FieldSchema("vo.linkList[].id", JsonType.STRING, "String"));
newS.add(new FieldSchema("expiresAtMs", JsonType.NUMBER, "Long"));
List<SchemaChange> changes = new SchemaDiffer().diff(oldS, newS);
List<ChangeType> types = changes.stream().map(SchemaChange::getChangeType).collect(Collectors.toList());
assertTrue(types.contains(ChangeType.WRAPPER_ADDED), "应检测到包装层新增");
assertTrue(types.contains(ChangeType.FIELD_PATH_MOVED), "应检测到字段路径迁移");
assertTrue(types.contains(ChangeType.FIELD_ADDED), "应检测到新增字段 expiresAtMs");
long moved = changes.stream().filter(c -> c.getChangeType() == ChangeType.FIELD_PATH_MOVED).count();
assertEquals(2, moved, "dbName 与 linkList[].id 均应迁移");
}
@Test
void detectsWrapperRemovalAndUpwardMoves() {
TypeSchema oldS = new TypeSchema("CacheEnvelope");
oldS.add(new FieldSchema("vo", JsonType.OBJECT, "TenantVO"));
oldS.add(new FieldSchema("vo.dbName", JsonType.STRING, "String"));
oldS.add(new FieldSchema("vo.linkList", JsonType.ARRAY, "List"));
oldS.add(new FieldSchema("vo.linkList[]", JsonType.OBJECT, "TenantLinkModel"));
oldS.add(new FieldSchema("vo.linkList[].id", JsonType.STRING, "String"));
TypeSchema newS = new TypeSchema("TenantVO");
newS.add(new FieldSchema("dbName", JsonType.STRING, "String"));
newS.add(new FieldSchema("linkList", JsonType.ARRAY, "List"));
newS.add(new FieldSchema("linkList[]", JsonType.OBJECT, "TenantLinkModel"));
newS.add(new FieldSchema("linkList[].id", JsonType.STRING, "String"));
List<SchemaChange> changes = new SchemaDiffer().diff(oldS, newS);
List<ChangeType> types = changes.stream().map(SchemaChange::getChangeType).collect(Collectors.toList());
assertTrue(types.contains(ChangeType.WRAPPER_REMOVED), "应检测到包装层删除");
assertTrue(types.contains(ChangeType.FIELD_PATH_MOVED), "应检测到字段上提迁移");
assertTrue(types.stream().noneMatch(t -> t == ChangeType.FIELD_ADDED),
"上提字段不应再被当成新增");
assertTrue(types.stream().noneMatch(t -> t == ChangeType.FIELD_REMOVED),
"上提字段不应再被当成删除");
SchemaChange wrapper = changes.stream()
.filter(c -> c.getChangeType() == ChangeType.WRAPPER_REMOVED)
.findFirst()
.orElseThrow(IllegalStateException::new);
assertEquals("vo", wrapper.getFieldPath());
long moved = changes.stream().filter(c -> c.getChangeType() == ChangeType.FIELD_PATH_MOVED).count();
assertEquals(2, moved, "vo.dbName / vo.linkList[].id 均应上提");
}
@Test
void detectsTypeChange() {
TypeSchema oldS = new TypeSchema("A");
oldS.add(new FieldSchema("count", JsonType.STRING, "String"));
TypeSchema newS = new TypeSchema("A");
newS.add(new FieldSchema("count", JsonType.NUMBER, "Integer"));
List<SchemaChange> changes = new SchemaDiffer().diff(oldS, newS);
assertEquals(1, changes.size());
assertEquals(ChangeType.TYPE_CHANGED, changes.get(0).getChangeType());
assertEquals(Severity.P0, changes.get(0).getSeverity());
assertTrue(changes.get(0).getMessage().contains("String"));
assertTrue(changes.get(0).getMessage().contains("Integer"));
}
@Test
void detectsBigDecimalToStringEvenWhenBothWereStringBucketHistorically() {
// 即便 JsonType 同为 STRINGjavaType 变化也必须检出(用户真实漏报场景)
TypeSchema oldS = new TypeSchema("A");
oldS.add(new FieldSchema("amount", JsonType.STRING, "BigDecimal"));
TypeSchema newS = new TypeSchema("A");
newS.add(new FieldSchema("amount", JsonType.STRING, "String"));
List<SchemaChange> changes = new SchemaDiffer().diff(oldS, newS);
assertEquals(1, changes.size());
assertEquals(ChangeType.TYPE_CHANGED, changes.get(0).getChangeType());
assertEquals("amount", changes.get(0).getFieldPath());
assertTrue(changes.get(0).getOldValue().contains("BigDecimal"));
assertTrue(changes.get(0).getNewValue().contains("String"));
}
@Test
void detectsBigDecimalToStringViaJsonTypeAndJavaType() {
TypeSchema oldS = new TypeSchema("A");
oldS.add(new FieldSchema("amount", JsonType.NUMBER, "BigDecimal"));
TypeSchema newS = new TypeSchema("A");
newS.add(new FieldSchema("amount", JsonType.STRING, "String"));
List<SchemaChange> changes = new SchemaDiffer().diff(oldS, newS);
assertEquals(1, changes.size());
assertEquals(ChangeType.TYPE_CHANGED, changes.get(0).getChangeType());
}
@Test
void detectsIntegerToLongWithinNumberBucket() {
TypeSchema oldS = new TypeSchema("A");
oldS.add(new FieldSchema("id", JsonType.NUMBER, "Integer"));
TypeSchema newS = new TypeSchema("A");
newS.add(new FieldSchema("id", JsonType.NUMBER, "Long"));
List<SchemaChange> changes = new SchemaDiffer().diff(oldS, newS);
assertEquals(1, changes.size());
assertEquals(ChangeType.TYPE_CHANGED, changes.get(0).getChangeType());
}
@Test
void noChangeWhenPrimitiveAndWrapperEquivalent() {
TypeSchema a = new TypeSchema("A");
a.add(new FieldSchema("n", JsonType.NUMBER, "int"));
TypeSchema b = new TypeSchema("A");
b.add(new FieldSchema("n", JsonType.NUMBER, "Integer"));
assertTrue(new SchemaDiffer().diff(a, b).isEmpty());
}
@Test
void noChangeWhenIdentical() {
TypeSchema a = new TypeSchema("A");
a.add(new FieldSchema("x", JsonType.STRING, "String"));
TypeSchema b = new TypeSchema("A");
b.add(new FieldSchema("x", JsonType.STRING, "String"));
assertTrue(new SchemaDiffer().diff(a, b).isEmpty());
}
}