package jnpf.dmsMapper; import org.apache.ibatis.builder.xml.XMLMapperBuilder; import org.apache.ibatis.io.Resources; import org.apache.ibatis.mapping.MappedStatement; import org.apache.ibatis.mapping.ResultMapping; import org.apache.ibatis.session.Configuration; import org.junit.jupiter.api.Test; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.util.HashMap; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; class DmsWenjianFenfaMapperXmlTest { private static final String RESOURCE = "mapper/DmsWenjianFenfaMapper.xml"; @Test void consumedCopiesIncludeVoidedAndDeletedRecords() throws IOException { Configuration configuration = parse(); Map parameters = Map.of("tenantId", "tenant-1", "taskId", "task-1"); String sql = normalize(configuration.getMappedStatement( DmsWenjianFenfaMapper.class.getName() + ".countConsumedPrints").getBoundSql(parameters).getSql()); assertTrue(sql.contains("f_tenant_id = ? AND dayin_renwu_id = ?")); assertFalse(sql.contains("biz_status")); assertFalse(sql.contains("f_delete_mark")); } @Test void mapperParsesAndUsesOnlyExplicitColumns() throws IOException { String xml; try (Reader reader = Resources.getResourceAsReader(RESOURCE)) { xml = read(reader); } assertFalse(xml.toUpperCase().contains("SELECT *")); assertFalse(xml.contains("f_delete_mark <>")); parse(); } @Test void taskAndPrintQueriesHaveExplicitResultMappings() throws IOException { Configuration configuration = parse(); assertMapping(configuration, DmsWenjianFenfaMapper.class.getName() + ".selectPrintTaskForUpdate", "laiyuan_danju_id", "laiyuanDanjuId"); assertMapping(configuration, DmsWenjianFenfaMapper.class.getName() + ".selectPrintTaskForUpdate", "peixun_wancheng_riqi", "peixunWanchengRiqi"); assertMapping(configuration, DmsWenjianFenfaMapper.class.getName() + ".selectPrintForUpdate", "dayin_liushuihao", "dayinLiushuihao"); assertMapping(configuration, DmsWenjianFenfaMapper.class.getName() + ".selectPrintForUpdate", "biz_review_sign", "bizReviewSign"); assertMapping(configuration, DmsWenjianFenfaMapper.class.getName() + ".selectHandoverDetail", "dayin_ren", "dayinRen"); assertMapping(configuration, DmsWenjianFenfaMapper.class.getName() + ".selectHandoverDetail", "jieshou_bumen", "jieshouBumen"); assertMapping(configuration, DmsWenjianFenfaMapper.class.getName() + ".selectHandoverDetail", "qianshou_bumen", "qianshouBumen"); assertMapping(configuration, DmsWenjianFenfaMapper.class.getName() + ".selectHandoverDetail", "dayin_fenshu", "dayinFenshu"); assertMapping(configuration, DmsWenjianFenfaMapper.class.getName() + ".selectHandoverDetail", "fenfa_bianhao", "fenfaBianhao"); } @Test void handoverDetailJoinsDisplayNamesAndReturnsOnlySelectedPrint() throws IOException { Configuration configuration = parse(); Map parameters = new HashMap<>(); parameters.put("tenantId", "tenant-1"); parameters.put("recordId", "print-1"); MappedStatement statement = configuration.getMappedStatement( DmsWenjianFenfaMapper.class.getName() + ".selectHandoverDetail"); String sql = normalize(statement.getBoundSql(parameters).getSql()); assertTrue(sql.contains("printer.f_real_name AS dayin_ren")); assertTrue(sql.contains("d.fenfa_bianhao")); assertTrue(sql.contains("p.dayin_liushuihao")); assertTrue(sql.contains("1 AS dayin_fenshu")); assertFalse(sql.contains("STRING_AGG")); assertTrue(sql.contains("r.jieshou_bumen_id")); assertTrue(sql.contains("p.qianshou_bumen_id")); assertFalse(sql.contains("COALESCE(p.qianshou_bumen_id, r.jieshou_bumen_id)")); assertTrue(sql.contains("p.f_id = ?")); } @Test void separateLedgersMapToIndependentStatuses() throws IOException { Configuration configuration = parse(); MappedStatement issueStatement = configuration.getMappedStatement( DmsWenjianFenfaMapper.class.getName() + ".selectIssueLedgerPageXml"); Map parameters = new HashMap<>(); parameters.put("tenantId", "tenant-1"); parameters.put("issueStatus", "unissued"); parameters.put("keyword", ""); String unissued = normalize(issueStatement.getBoundSql(parameters).getSql()); assertTrue(unissued.contains("p.f_id")); assertTrue(unissued.contains("d.f_id AS fenfa_renwu_id")); assertTrue(unissued.contains("p.dayin_liushuihao")); assertTrue(unissued.contains("p.fafang_shijian IS NULL")); assertTrue(unissued.contains("p.biz_status IN ('daifafang', 'daiqianshou')")); parameters.put("issueStatus", ""); String issueHistory = normalize(issueStatement.getBoundSql(parameters).getSql()); assertFalse(issueHistory.contains("p.biz_status IN ('daifafang', 'daiqianshou')")); MappedStatement receiptStatement = configuration.getMappedStatement( DmsWenjianFenfaMapper.class.getName() + ".selectReceiptLedgerPageXml"); parameters.remove("issueStatus"); parameters.put("receiptStatus", "pending"); String pending = normalize(receiptStatement.getBoundSql(parameters).getSql()); assertTrue(pending.contains("p.f_id")); assertTrue(pending.contains("p.qianshou_shijian IS NULL")); assertTrue(pending.contains("p.biz_status IN ('daifafang', 'daiqianshou')")); assertFalse(pending.contains("d.biz_status IN ('daiqianshou', 'yiwancheng')")); parameters.put("receiptStatus", "received"); String received = normalize(receiptStatement.getBoundSql(parameters).getSql()); assertTrue(received.contains("p.qianshou_shijian IS NOT NULL")); assertFalse(received.contains("p.biz_status IN ('daifafang', 'daiqianshou')")); } @Test void distributionStartsFromPartiallyOrFullyPrintedPublicTask() throws IOException { Configuration configuration = parse(); MappedStatement insert = configuration.getMappedStatement( DmsWenjianFenfaMapper.class.getName() + ".insertDistributionTaskIfAbsent"); String insertSql = normalize(insert.getBoundSql(new HashMap<>()).getSql()); assertTrue(insertSql.contains("p.biz_status IN ('bufendayin', 'yidayin')")); assertTrue(insertSql.contains("dayin_renwu_id")); MappedStatement records = configuration.getMappedStatement( DmsWenjianFenfaMapper.class.getName() + ".selectDistributionPageXml"); Map parameters = new HashMap<>(); parameters.put("tenantId", "tenant-1"); parameters.put("bizStatus", ""); parameters.put("keyword", ""); String recordsSql = normalize(records.getBoundSql(parameters).getSql()); assertTrue(recordsSql.contains("t.f_id = d.dayin_renwu_id")); } @Test void handoverCompletesOnePrintAndFinishesTaskOnlyAfterAllCopies() throws IOException { Configuration configuration = parse(); Map parameters = new HashMap<>(); parameters.put("tenantId", "tenant-1"); parameters.put("printTaskId", "task-1"); MappedStatement handoverRecords = configuration.getMappedStatement( DmsWenjianFenfaMapper.class.getName() + ".handoverPrintRecord"); String recordSql = normalize(handoverRecords.getBoundSql(parameters).getSql()); assertTrue(recordSql.contains("f_id = ?")); assertFalse(recordSql.contains("dayin_renwu_id = ?")); assertTrue(recordSql.contains("biz_status IN ('daifafang', 'daiqianshou')")); assertTrue(recordSql.contains("biz_status = 'daihuishou'")); assertTrue(recordSql.contains("fafang_ren_id")); assertTrue(recordSql.contains("qianshou_ren_id")); assertTrue(recordSql.contains("qianshou_bumen_id = ?")); assertTrue(recordSql.contains("biz_sign")); assertTrue(recordSql.contains("biz_review_sign")); MappedStatement progress = configuration.getMappedStatement( DmsWenjianFenfaMapper.class.getName() + ".completeDistributionTaskHandoverIfFinished"); String progressSql = normalize(progress.getBoundSql(parameters).getSql()); assertTrue(progressSql.contains("biz_status = 'yiwancheng'")); assertTrue(progressSql.contains("d.biz_status IN ('daifafang', 'daiqianshou')")); assertTrue(progressSql.contains("NOT EXISTS")); assertTrue(progressSql.contains("t.biz_status = 'yidayin'")); assertTrue(progressSql.contains("p.biz_status IN ('daifafang', 'daiqianshou')")); } @Test void printInsertKeepsTargetAndActualReceiptDepartmentsSeparate() throws IOException { Configuration configuration = parse(); MappedStatement insert = configuration.getMappedStatement( DmsWenjianFenfaMapper.class.getName() + ".insertPrintRecord"); String sql = normalize(insert.getBoundSql(new HashMap<>()).getSql()); assertTrue(sql.contains("dayin_bumen_id")); assertFalse(sql.contains("qianshou_bumen_id")); } @Test void archivePrintRecordsUpdatesOnlyTheSpecifiedActiveSerials() throws IOException { Configuration configuration = parse(); Map parameters = new HashMap<>(); parameters.put("serialNumbers", java.util.Arrays.asList("serial-1", "serial-2")); String sql = normalize(configuration.getMappedStatement(DmsWenjianFenfaMapper.class.getName() + ".archivePrintRecords").getBoundSql(parameters).getSql()); assertTrue(sql.contains("SET biz_status = 'yiguidang'")); assertTrue(sql.contains("f_delete_mark IS NULL")); assertTrue(sql.contains("dayin_liushuihao IN ( ? , ? )")); } @Test void trainingCompletionDateComesFromAuditRecord() throws IOException { Configuration configuration = parse(); MappedStatement snapshot = configuration.getMappedStatement( DmsWenjianFenfaMapper.class.getName() + ".selectAuditPrintSnapshot"); Map parameters = new HashMap<>(); parameters.put("tenantId", "tenant-1"); parameters.put("auditType", "xinzeng"); parameters.put("auditId", "audit-1"); String sql = normalize(snapshot.getBoundSql(parameters).getSql()); assertTrue(sql.contains("a.peixun_wancheng_riqi")); assertTrue(sql.contains("r.wenjian_bianhao")); assertTrue(sql.contains("v.f_id = a.shengxiao_wenjian_banben_id")); assertTrue(sql.contains("r.f_id = a.wenjian_id")); assertFalse(sql.contains("select a.wenjian_bianhao")); } @Test void scopeQueriesReadAuditChildrenDirectly() throws IOException { Configuration configuration = parse(); Map parameters = new HashMap<>(); parameters.put("tenantId", "tenant-1"); parameters.put("auditId", "audit-1"); MappedStatement newScopes = configuration.getMappedStatement( DmsWenjianFenfaMapper.class.getName() + ".selectNewScopes"); String newSql = normalize(newScopes.getBoundSql(parameters).getSql()); assertTrue(newSql.contains("dms_wenjian_xinzeng_shenhe_fenfa_bumen s")); assertTrue(newSql.contains("s.f_foreign_id = a.f_id")); MappedStatement revisionScopes = configuration.getMappedStatement( DmsWenjianFenfaMapper.class.getName() + ".selectRevisionScopes"); String revisionSql = normalize(revisionScopes.getBoundSql(parameters).getSql()); assertTrue(revisionSql.contains("dms_wenjian_xiuding_shenhe_fenfa_bumen s")); assertTrue(revisionSql.contains("s.f_foreign_id = a.f_id")); } @Test void recycleQueriesLockOnlyRequestedPendingRecordsAndMapEveryDetailField() throws IOException { Configuration configuration = parse(); String namespace = DmsWenjianFenfaMapper.class.getName() + "."; assertMapping(configuration, namespace + "selectRecycleCandidateBySerialNumber", "dayin_jilu_id", "dayinJiluId"); assertMapping(configuration, namespace + "selectRecycleCandidateBySerialNumber", "qianshou_shijian", "qianshouShijian"); assertMapping(configuration, namespace + "selectRecyclePrintsForUpdate", "biz_status", "bizStatus"); Map parameters = new HashMap<>(); parameters.put("tenantId", "tenant-1"); parameters.put("recordIds", java.util.Arrays.asList("print-1", "print-2")); String locked = normalize(configuration.getMappedStatement(namespace + "selectRecyclePrintsForUpdate").getBoundSql(parameters).getSql()); assertTrue(locked.contains("FOR UPDATE OF p")); assertTrue(locked.contains("p.f_id IN ( ? , ? )")); String mark = normalize(configuration.getMappedStatement(namespace + "markPrintsRecycled").getBoundSql(parameters).getSql()); assertTrue(mark.contains("biz_status = 'daixiaohui'")); assertTrue(mark.contains("biz_status = 'daihuishou'")); assertTrue(mark.contains("f_last_modify_user_id = ?")); String insertMain = normalize(configuration.getMappedStatement(namespace + "insertRecycle").getBoundSql(new Object()).getSql()); assertFalse(insertMain.contains("ON CONFLICT")); assertFalse(insertMain.contains("f_creator_user_id")); assertFalse(insertMain.contains("f_creator_time")); assertTrue(insertMain.contains("biz_sign, chuli_fangshi, beizhu_shuoming")); assertTrue(configuration.getMappedStatement(namespace + "insertRecycle") .getBoundSql(new Object()).getParameterMappings().stream() .anyMatch(mapping -> "chuliFangshi".equals(mapping.getProperty()))); } @Test void destructionScanReturnsOnlyTheRequestedPendingCopy() throws IOException { Configuration configuration = parse(); String statementId = DmsWenjianFenfaMapper.class.getName() + ".selectDestructionCandidateBySerialNumber"; assertMapping(configuration, statementId, "dayin_jilu_id", "dayinJiluId"); assertMapping(configuration, statementId, "wenjian_id", "wenjianId"); assertMapping(configuration, statementId, "qianshou_bumen_id", "qianshouBumenId"); Map parameters = new HashMap<>(); parameters.put("tenantId", "tenant-1"); parameters.put("serialNumber", "serial-1"); String sql = normalize(configuration.getMappedStatement(statementId) .getBoundSql(parameters).getSql()); assertTrue(sql.contains("p.dayin_liushuihao = ?")); assertTrue(sql.contains("p.biz_status = 'daixiaohui'")); assertTrue(sql.contains("p.f_delete_mark IS NULL")); assertTrue(sql.contains("t.wenjian_id")); assertTrue(sql.contains("p.qianshou_bumen_id")); assertFalse(sql.contains("bumen_banzu")); } private Configuration parse() throws IOException { Configuration configuration = new Configuration(); try (InputStream input = Resources.getResourceAsStream(RESOURCE)) { new XMLMapperBuilder(input, configuration, RESOURCE, configuration.getSqlFragments()).parse(); } return configuration; } private void assertMapping(Configuration configuration, String statementId, String column, String property) { MappedStatement statement = configuration.getMappedStatement(statementId); boolean mapped = statement.getResultMaps().stream() .flatMap(resultMap -> resultMap.getResultMappings().stream()) .anyMatch(mapping -> matches(mapping, column, property)); assertTrue(mapped, column + " must map explicitly to " + property); } private boolean matches(ResultMapping mapping, String column, String property) { return column.equals(mapping.getColumn()) && property.equals(mapping.getProperty()); } private String read(Reader reader) throws IOException { StringBuilder result = new StringBuilder(); char[] buffer = new char[2048]; int length; while ((length = reader.read(buffer)) >= 0) { result.append(buffer, 0, length); } return result.toString(); } private String normalize(String sql) { return sql.replaceAll("\\s+", " ").trim(); } }