package cn.iocoder.yudao.module.mes.framework.qrcode; import cn.iocoder.yudao.framework.common.exception.ServiceException; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO; import cn.iocoder.yudao.module.mes.framework.config.MesTraceConfigSnapshot; import cn.iocoder.yudao.module.mes.framework.config.MesTraceUrlSource; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import java.util.Map; import static org.junit.jupiter.api.Assertions.*; /** * 标签构建器的配置来源测试。 *

* 构建器是静态工具类,配置来源通过 {@link MesTraceConfigProvider} 装配。这里重点验证 * 「配置来源优先、配置文件兜底、两者皆无则拒绝导出」这条链路,以及标签可读文本与 * 二维码内容取到的是同一个追溯网址。 */ class MesProQrLabelBuilderTest { private static final String YAML_URL = "http://yaml.example.org/trace.html"; private static final String DICT_URL = "http://1.95.78.124:9008/prod/trace.html"; @AfterEach void resetStaticState() { // 构建器的配置是静态字段,不清干净会串味到其它测试 MesProQrLabelBuilder.setTraceConfigProvider(null); MesProQrLabelBuilder.setTraceBaseUrl(""); MesProQrLabelBuilder.setOperatorName(""); MesProQrLabelBuilder.setImporterName(""); MesProQrLabelBuilder.setImported(false); MesProQrLabelBuilder.setAllowPlainQrCode(false); } @Test void providerValueWinsOverConfiguredFile() { MesProQrLabelBuilder.setTraceBaseUrl(YAML_URL); MesProQrLabelBuilder.setOperatorName("生产经营者"); useProvider(snapshot(DICT_URL, "生产经营者", "", false)); assertEquals(DICT_URL, MesProQrLabelBuilder.resolveTraceUrl()); } @Test void fallsBackToConfiguredFileWhenProviderAbsent() { MesProQrLabelBuilder.setTraceBaseUrl(YAML_URL); // 未装配配置来源(单测 / 非 Spring 上下文)时应回退配置文件 assertEquals(YAML_URL, MesProQrLabelBuilder.resolveTraceUrl()); } @Test void blankProviderValueDoesNotEraseConfiguredFile() { MesProQrLabelBuilder.setTraceBaseUrl(YAML_URL); useProvider(snapshot("", "生产经营者", "", false)); // 配置来源只应「补充」,不应把兜底值抹成空 assertEquals(YAML_URL, MesProQrLabelBuilder.resolveTraceUrl()); } @Test void bagLabelPrintsSameUrlAsItsQrCode() { MesProQrLabelBuilder.setOperatorName("生产经营者"); useProvider(snapshot(DICT_URL, "生产经营者", "", false)); QrLabelInfo label = MesProQrLabelBuilder.buildBagCodeLabel(bagCode(), null, Map.of(), Map.of()); // 可读文本与二维码内容必须是同一个网址,否则标签会自相矛盾 assertEquals(DICT_URL, label.getKeyValues().get("追溯网址")); assertEquals(DICT_URL + "?code=12345678901234567890", label.getCode()); } @Test void importedSceneLabelsImporterName() { useProvider(snapshot(DICT_URL, "生产经营者", "某进口商", true)); QrLabelInfo label = MesProQrLabelBuilder.buildBagCodeLabel(bagCode(), null, Map.of(), Map.of()); assertEquals("某进口商", label.getKeyValues().get("进口商名称")); assertNull(label.getKeyValues().get("生产经营者名称")); } @Test void rejectsExportWhenNeitherSourceHasUrl() { MesProQrLabelBuilder.setOperatorName("生产经营者"); useProvider(snapshot("", "生产经营者", "", false)); // 四要素缺失即拒绝导出:这是标签合规的最后一道闸门,绝不能静默降级 assertThrows(ServiceException.class, () -> MesProQrLabelBuilder.buildBagCodeLabel(bagCode(), null, Map.of(), Map.of())); } @Test void providerCannotBypassElementValidation() { // 即使配置来源给了网址,生产经营者名称缺失仍须拒绝导出 useProvider(snapshot(DICT_URL, "", "", false)); assertThrows(ServiceException.class, () -> MesProQrLabelBuilder.buildBagCodeLabel(bagCode(), null, Map.of(), Map.of())); } private static void useProvider(MesTraceConfigSnapshot snapshot) { MesProQrLabelBuilder.setTraceConfigProvider(() -> snapshot); } private static MesTraceConfigSnapshot snapshot(String traceUrl, String operatorName, String importerName, boolean imported) { return new MesTraceConfigSnapshot(traceUrl, MesTraceUrlSource.DICT, operatorName, importerName, imported); } private static MesProBagCodeDO bagCode() { return new MesProBagCodeDO().setCode("12345678901234567890").setItemName("新陆早78号"); } }