diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2ColdStart.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2ColdStart.java index 393242e4..59251ca4 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2ColdStart.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2ColdStart.java @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Optional; +import java.util.function.Supplier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -28,6 +29,7 @@ import nl.overheid.aerius.gml.base.IsGmlProperty; import nl.overheid.aerius.shared.domain.v2.base.TimeUnit; import nl.overheid.aerius.shared.domain.v2.source.ColdStartEmissionSource; +import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; import nl.overheid.aerius.shared.domain.v2.source.road.StandardColdStartVehicles; import nl.overheid.aerius.shared.domain.v2.source.road.Vehicles; import nl.overheid.aerius.shared.exception.AeriusException; @@ -40,6 +42,13 @@ public class GML2ColdStart extends AbstractGML2S private static final Logger LOG = LoggerFactory.getLogger(GML2ColdStart.class); + /** + * When a specific vehicle is converted to a custom vehicle, and the source has vehicle based characteristics, + * the vehicle type of that sub source is set to this value. + * Its up to the user to check if this is correct, and change it if needed. + */ + private static final String REMOVED_CODE_CONVERSION_VEHICLE_TYPE = "LIGHT_TRAFFIC"; + /** * @param conversionData The conversion data to use. */ @@ -64,15 +73,25 @@ protected void addVehicleEmissions(final List addToVehicles, final T s if (av instanceof final IsGmlColdStartStandardVehicle standardVehicle) { addEmissionValues(addToVehicles, source, standardVehicle, mergingStandardVehicles); } else if (av instanceof final IsGmlSpecificVehicle specificVehicle) { - GML2VehicleUtil.addEmissionValuesSpecific(addToVehicles, source, specificVehicle, getConversionData()); + final Vehicles converted = GML2VehicleUtil.convertEmissionValuesSpecific(source, specificVehicle, getConversionData()); + checkVehicleType(source, converted, () -> REMOVED_CODE_CONVERSION_VEHICLE_TYPE); + addToVehicles.add(converted); } else if (av instanceof final IsGmlCustomVehicle customVehicle) { - GML2VehicleUtil.addEmissionValuesCustom(addToVehicles, customVehicle, source.isVehicleBasedCharacteristics()); + final Vehicles converted = GML2VehicleUtil.convertEmissionValuesCustom(customVehicle); + checkVehicleType(source, converted, customVehicle::getVehicleType); + addToVehicles.add(converted); } else { LOG.error("Don't know how to treat cold start vehicle type: {}", av.getClass()); throw new AeriusException(ImaerExceptionReason.INTERNAL_ERROR); } } + private void checkVehicleType(final T source, final Vehicles converted, final Supplier vehicleTypeSupplier) { + if (converted instanceof final CustomVehicles convertedCustom && source.isVehicleBasedCharacteristics()) { + convertedCustom.setVehicleType(vehicleTypeSupplier.get()); + } + } + private void addEmissionValues(final List addToVehicles, final T source, final IsGmlColdStartStandardVehicle sv, final List mergingStandardVehicles) { final StandardColdStartVehicles standardVehicle = findExistingMatch(sv, mergingStandardVehicles).orElseGet(() -> { diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2Road.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2Road.java index 7f990268..428da2ec 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2Road.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2Road.java @@ -75,9 +75,9 @@ protected void addVehicleEmissions(final List addToVehicles, final T s if (av instanceof final IsGmlStandardVehicle standardVehicle) { addEmissionValues(addToVehicles, source, standardVehicle, mergingStandardVehicles); } else if (av instanceof final IsGmlSpecificVehicle specificVehicle) { - GML2VehicleUtil.addEmissionValuesSpecific(addToVehicles, source, specificVehicle, getConversionData()); + addToVehicles.add(GML2VehicleUtil.convertEmissionValuesSpecific(source, specificVehicle, getConversionData())); } else if (av instanceof final IsGmlCustomVehicle customVehicle) { - GML2VehicleUtil.addEmissionValuesCustom(addToVehicles, customVehicle, false); + addToVehicles.add(GML2VehicleUtil.convertEmissionValuesCustom(customVehicle)); } else { throw new IllegalArgumentException("Instance not supported:" + av.getClass().getCanonicalName()); } diff --git a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtil.java b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtil.java index 84b4d529..7c3e31b0 100644 --- a/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtil.java +++ b/source/imaer-gml/src/main/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtil.java @@ -16,8 +16,6 @@ */ package nl.overheid.aerius.gml.base.source.road; -import java.util.List; - import nl.overheid.aerius.gml.base.GMLConversionData; import nl.overheid.aerius.gml.base.GMLLegacyCodeConverter.GMLLegacyCodeType; import nl.overheid.aerius.gml.base.IsGmlProperty; @@ -28,32 +26,28 @@ import nl.overheid.aerius.shared.domain.v2.source.road.SpecificVehicles; import nl.overheid.aerius.shared.domain.v2.source.road.Vehicles; -/** - * - */ -class GML2VehicleUtil { +final class GML2VehicleUtil { private GML2VehicleUtil() { // Util class } - static void addEmissionValuesSpecific(final List addToVehicles, final IsGmlEmissionSource source, final IsGmlSpecificVehicle sv, + static Vehicles convertEmissionValuesSpecific(final IsGmlEmissionSource source, final IsGmlSpecificVehicle sv, final GMLConversionData conversionData) { final String vehicleCode = conversionData.getCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, sv.getCode(), source.getLabel()); if (conversionData.warnIfRemovedCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, vehicleCode, source.getLabel())) { - addToVehicles.add(RemovedVehicleUtil.toCustomVehicles(sv, vehicleCode)); - return; + return RemovedVehicleUtil.toCustomVehicles(sv, vehicleCode); } final SpecificVehicles vse = new SpecificVehicles(); vse.setVehicleCode(vehicleCode); vse.setTimeUnit(TimeUnit.valueOf(sv.getTimeUnit().name())); vse.setVehiclesPerTimeUnit(sv.getVehiclesPerTimeUnit()); - addToVehicles.add(vse); + return vse; } - static void addEmissionValuesCustom(final List addToVehicles, final IsGmlCustomVehicle cv, final boolean includeVehicleType) { + static Vehicles convertEmissionValuesCustom(final IsGmlCustomVehicle cv) { final CustomVehicles vce = new CustomVehicles(); vce.setDescription(cv.getDescription()); for (final IsGmlProperty e : cv.getEmissionFactors()) { @@ -62,10 +56,7 @@ static void addEmissionValuesCustom(final List addToVehicles, final Is } vce.setTimeUnit(TimeUnit.valueOf(cv.getTimeUnit().name())); vce.setVehiclesPerTimeUnit(cv.getVehiclesPerTimeUnit()); - if (includeVehicleType) { - vce.setVehicleType(cv.getVehicleType()); - } - addToVehicles.add(vce); + return vce; } } diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java index 45eb5c23..d3dfd3e5 100644 --- a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/RemovedVehicleCodeImportTest.java @@ -34,6 +34,7 @@ import nl.overheid.aerius.importer.ImaerImporter; import nl.overheid.aerius.importer.ImportOption; import nl.overheid.aerius.shared.domain.v2.importer.ImportParcel; +import nl.overheid.aerius.shared.domain.v2.source.ColdStartEmissionSource; import nl.overheid.aerius.shared.domain.v2.source.SRM2RoadEmissionSource; import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; import nl.overheid.aerius.shared.exception.AeriusException; @@ -68,8 +69,37 @@ void testRemovedVehicleCodeIsConvertedDuringImport() throws IOException, AeriusE final SRM2RoadEmissionSource roadSource = (SRM2RoadEmissionSource) result.getSituation().getEmissionSourcesList().get(0).getProperties(); - final CustomVehicles converted = assertInstanceOf(CustomVehicles.class, roadSource.getSubSources().get(0)); - assertEquals(REMOVED_CODE, converted.getDescription()); + final CustomVehicles converted = + assertInstanceOf(CustomVehicles.class, roadSource.getSubSources().get(0), "Should be converted to CustomVehicles"); + assertEquals(REMOVED_CODE, converted.getDescription(), "Description should contain the removed code"); + } + + @Test + void testRemovedVehicleCodeForColdStart() throws IOException, AeriusException { + final GMLHelper mockHelper = AssertGML.mockGMLHelper(); + when(mockHelper.getRemovedCodes()).thenReturn(Map.of(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, Set.of(REMOVED_CODE))); + + // Create fresh factory with our mock helper (not cached) so getRemovedVehicleCodes is used + final GMLReaderFactory factory = new GMLReaderFactory(mockHelper); + final ImaerImporter importer = new ImaerImporter(mockHelper, factory); + final ImportParcel result = new ImportParcel(); + + try (final InputStream inputStream = AssertGML.getFileInputStream( + AssertGML.PATH_LATEST_VERSION + "roundtrip", "coldstart_without_characteristics")) { + importer.importStream(inputStream, EnumSet.of(ImportOption.INCLUDE_SOURCES), result); + } + + assertEquals(0, result.getExceptions().size(), "Expected no exceptions"); + assertTrue(result.getWarnings().stream() + .anyMatch(w -> w.getReason() == ImaerExceptionReason.GML_REMOVED_CODE_CONVERTED), + "Expected warning for removed vehicle code"); + + final ColdStartEmissionSource coldStart = + (ColdStartEmissionSource) result.getSituation().getEmissionSourcesList().get(0).getProperties(); + final CustomVehicles converted = + assertInstanceOf(CustomVehicles.class, coldStart.getSubSources().get(1), "Should be converted to CustomVehicles"); + assertEquals(REMOVED_CODE, converted.getDescription(), "Description should contain the removed code"); + assertEquals("LIGHT_TRAFFIC", converted.getVehicleType(), "Vehicle type should be set to hardcoded value if characteristics are vehicle based"); } } diff --git a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtilTest.java b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtilTest.java index c441ceb0..d843e1f0 100644 --- a/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtilTest.java +++ b/source/imaer-gml/src/test/java/nl/overheid/aerius/gml/base/source/road/GML2VehicleUtilTest.java @@ -16,14 +16,11 @@ */ package nl.overheid.aerius.gml.base.source.road; -import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import java.util.ArrayList; -import java.util.List; - import org.junit.jupiter.api.Test; import nl.overheid.aerius.gml.base.GMLConversionData; @@ -33,7 +30,6 @@ import nl.overheid.aerius.shared.domain.v2.source.road.CustomVehicles; import nl.overheid.aerius.shared.domain.v2.source.road.SpecificVehicles; import nl.overheid.aerius.shared.domain.v2.source.road.Vehicles; -import nl.overheid.aerius.shared.exception.AeriusException; class GML2VehicleUtilTest { @@ -42,33 +38,30 @@ class GML2VehicleUtilTest { private static final String SOURCE_LABEL = "Test source"; @Test - void testRemovedCodeRoutesToCustomVehicles() throws AeriusException { + void testRemovedCodeRoutesToCustomVehicles() { final GMLConversionData conversionData = mock(GMLConversionData.class); when(conversionData.getCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, REMOVED_CODE, SOURCE_LABEL)) .thenReturn(REMOVED_CODE); when(conversionData.warnIfRemovedCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, REMOVED_CODE, SOURCE_LABEL)) .thenReturn(true); - final List vehicles = new ArrayList<>(); - GML2VehicleUtil.addEmissionValuesSpecific(vehicles, mockSource(), mockSpecificVehicle(REMOVED_CODE), conversionData); + final Vehicles vehicle = GML2VehicleUtil.convertEmissionValuesSpecific(mockSource(), mockSpecificVehicle(REMOVED_CODE), conversionData); - assertEquals(1, vehicles.size()); - assertInstanceOf(CustomVehicles.class, vehicles.get(0)); + assertInstanceOf(CustomVehicles.class, vehicle, "Returned vehicle should be custom"); + assertNull(((CustomVehicles) vehicle).getVehicleType(), "Vehicle type should not be set by this conversion"); } @Test - void testUnknownCodeStaysSpecificVehicle() throws AeriusException { + void testUnknownCodeStaysSpecificVehicle() { final GMLConversionData conversionData = mock(GMLConversionData.class); when(conversionData.getCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, VALID_CODE, SOURCE_LABEL)) .thenReturn(VALID_CODE); when(conversionData.warnIfRemovedCode(GMLLegacyCodeType.ON_ROAD_MOBILE_SOURCE, VALID_CODE, SOURCE_LABEL)) .thenReturn(false); - final List vehicles = new ArrayList<>(); - GML2VehicleUtil.addEmissionValuesSpecific(vehicles, mockSource(), mockSpecificVehicle(VALID_CODE), conversionData); + final Vehicles vehicle = GML2VehicleUtil.convertEmissionValuesSpecific(mockSource(), mockSpecificVehicle(VALID_CODE), conversionData); - assertEquals(1, vehicles.size()); - assertInstanceOf(SpecificVehicles.class, vehicles.get(0)); + assertInstanceOf(SpecificVehicles.class, vehicle, "Returned vehicle should be specific"); } private IsGmlEmissionSource mockSource() {