| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- package com.zksy.web.controller.cockpit;
- import com.zksy.base.domain.GasPipePoint;
- import com.zksy.base.domain.ManholeBase;
- import com.zksy.base.domain.PipeNetworkBase;
- import com.zksy.base.service.GasPipePointService;
- import com.zksy.base.service.ManholeBaseService;
- import com.zksy.base.service.PipeNetworkBaseService;
- import com.zksy.cockpit.foundation.CockpitReadException;
- import com.zksy.cockpit.geometry.CockpitFacilityGeometryResponse;
- import com.zksy.cockpit.geometry.CockpitFacilityGeometryResponse.Coverage;
- import com.zksy.cockpit.geometry.CockpitFacilityGeometryResponse.Feature;
- import com.zksy.cockpit.geometry.CockpitFacilityGeometryService;
- import org.junit.jupiter.api.BeforeEach;
- import org.junit.jupiter.api.Test;
- import org.junit.jupiter.params.ParameterizedTest;
- import org.junit.jupiter.params.provider.CsvSource;
- import java.math.BigDecimal;
- import java.time.Clock;
- import java.time.Instant;
- import java.time.ZoneOffset;
- import java.util.Arrays;
- import java.util.Collections;
- import java.util.List;
- import java.util.stream.Collectors;
- import static org.junit.jupiter.api.Assertions.*;
- import static org.mockito.Mockito.*;
- class CockpitFacilityGeometryServiceTest {
- private PipeNetworkBaseService networks;
- private GasPipePointService points;
- private ManholeBaseService manholes;
- private CockpitFacilityGeometryService service;
- @BeforeEach
- void setUp() {
- networks = mock(PipeNetworkBaseService.class);
- points = mock(GasPipePointService.class);
- manholes = mock(ManholeBaseService.class);
- when(networks.list()).thenReturn(Collections.emptyList());
- when(points.list()).thenReturn(Collections.emptyList());
- when(manholes.list()).thenReturn(Collections.emptyList());
- service = new CockpitFacilityGeometryService(networks, points, manholes,
- Clock.fixed(Instant.parse("2026-10-12T02:00:00Z"), ZoneOffset.UTC));
- }
- @Test
- void readsAllThreeIndustriesAsActualTwoEndpointLinesWithoutInventingTopology() {
- when(networks.list()).thenReturn(Arrays.asList(network("same-id", "0"), network("water", "2"),
- network("drain", "1"), network("unknown", "3")));
- GasPipePoint point = point(1L, "三通");
- point.setNetworkId("same-id");
- when(points.list()).thenReturn(Collections.singletonList(point));
- ManholeBase manhole = new ManholeBase();
- manhole.setManholeId("same-id");
- manhole.setLongitude(new BigDecimal("110.5"));
- manhole.setLatitude(new BigDecimal("28.5"));
- when(manholes.list()).thenReturn(Collections.singletonList(manhole));
- CockpitFacilityGeometryResponse response = service.load();
- assertEquals("FeatureCollection", response.getType());
- assertEquals("2026-10-12T10:00:00+08:00", response.getGeneratedAt());
- assertEquals(6, response.getFeatures().size());
- assertEquals(6, response.getFeatures().stream().map(Feature::getId).distinct().count());
- assertEquals(Arrays.asList("GAS", "WATER_SUPPLY", "DRAINAGE", "UNKNOWN", "GAS", "MANHOLE"),
- response.getFeatures().stream().map(item -> item.getProperties().getIndustry()).collect(Collectors.toList()));
- Feature gas = response.getFeatures().get(0);
- assertEquals("LineString", gas.getGeometry().getType());
- assertEquals(Arrays.asList(Arrays.asList(new BigDecimal("110.4"), new BigDecimal("28.4")),
- Arrays.asList(new BigDecimal("110.6"), new BigDecimal("28.6"))), gas.getGeometry().getCoordinates());
- assertEquals("GAS_PIPE", gas.getProperties().getTypeCode());
- assertEquals("PIPE_UNCLASSIFIED", response.getFeatures().get(3).getProperties().getTypeCode());
- assertEquals("3", response.getFeatures().get(3).getProperties().getNetworkType());
- Feature component = response.getFeatures().get(4);
- assertEquals("Point", component.getGeometry().getType());
- assertEquals("三通", component.getProperties().getPointType());
- assertEquals(gas.getProperties().getNetworkId(), component.getProperties().getNetworkId());
- assertEquals(1, coverage(response, "UNKNOWN", "LineString").getRecordCount());
- verify(networks).list();
- verify(points).list();
- verify(manholes).list();
- verifyNoMoreInteractions(networks, points, manholes);
- }
- @Test
- void preservesEveryComponentTypeIncludingUnknownAndMissingTypesWithoutFabricatingNodes() {
- List<String> types = Arrays.asList("阀门", "调压", "计量", "阴极保护", "弯头", "三通", "其它", "未知原始值", null);
- List<GasPipePoint> records = new java.util.ArrayList<>();
- for (int i = 0; i < types.size(); i++) {
- records.add(point((long) i, types.get(i)));
- }
- when(points.list()).thenReturn(records);
- CockpitFacilityGeometryResponse response = service.load();
- assertEquals(types, response.getFeatures().stream()
- .map(item -> item.getProperties().getPointType()).collect(Collectors.toList()));
- assertEquals(types.size(), response.getFeatures().size());
- assertTrue(response.getFeatures().stream().allMatch(item -> item.getProperties().getNetworkId() == null));
- }
- @ParameterizedTest
- @CsvSource({",28.4,MISSING_LONGITUDE", "110.4,,MISSING_LATITUDE", "181,28.4,LONGITUDE_OUT_OF_RANGE",
- "-181,28.4,LONGITUDE_OUT_OF_RANGE", "110.4,91,LATITUDE_OUT_OF_RANGE",
- "110.4,-91,LATITUDE_OUT_OF_RANGE", "0,0,ZERO_COORDINATE"})
- void invalidPointsStayInTheCollectionWithNullGeometryAndSpecificReason(String longitude, String latitude,
- String reason) {
- GasPipePoint point = point(1L, "阀门");
- point.setLongitude(decimal(longitude));
- point.setLatitude(decimal(latitude));
- when(points.list()).thenReturn(Collections.singletonList(point));
- Feature feature = service.load().getFeatures().get(0);
- assertNull(feature.getGeometry());
- assertEquals("INVALID", feature.getProperties().getCoordinateValidation().getState());
- assertEquals(reason, feature.getProperties().getCoordinateValidation().getReason());
- assertFalse(feature.getProperties().getCoordinateValidation().isRenderable());
- assertEquals(Arrays.asList(decimal(longitude), decimal(latitude)),
- feature.getProperties().getSourceCoordinates().get(0));
- }
- @Test
- void invalidEndIsNotMaskedByAnUnverifiedStartAndEntireLineHasNullGeometry() {
- PipeNetworkBase line = network("bad-end", "1");
- line.setEndLatitude(null);
- when(networks.list()).thenReturn(Collections.singletonList(line));
- CockpitFacilityGeometryResponse response = service.load();
- Feature feature = response.getFeatures().get(0);
- assertNull(feature.getGeometry());
- assertEquals("MISSING_LATITUDE", feature.getProperties().getCoordinateValidation().getReason());
- assertEquals("UNVERIFIED", feature.getProperties().getCoordinateValidations().get(0).getState());
- assertEquals("INVALID", feature.getProperties().getCoordinateValidations().get(1).getState());
- assertEquals(1, coverage(response, "DRAINAGE", "LineString").getRecordCount());
- assertEquals(0, coverage(response, "DRAINAGE", "LineString").getGeometryCount());
- }
- @Test
- void numericBoundsDoNotGrantCoordinateVerificationForAnySource() {
- when(networks.list()).thenReturn(Collections.singletonList(network("line", "0")));
- when(points.list()).thenReturn(Collections.singletonList(point(1L, "阀门")));
- ManholeBase manhole = new ManholeBase();
- manhole.setManholeId("well");
- manhole.setLongitude(new BigDecimal("-180"));
- manhole.setLatitude(new BigDecimal("90"));
- when(manholes.list()).thenReturn(Collections.singletonList(manhole));
- CockpitFacilityGeometryResponse response = service.load();
- for (Feature feature : response.getFeatures()) {
- assertNotNull(feature.getGeometry());
- assertEquals("UNVERIFIED", feature.getProperties().getCoordinateValidation().getState());
- assertEquals("UNVERIFIED_COORDINATE", feature.getProperties().getCoordinateValidation().getReason());
- assertEquals("WGS84", feature.getProperties().getCoordinateValidation().getCrs());
- assertFalse(feature.getProperties().getCoordinateValidation().isRenderable());
- }
- assertTrue(response.getCoverage().stream().allMatch(item -> item.getRenderableCount() == 0));
- }
- @Test
- void emptySourcesAreDistinguishedFromUnsupportedIndustryGeometry() {
- CockpitFacilityGeometryResponse response = service.load();
- assertTrue(response.getFeatures().isEmpty());
- assertEquals("EMPTY", coverage(response, "GAS", "Point").getState());
- assertEquals("EMPTY", coverage(response, "WATER_SUPPLY", "LineString").getState());
- assertEquals("TWO_ENDPOINTS_ONLY", coverage(response, "WATER_SUPPLY", "LineString").getReason());
- assertEquals("UNAVAILABLE", coverage(response, "WATER_SUPPLY", "Point").getState());
- assertEquals("NO_COMPONENT_SOURCE", coverage(response, "WATER_SUPPLY", "Point").getReason());
- assertEquals("NO_TYPED_COMPONENT_SOURCE", coverage(response, "DRAINAGE", "Point").getReason());
- assertEquals("NO_COMPONENT_TYPE", coverage(response, "MANHOLE", "Point").getReason());
- assertEquals("NO_PIPELINE_SOURCE", coverage(response, "MANHOLE", "LineString").getReason());
- }
- @Test
- void aFailedSourceNeverProducesAnEmptyOrPartialSuccess() {
- when(networks.list()).thenReturn(Collections.singletonList(network("line", "0")));
- when(points.list()).thenThrow(new IllegalStateException("private database detail"));
- CockpitReadException failure = assertThrows(CockpitReadException.class, service::load);
- assertEquals("facility geometry source unavailable", failure.getMessage());
- verifyNoInteractions(manholes);
- }
- @Test
- void aNullSourceIsAReadFailureRatherThanASuccessfulEmptyCollection() {
- when(manholes.list()).thenReturn(null);
- assertThrows(CockpitReadException.class, service::load);
- }
- private static Coverage coverage(CockpitFacilityGeometryResponse response, String industry, String geometry) {
- return response.getCoverage().stream().filter(item -> industry.equals(item.getIndustry())
- && geometry.equals(item.getGeometryType())).findFirst().orElseThrow();
- }
- private static PipeNetworkBase network(String id, String type) {
- PipeNetworkBase network = new PipeNetworkBase();
- network.setNetworkId(id);
- network.setNetworkCode("code-" + id);
- network.setNetworkType(type);
- network.setStartLongitude(new BigDecimal("110.4"));
- network.setStartLatitude(new BigDecimal("28.4"));
- network.setEndLongitude(new BigDecimal("110.6"));
- network.setEndLatitude(new BigDecimal("28.6"));
- return network;
- }
- private static GasPipePoint point(Long id, String type) {
- GasPipePoint point = new GasPipePoint();
- point.setPointId(id);
- point.setPointType(type);
- point.setLongitude(new BigDecimal("110.4"));
- point.setLatitude(new BigDecimal("28.4"));
- return point;
- }
- private static BigDecimal decimal(String value) {
- return value == null ? null : new BigDecimal(value);
- }
- }
|