package cn.iocoder.yudao.module.qcreport.engine; import cn.iocoder.yudao.module.qcreport.dal.dataobject.version.ReportTemplateSchema; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; /** * {@link QualityReportEngine#hasCanvas} 的判据测试。 *

* 这条判据同时守着两处:出报告弹窗要不要把这个模板摆出来({@code getSelectableTemplates}), * 以及出件前要不要直接拒绝({@code resolveVersion})。它必须与渲染器读画布的那一行 * ({@code pages[0].frames[0].component})严格一致——放宽一点,用户就会拿到一张不报错的白纸 PDF。 */ class QualityReportEngineTest { private static final ObjectMapper MAPPER = new ObjectMapper(); private static final String CANVAS_DIR = "qcreport/canvas/"; @Test @DisplayName("只有元数据的画布不算有内容:它是非空 Map,但渲染器取不到根组件,渲染出来是白纸") void metadataOnlyGrapesIsNotCanvas() { // GrapesJS 把「打开过设计器但一个组件都没放」的项目存成这个样子 assertFalse(QualityReportEngine.hasCanvas(schema(Map.of("assets", List.of(), "styles", List.of())))); // 只多了 pages 但没有 frames 也不行 assertFalse(QualityReportEngine.hasCanvas(schema(Map.of("pages", List.of())))); // 有 frame 但没有 component 同样不行 assertFalse(QualityReportEngine.hasCanvas(schema(Map.of("pages", List.of(Map.of("frames", List.of(Map.of("id", "f1")))))))); } @Test @DisplayName("frame 上有根组件才算有内容") void frameComponentIsCanvas() { assertTrue(QualityReportEngine.hasCanvas(schema(Map.of("pages", List.of(Map.of("frames", List.of(Map.of("component", Map.of("type", "wrapper", "components", List.of()))))))))); } @Test @DisplayName("Schema 或 grapes 为 null 不算有内容,且不抛错") void nullSchemaOrGrapesIsNotCanvas() { assertFalse(QualityReportEngine.hasCanvas(null)); assertFalse(QualityReportEngine.hasCanvas(new ReportTemplateSchema())); assertFalse(QualityReportEngine.hasCanvas(schema(null))); } @ParameterizedTest(name = "存量画布 {0} 有内容") @ValueSource(strings = {"canvas-t5-v1.0.json", "canvas-t3-v1.0.json", "canvas-t5-v1.1.json", "canvas-t5-v1.2.json"}) @DisplayName("运行库里真正画了东西的版本,判据为真") void realStoredCanvasIsCanvas(String fileName) throws IOException { assertTrue(QualityReportEngine.hasCanvas(schema(realGrapes(fileName))), fileName); } @ParameterizedTest(name = "存量空画布 {0} 无内容") @ValueSource(strings = {"canvas-t1-v1.0.json", "canvas-t1-v1.1.json"}) @DisplayName("运行库里「打开过但没放组件」的版本,判据为假(它就是白纸 PDF 的来源)") void realStoredEmptyCanvasIsNotCanvas(String fileName) throws IOException { assertFalse(QualityReportEngine.hasCanvas(schema(realGrapes(fileName))), fileName); } private static ReportTemplateSchema schema(Map grapes) { ReportTemplateSchema schema = new ReportTemplateSchema(); schema.setGrapes(grapes); return schema; } @SuppressWarnings("unchecked") private static Map realGrapes(String fileName) throws IOException { String path = CANVAS_DIR + fileName; try (InputStream in = QualityReportEngineTest.class.getClassLoader().getResourceAsStream(path)) { if (in == null) { throw new IOException("找不到画布夹具:" + path); } Map full = MAPPER.readValue(new String(in.readAllBytes(), StandardCharsets.UTF_8), new TypeReference>() { }); Object grapes = full.get("grapes"); return grapes instanceof Map ? (Map) grapes : null; } } }