From f329f504040f3608478c687a99aa36a3cf5720b7 Mon Sep 17 00:00:00 2001
From: xyc <jc_xiong@hotmail.com>
Date: 星期六, 03 十月 2026 23:45:04 +0800
Subject: [PATCH] feat(observation): 新增观测站分日调查数据导入与明细查看

---
 traffic-audit-server/src/test/java/com/trafficaudit/holiday/service/HolidayBulletinServiceTest.java |  117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 117 insertions(+), 0 deletions(-)

diff --git a/traffic-audit-server/src/test/java/com/trafficaudit/holiday/service/HolidayBulletinServiceTest.java b/traffic-audit-server/src/test/java/com/trafficaudit/holiday/service/HolidayBulletinServiceTest.java
new file mode 100644
index 0000000..bdef3e2
--- /dev/null
+++ b/traffic-audit-server/src/test/java/com/trafficaudit/holiday/service/HolidayBulletinServiceTest.java
@@ -0,0 +1,117 @@
+package com.trafficaudit.holiday.service;
+
+import com.trafficaudit.holiday.service.HolidayStatService.DailyMetrics;
+import org.junit.jupiter.api.Test;
+
+import java.lang.reflect.Method;
+import java.math.BigDecimal;
+import java.util.function.Function;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+class HolidayBulletinServiceTest {
+
+    @Test
+    void formatsTableRatiosAsSignedPercentages() throws Exception {
+        HolidayBulletinService service = new HolidayBulletinService(null);
+
+        assertEquals("-4.7%", ratio(service, "95.3", "100"));
+        assertEquals("1.0%", ratio(service, "101", "100"));
+        assertEquals("0%", ratio(service, "100", "100"));
+        assertEquals("0%", ratio(service, "10004", "10000"));
+        assertEquals("鈥�", ratio(service, "100", null));
+        assertEquals("鈥�", ratio(service, "100", "0"));
+    }
+
+    @Test
+    void comparesCivilAviationOnlyThroughCoveredDay() throws Exception {
+        HolidayStatService stat = mock(HolidayStatService.class);
+        HolidayBulletinService service = new HolidayBulletinService(stat);
+
+        DailyMetrics current = new DailyMetrics();
+        current.setYear(2026);
+        current.setHolidayType("NATIONAL_DAY");
+        current.setDayIndex(2);
+
+        DailyMetrics coveredDay = new DailyMetrics();
+        coveredDay.setCivilAviation(new BigDecimal("6.7482"));
+        DailyMetrics missingDay = new DailyMetrics();
+
+        when(stat.dailyMetrics(2026, "NATIONAL_DAY", 2)).thenReturn(missingDay);
+        when(stat.dailyMetrics(2026, "NATIONAL_DAY", 1)).thenReturn(coveredDay);
+
+        DailyMetrics previousYear = new DailyMetrics();
+        previousYear.setYear(2025);
+        DailyMetrics previousYearThroughDay1 = new DailyMetrics();
+        previousYearThroughDay1.setCivilAviation(new BigDecimal("7.5003"));
+        when(stat.cumulativeMetrics(2025, "NATIONAL_DAY", 1)).thenReturn(previousYearThroughDay1);
+
+        Object result = comparableCumulative(service, current, previousYear, DailyMetrics::getCivilAviation);
+
+        assertSame(previousYearThroughDay1, result);
+        verify(stat).cumulativeMetrics(2025, "NATIONAL_DAY", 1);
+        verify(stat, never()).cumulativeMetrics(2025, "NATIONAL_DAY", 2);
+    }
+
+    @Test
+    void comparableCumulativeIsNullWhenCurrentYearHasNoMetricData() throws Exception {
+        HolidayStatService stat = mock(HolidayStatService.class);
+        HolidayBulletinService service = new HolidayBulletinService(stat);
+
+        DailyMetrics current = new DailyMetrics();
+        current.setYear(2026);
+        current.setHolidayType("NATIONAL_DAY");
+        current.setDayIndex(2);
+        when(stat.dailyMetrics(2026, "NATIONAL_DAY", 2)).thenReturn(new DailyMetrics());
+        when(stat.dailyMetrics(2026, "NATIONAL_DAY", 1)).thenReturn(new DailyMetrics());
+
+        Object result = comparableCumulative(service, current, new DailyMetrics(), DailyMetrics::getCivilAviation);
+
+        assertNull(result);
+        verify(stat, never()).cumulativeMetrics(0, "NATIONAL_DAY", 1);
+    }
+
+    @Test
+    void cumulativeParagraphUsesWanUnitAndSingleRounding() throws Exception {
+        HolidayBulletinService service = new HolidayBulletinService(null);
+
+        DailyMetrics current = new DailyMetrics();
+        current.setTotalPersonFlow(new BigDecimal("3088.62958"));
+        DailyMetrics previousYear = new DailyMetrics();
+        previousYear.setTotalPersonFlow(new BigDecimal("3232.42742"));
+        DailyMetrics twoYearsAgo = new DailyMetrics();
+        twoYearsAgo.setTotalPersonFlow(new BigDecimal("3137.80860"));
+
+        Method method = HolidayBulletinService.class.getDeclaredMethod(
+                "cumulativeParagraph", DailyMetrics.class, DailyMetrics.class, DailyMetrics.class);
+        method.setAccessible(true);
+        String text = (String) method.invoke(service, current, previousYear, twoYearsAgo);
+
+        assertEquals(
+                "鍋囨湡浠ユ潵锛屽叏鐪佸叏绀句細璺ㄥ尯鍩熶汉鍛樻祦鍔ㄩ噺绱3088.63涓囦汉娆★紝姣�2025骞村悓鏈熶笅闄�4.4%锛屾瘮2024骞村悓鏈熶笅闄�1.6%銆�",
+                text);
+    }
+
+    private Object comparableCumulative(HolidayBulletinService service, DailyMetrics current,
+                                        DailyMetrics comparisonYear,
+                                        Function<DailyMetrics, BigDecimal> selector) throws Exception {
+        Method method = HolidayBulletinService.class.getDeclaredMethod(
+                "comparableCumulative", DailyMetrics.class, DailyMetrics.class, Function.class);
+        method.setAccessible(true);
+        return method.invoke(service, current, comparisonYear, selector);
+    }
+
+    private String ratio(HolidayBulletinService service, String current, String base) throws Exception {
+        Method method = HolidayBulletinService.class.getDeclaredMethod("ratio", BigDecimal.class, BigDecimal.class);
+        method.setAccessible(true);
+        BigDecimal currentValue = current == null ? null : new BigDecimal(current);
+        BigDecimal baseValue = base == null ? null : new BigDecimal(base);
+        return (String) method.invoke(service, currentValue, baseValue);
+    }
+}

--
Gitblit v1.9.1