package cn.iocoder.yudao.module.qcreport.dal.dataobject.version;
|
|
import com.baomidou.mybatisplus.extension.handlers.Jackson3TypeHandler;
|
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.Test;
|
|
import java.lang.reflect.Field;
|
import java.util.List;
|
import java.util.Map;
|
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
|
/**
|
* Schema 读写兼容性测试。
|
* <p>
|
* 走的是生产同款读取路径——MyBatis-Plus 的 {@link Jackson3TypeHandler} 配
|
* {@code QcReportTemplateVersionDO.schema} 字段,而不是测试自己 new 一个 ObjectMapper,
|
* 因为要防的就是「反序列化读取」这条链路:{@code schema_json} 列里存的都是历史 JSON。
|
* <p>
|
* 契约 1.1 删掉了 dataSources / bindings / styles 三个从未使用的字段,库里已经存着带这三个键的
|
* 旧记录。这里守的是「旧 JSON 仍然读得出、且该有的字段一个不少」——出问题的表现是
|
* 「老模板点进去报系统异常」,只有存量数据会中招,事后很难查。
|
* <p>
|
* 它<b>不</b>负责证明 {@code ReportTemplateSchema} 上 {@code @JsonIgnoreProperties} 的必要性:
|
* 实测把那行注解去掉本测试照样通过(Jackson 3 默认就忽略未知属性)。
|
* 注解的意义写在那个类上,别把这条测试当成它的守卫。
|
*/
|
class ReportTemplateSchemaCompatibilityTest {
|
|
/** 1.0 时期存进去的 Schema:含已删除的三个字段,components 还是无类型的 Map */
|
private static final String LEGACY_JSON = """
|
{
|
"schemaVersion": "1.0",
|
"page": { "size": "A4", "orientation": "portrait", "margin": { "top": 12, "right": 8, "bottom": 12, "left": 8 } },
|
"grapes": { "pages": [ { "frames": [] } ] },
|
"components": [ { "id": "abc", "index": 0, "qualityType": "quality-table", "attributes": { "data-qc-repeat": "inspectionItems" } } ],
|
"dataSources": [],
|
"bindings": [],
|
"rules": [ { "id": "r1", "name": "实测值在规格内", "scope": "item", "expression": "item.actualValue >= item.lowerLimit", "enabled": true } ],
|
"styles": []
|
}""";
|
|
@Test
|
@DisplayName("含已删除字段的旧 Schema 仍能读出来(否则老模板打不开)")
|
void readsLegacySchemaWithRemovedFields() throws Exception {
|
ReportTemplateSchema schema = parse(LEGACY_JSON);
|
|
assertNotNull(schema);
|
assertEquals("1.0", schema.getSchemaVersion(), "旧记录的版本号要原样读出来,不能因为版本升级就丢掉");
|
assertEquals("A4", schema.getPage().getSize());
|
assertEquals(12.0, schema.getPage().getMargin().getTop().doubleValue());
|
assertFalse(schema.getGrapes().isEmpty(), "画布数据不能丢,丢了模板就只剩空壳");
|
|
List<ReportTemplateSchema.QualityComponentNode> components = schema.getComponents();
|
assertEquals(1, components.size());
|
assertEquals("quality-table", components.get(0).getQualityType());
|
assertEquals(0, components.get(0).getIndex().intValue());
|
assertEquals("inspectionItems", components.get(0).getAttributes().get("data-qc-repeat"));
|
|
assertEquals(1, schema.getRules().size(), "规则是设计器管不到的字段,读的时候绝不能少");
|
Map<String, Object> rule = schema.getRules().get(0);
|
assertEquals("item", rule.get("scope"));
|
assertEquals("item.actualValue >= item.lowerLimit", rule.get("expression"));
|
}
|
|
@Test
|
@DisplayName("写入再读出:当前格式往返不丢内容")
|
void roundTripsCurrentSchema() throws Exception {
|
ReportTemplateSchema schema = parse(LEGACY_JSON);
|
|
Jackson3TypeHandler handler = handler();
|
ReportTemplateSchema reloaded = (ReportTemplateSchema) handler.parse(handler.toJson(schema));
|
|
assertEquals(schema.getSchemaVersion(), reloaded.getSchemaVersion());
|
assertEquals("quality-table", reloaded.getComponents().get(0).getQualityType());
|
assertEquals("item.actualValue >= item.lowerLimit",
|
reloaded.getRules().get(0).get("expression"));
|
assertEquals(1, reloaded.getRules().size());
|
}
|
|
@Test
|
@DisplayName("缺字段的旧 Schema 也能读:只有 schemaVersion 不报错")
|
void readsSchemaMissingOptionalFields() throws Exception {
|
ReportTemplateSchema schema = parse("{\"schemaVersion\":\"1.0\"}");
|
|
assertEquals("1.0", schema.getSchemaVersion());
|
assertNull(schema.getPage());
|
assertNull(schema.getGrapes());
|
}
|
|
/** 走 MyBatis 实例化类型处理器的方式:带字段,genericType 一并带上 */
|
private static ReportTemplateSchema parse(String json) throws Exception {
|
return (ReportTemplateSchema) handler().parse(json);
|
}
|
|
private static Jackson3TypeHandler handler() throws NoSuchFieldException {
|
Field field = QcReportTemplateVersionDO.class.getDeclaredField("schema");
|
return new Jackson3TypeHandler(QcReportTemplateVersionDO.class, field);
|
}
|
|
}
|