package com.xly.service; import org.junit.jupiter.api.Test; import org.springframework.jdbc.core.JdbcTemplate; import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; /** * 数值/租户的**数据正确性不变量**(审计高危项): * 脏数值宁可报错也不静默写错值;缺租户时不退化成全库查询。 */ class FormResolverCoerceTest { private final FormResolverService resolver = new FormResolverService(mock(JdbcTemplate.class)); @Test void numericCoercionRejectsGarbageInsteadOfWritingZero() { assertThrows(IllegalArgumentException.class, () -> resolver.coerce("decimal", "一千"), "中文数字曾被写成 0——必须报错"); assertThrows(IllegalArgumentException.class, () -> resolver.coerce("int", "1k")); assertThrows(IllegalArgumentException.class, () -> resolver.coerce("decimal", "abc")); } @Test void numericCoercionKeepsFullValueWithThousandSeparators() { assertEquals("1000", resolver.coerce("decimal", "1,000"), "「1,000」曾被截成 1"); assertEquals("1000", resolver.coerce("decimal", "1,000")); assertEquals("12.5", resolver.coerce("decimal", " 12.5 ")); assertEquals("-3", resolver.coerce("int", "-3")); } @Test void dateCoercionDropsNonDates() { assertNull(resolver.coerce("datetime", "12"), "非日期交给 ERP 默认值,不写垃圾"); assertEquals("2026-07-28", resolver.coerce("date", "2026-07-28")); } @Test void fkOptionsWithoutTenantReturnsEmptyInsteadOfWholeTable() { JdbcTemplate jdbc = mock(JdbcTemplate.class); when(jdbc.queryForObject(anyString(), any(Class.class), (Object[]) any())).thenReturn(1); FormResolverService r = new FormResolverService(jdbc); Map page = r.fkOptionPage("elecustomer", null, null, 1, 20); assertEquals(0, page.get("total")); assertTrue(((List) page.get("rows")).isEmpty(), "拿不到租户就返回空,绝不跨租户全表翻页"); } }