From 506cdc55c5f305f079e1382298ab19c47a46176c Mon Sep 17 00:00:00 2001 From: Dominic Burger Date: Wed, 24 Jan 2024 14:47:48 +0100 Subject: [PATCH 1/3] Add helper classes --- .../functions/ngk/BaseInterlisFunction.java | 46 +++++++++ .../functions/ngk/EvaluationHelper.java | 79 +++++++++++++++ .../functions/ngk/AssertionHelper.java | 63 ++++++++++++ .../functions/ngk/LogCollector.java | 31 ++++++ .../functions/ngk/ValidationTestHelper.java | 97 +++++++++++++++++++ 5 files changed, 316 insertions(+) create mode 100644 src/main/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/BaseInterlisFunction.java create mode 100644 src/main/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/EvaluationHelper.java create mode 100644 src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/AssertionHelper.java create mode 100644 src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/LogCollector.java create mode 100644 src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/ValidationTestHelper.java diff --git a/src/main/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/BaseInterlisFunction.java b/src/main/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/BaseInterlisFunction.java new file mode 100644 index 0000000..cf38626 --- /dev/null +++ b/src/main/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/BaseInterlisFunction.java @@ -0,0 +1,46 @@ +package ch.geowerkstatt.ilivalidator.extensions.functions.ngk; + +import ch.ehi.basics.settings.Settings; +import ch.interlis.ili2c.metamodel.TransferDescription; +import ch.interlis.iom.IomObject; +import ch.interlis.iox.IoxValidationConfig; +import ch.interlis.iox_j.logging.LogEventFactory; +import ch.interlis.iox_j.validator.InterlisFunction; +import ch.interlis.iox_j.validator.ObjectPool; +import ch.interlis.iox_j.validator.Validator; +import ch.interlis.iox_j.validator.Value; + +public abstract class BaseInterlisFunction implements InterlisFunction { + + protected LogEventFactory logger; + protected TransferDescription td; + protected Settings settings; + protected Validator validator; + protected ObjectPool objectPool; + + @Override + public final void init(TransferDescription td, Settings settings, IoxValidationConfig validationConfig, ObjectPool objectPool, LogEventFactory logEventFactory) { + this.logger = logEventFactory; + this.logger.setValidationConfig(validationConfig); + this.td = td; + this.settings = settings; + this.validator = (Validator) settings.getTransientObject(IOX_VALIDATOR); + this.objectPool = objectPool; + } + + @Override + public final Value evaluate(String validationKind, String usageScope, IomObject mainObj, Value[] actualArguments) { + + for (Value arg : actualArguments) { + if (arg.skipEvaluation()) { + return arg; + } + } + + logger.setDataObj(mainObj); + + return evaluateInternal(validationKind, usageScope, mainObj, actualArguments); + } + + protected abstract Value evaluateInternal(String validationKind, String usageScope, IomObject mainObj, Value[] actualArguments); +} diff --git a/src/main/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/EvaluationHelper.java b/src/main/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/EvaluationHelper.java new file mode 100644 index 0000000..1b4dbd2 --- /dev/null +++ b/src/main/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/EvaluationHelper.java @@ -0,0 +1,79 @@ +package ch.geowerkstatt.ilivalidator.extensions.functions.ngk; + +import ch.ehi.basics.logging.EhiLogger; +import ch.interlis.ili2c.Ili2cException; +import ch.interlis.ili2c.metamodel.Element; +import ch.interlis.ili2c.metamodel.ObjectPath; +import ch.interlis.ili2c.metamodel.PathEl; +import ch.interlis.ili2c.metamodel.TransferDescription; +import ch.interlis.ili2c.metamodel.Viewable; +import ch.interlis.iom.IomObject; +import ch.interlis.iox_j.validator.Validator; +import ch.interlis.iox_j.validator.Value; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; + +public final class EvaluationHelper { + + private EvaluationHelper() { + // Utility class + } + + /** + * Parse the {@code argPath} into a {@link PathEl} array. + * + * @param validator the {@link Validator} instance. + * @param contextClass the {@link Viewable} definition where the {@code argPath} starts. + * @param argPath the path string to parse. see {@link Value#getValue()}. + * + * @return the parsed {@link PathEl} array or {@code null} if the {@code argPath} could not be parsed. + */ + public static PathEl[] getAttributePathEl(Validator validator, Viewable contextClass, Value argPath) { + try { + ObjectPath objectPath = validator.parseObjectOrAttributePath(contextClass, argPath.getValue()); + if (objectPath.getPathElements() != null) { + return objectPath.getPathElements(); + } + } catch (Ili2cException e) { + EhiLogger.logError(e); + } + return null; + } + + /** + * Get the {@link Viewable} (e.g. the class definition) from the {@link TransferDescription}. + * If the {@code iomObject} is {@code null}, the {@code argObjects} is used to retrieve the {@link Viewable}. + */ + public static Viewable getContextClass(TransferDescription td, IomObject iomObject, Value argObjects) { + if (iomObject != null) { + return (Viewable) td.getElement(iomObject.getobjecttag()); + } else if (argObjects.getViewable() != null) { + return argObjects.getViewable(); + } else if (argObjects.getComplexObjects() != null) { + Iterator it = argObjects.getComplexObjects().iterator(); + if (!it.hasNext()) { + return null; + } + return (Viewable) td.getElement(it.next().getobjecttag()); + } + return null; + } + + /** + * Get the collection of {@link IomObject} inside {@code argObjects} by following the provided {@code attributePath}. + */ + public static Collection evaluateAttributes(Validator validator, Value argObjects, PathEl[] attributePath) { + Collection attributes = new ArrayList<>(); + + for (IomObject rootObject : argObjects.getComplexObjects()) { + Value surfaceAttributes = validator.getValueFromObjectPath(null, rootObject, attributePath, null); + if (!(surfaceAttributes.isUndefined() || surfaceAttributes.skipEvaluation() || surfaceAttributes.getComplexObjects() == null)) { + attributes.addAll(surfaceAttributes.getComplexObjects()); + } + } + + return attributes; + } +} diff --git a/src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/AssertionHelper.java b/src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/AssertionHelper.java new file mode 100644 index 0000000..00ff0dc --- /dev/null +++ b/src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/AssertionHelper.java @@ -0,0 +1,63 @@ +package ch.geowerkstatt.ilivalidator.extensions.functions.ngk; + +import ch.interlis.iox.IoxLogEvent; +import com.vividsolutions.jts.util.Assert; + +import java.util.List; +import java.util.regex.Pattern; + +import static org.junit.jupiter.api.Assertions.fail; + +public final class AssertionHelper { + + private AssertionHelper() { + // Utility class + } + + public static void assertConstraintErrors(ValidationTestHelper vh, int expectedCount, String oid, String constraintName) { + int errorsFound = 0; + for (IoxLogEvent err : vh.getErrs()) { + if (oid.equals(err.getSourceObjectXtfId()) && err.getEventMsg().contains(String.format(".%s ", constraintName))) { + errorsFound++; + } + } + + Assert.equals(expectedCount, errorsFound, + String.format("Expected %d but found %d errors with OID <%s> and Source <%s>.", expectedCount, errorsFound, oid, constraintName)); + } + + public static void assertSingleConstraintError(ValidationTestHelper vh, int oid, String constraintName) { + assertConstraintErrors(vh, 1, Integer.toString(oid), constraintName); + } + + public static void assertConstraintErrors(ValidationTestHelper vh, int expectedCount, String constraintName) { + int errorsFound = 0; + for (IoxLogEvent err : vh.getErrs()) { + if (err.getEventMsg().contains(String.format(".%s ", constraintName))) { + errorsFound++; + } + } + + Assert.equals(expectedCount, errorsFound, + String.format("Expected %s errors with Source <%s> but found %d.", expectedCount, constraintName, errorsFound)); + } + + public static void assertNoConstraintError(ValidationTestHelper vh, String constraintName) { + int errorsFound = 0; + for (IoxLogEvent err : vh.getErrs()) { + if (err.getEventMsg().contains(String.format(".%s ", constraintName))) { + errorsFound++; + } + } + + Assert.equals(0, errorsFound, + String.format("Expected No errors with Source <%s> but found %d.", constraintName, errorsFound)); + } + + public static void assertLogEventsContainMessage(List logs, String expectedMessageRegex) { + Pattern pattern = Pattern.compile(expectedMessageRegex); + if (logs.stream().noneMatch(log -> pattern.matcher(log.getEventMsg()).find())) { + fail(String.format("The logs are missing the message <%s>.", expectedMessageRegex)); + } + } +} diff --git a/src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/LogCollector.java b/src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/LogCollector.java new file mode 100644 index 0000000..70d7ad6 --- /dev/null +++ b/src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/LogCollector.java @@ -0,0 +1,31 @@ +package ch.geowerkstatt.ilivalidator.extensions.functions.ngk; + +import ch.ehi.basics.logging.EhiLogger; +import ch.ehi.basics.logging.LogEvent; +import ch.interlis.iox.IoxLogEvent; + +import java.util.ArrayList; + + +public final class LogCollector implements ch.interlis.iox.IoxLogging { + private final ArrayList errs = new ArrayList<>(); + private final ArrayList warn = new ArrayList<>(); + + @Override + public void addEvent(IoxLogEvent event) { + EhiLogger.getInstance().logEvent((LogEvent) event); + if (event.getEventKind() == IoxLogEvent.ERROR) { + errs.add(event); + } else if (event.getEventKind() == IoxLogEvent.WARNING) { + warn.add(event); + } + } + + public ArrayList getErrs() { + return errs; + } + + public ArrayList getWarn() { + return warn; + } +} diff --git a/src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/ValidationTestHelper.java b/src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/ValidationTestHelper.java new file mode 100644 index 0000000..9a64cc3 --- /dev/null +++ b/src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/ValidationTestHelper.java @@ -0,0 +1,97 @@ +package ch.geowerkstatt.ilivalidator.extensions.functions.ngk; + +import ch.ehi.basics.settings.Settings; +import ch.interlis.ili2c.Ili2cFailure; +import ch.interlis.ili2c.metamodel.TransferDescription; +import ch.interlis.iox.EndTransferEvent; +import ch.interlis.iox.IoxEvent; +import ch.interlis.iox.IoxException; +import ch.interlis.iox.IoxLogEvent; +import ch.interlis.iox.IoxReader; +import ch.interlis.iox_j.IoxIliReader; +import ch.interlis.iox_j.PipelinePool; +import ch.interlis.iox_j.logging.LogEventFactory; +import ch.interlis.iox_j.utility.ReaderFactory; +import ch.interlis.iox_j.validator.InterlisFunction; +import ch.interlis.iox_j.validator.ValidationConfig; +import ch.interlis.iox_j.validator.Validator; + +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; + +public final class ValidationTestHelper { + + private final HashMap> userFunctions = new HashMap<>(); + private LogCollector logCollector; + + public void runValidation(String[] dataFiles, String[] modelFiles) throws IoxException, Ili2cFailure { + dataFiles = addLeadingTestDataDirectory(dataFiles); + modelFiles = addLeadingTestDataDirectory(modelFiles); + modelFiles = appendFunctionsExtIli(modelFiles); + + logCollector = new LogCollector(); + LogEventFactory errFactory = new LogEventFactory(); + errFactory.setLogger(logCollector); + + Settings settings = new Settings(); + settings.setTransientObject(ch.interlis.iox_j.validator.Validator.CONFIG_CUSTOM_FUNCTIONS, userFunctions); + + TransferDescription td = ch.interlis.ili2c.Ili2c.compileIliFiles(new ArrayList<>(Arrays.asList(modelFiles)), new ArrayList()); + + ValidationConfig modelConfig = new ValidationConfig(); + modelConfig.mergeIliMetaAttrs(td); + + PipelinePool pool = new PipelinePool(); + Validator validator = new ch.interlis.iox_j.validator.Validator(td, modelConfig, logCollector, errFactory, pool, settings); + + for (String filename : dataFiles) { + IoxReader ioxReader = new ReaderFactory().createReader(new java.io.File(filename), errFactory, settings); + if (ioxReader instanceof IoxIliReader) { + ((IoxIliReader) ioxReader).setModel(td); + + errFactory.setDataSource(filename); + td.setActualRuntimeParameter(ch.interlis.ili2c.metamodel.RuntimeParameters.MINIMAL_RUNTIME_SYSTEM01_CURRENT_TRANSFERFILE, filename); + try { + IoxEvent event; + do { + event = ioxReader.read(); + validator.validate(event); + } while (!(event instanceof EndTransferEvent)); + } finally { + ioxReader.close(); + } + } + } + } + + private String[] appendFunctionsExtIli(String[] modelDirs) { + System.out.println("Working Directory = " + System.getProperty("user.dir")); + String functionsExtIliPath = "src/model/NGK_SO_FunctionsExt.ili"; + ArrayList result = new ArrayList<>(); + result.add(functionsExtIliPath); + result.addAll(Arrays.asList(modelDirs)); + return result.toArray(new String[0]); + } + + @SuppressWarnings("unchecked") + public void addFunction(InterlisFunction function) { + userFunctions.put(function.getQualifiedIliName(), (Class) function.getClass()); + } + + public String[] addLeadingTestDataDirectory(String[] files) { + return Arrays + .stream(files).map(file -> Paths.get("src/test/data", file).toString()) + .distinct() + .toArray(String[]::new); + } + + public ArrayList getErrs() { + return logCollector.getErrs(); + } + + public ArrayList getWarn() { + return logCollector.getWarn(); + } +} From 9ab2816b1b13e6a24729eb40a1e6156f1740155f Mon Sep 17 00:00:00 2001 From: Dominic Burger Date: Wed, 24 Jan 2024 15:12:48 +0100 Subject: [PATCH 2/3] Add IsInsideAreaByCodeEnum function --- .../ngk/IsInsideAreaByCodeEnumIoxPlugin.java | 199 +++++++ src/model/NGK_SO_FunctionsExt.ili | 6 +- src/model/ilimodels.xml | 8 + .../IsInsideAreaByCodeEnum/SetConstraints.ili | 31 ++ .../IsInsideAreaByCodeEnum/TestData_Fail.xtf | 519 ++++++++++++++++++ .../IsInsideAreaByCodeEnum/TestData_Ok.xtf | 216 ++++++++ .../IsInsideAreaByCodeEnumIoxPluginTest.java | 34 ++ 7 files changed, 1012 insertions(+), 1 deletion(-) create mode 100644 src/main/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/IsInsideAreaByCodeEnumIoxPlugin.java create mode 100644 src/model/ilimodels.xml create mode 100644 src/test/data/IsInsideAreaByCodeEnum/SetConstraints.ili create mode 100644 src/test/data/IsInsideAreaByCodeEnum/TestData_Fail.xtf create mode 100644 src/test/data/IsInsideAreaByCodeEnum/TestData_Ok.xtf create mode 100644 src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/IsInsideAreaByCodeEnumIoxPluginTest.java diff --git a/src/main/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/IsInsideAreaByCodeEnumIoxPlugin.java b/src/main/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/IsInsideAreaByCodeEnumIoxPlugin.java new file mode 100644 index 0000000..76b5442 --- /dev/null +++ b/src/main/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/IsInsideAreaByCodeEnumIoxPlugin.java @@ -0,0 +1,199 @@ +package ch.geowerkstatt.ilivalidator.extensions.functions.ngk; + +import ch.ehi.basics.types.OutParam; +import ch.interlis.ili2c.metamodel.EnumerationType; +import ch.interlis.ili2c.metamodel.PathEl; +import ch.interlis.ili2c.metamodel.Type; +import ch.interlis.ili2c.metamodel.Viewable; +import ch.interlis.iom.IomObject; +import ch.interlis.iox_j.jts.Iox2jtsext; +import ch.interlis.iox_j.validator.Value; +import com.vividsolutions.jts.geom.Geometry; +import com.vividsolutions.jts.geom.GeometryFactory; + +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +public final class IsInsideAreaByCodeEnumIoxPlugin extends BaseInterlisFunction { + private static final Map OBJECTS_CACHE = new HashMap<>(); + + @Override + public String getQualifiedIliName() { + return "NGK_SO_FunctionsExt.IsInsideAreaByCodeEnum"; + } + + @Override + protected Value evaluateInternal(String validationKind, String usageScope, IomObject contextObject, Value[] arguments) { + Value argObjects = arguments[0]; + Value argGeometryPath = arguments[1]; + Value argEnumPath = arguments[2]; + + if (argObjects.isUndefined() || argGeometryPath.isUndefined() || argEnumPath.isUndefined()) { + return Value.createSkipEvaluation(); + } + + Collection objects = argObjects.getComplexObjects(); + if (objects.isEmpty()) { + return new Value(true); + } + + List objectIds = objects.stream().map(IomObject::getobjectoid).collect(Collectors.toList()); + String geometryAttribute = argGeometryPath.getValue(); + String enumAttribute = argEnumPath.getValue(); + + InsideAreaKey key = new InsideAreaKey(objectIds, geometryAttribute, enumAttribute); + return OBJECTS_CACHE.computeIfAbsent(key, k -> { + Viewable contextClass = EvaluationHelper.getContextClass(td, contextObject, argObjects); + if (contextClass == null) { + throw new IllegalStateException("unknown class in " + usageScope); + } + + PathEl[] geometryPath = EvaluationHelper.getAttributePathEl(validator, contextClass, argGeometryPath); + PathEl[] enumPath = EvaluationHelper.getAttributePathEl(validator, contextClass, argEnumPath); + + return isInsideArea(usageScope, objects, geometryPath, enumPath); + }); + } + + private Value isInsideArea(String usageScope, Collection objects, PathEl[] geometryPath, PathEl[] enumPath) { + Map geometriesByEnumValue = objects.stream() + .collect(Collectors.toMap( + o -> getEnumValue(o, enumPath), + o -> getGeometryValue(o, geometryPath), + Geometry::union + )); + + ValueKey firstKey = geometriesByEnumValue.keySet().iterator().next(); + Type keyType = firstKey.getType(); + if (!(keyType instanceof EnumerationType)) { + logger.addEvent(logger.logErrorMsg("{0}: Enumeration type expected.", usageScope)); + return Value.createSkipEvaluation(); + } + EnumerationType enumType = (EnumerationType) keyType; + if (!enumType.isOrdered()) { + logger.addEvent(logger.logErrorMsg("{0}: Enumeration type must be ordered.", usageScope)); + return Value.createSkipEvaluation(); + } + + List sortedGeometries = sortByEnumValues(geometriesByEnumValue, enumType); + for (int i = 0; i < sortedGeometries.size() - 1; i++) { + Geometry current = sortedGeometries.get(i); + Geometry next = sortedGeometries.get(i + 1); + + if (!next.contains(current)) { + return new Value(false); + } + } + + return new Value(true); + } + + private List sortByEnumValues(Map map, EnumerationType enumType) { + List enumValues = enumType.getValues(); + + return map.entrySet() + .stream() + .sorted(Comparator.comparingInt(entry -> enumValues.indexOf(entry.getKey().getStringValue()))) + .map(Map.Entry::getValue) + .collect(Collectors.toList()); + } + + private ValueKey getEnumValue(IomObject object, PathEl[] enumPath) { + Value value = validator.getValueFromObjectPath(null, object, enumPath, null); + return new ValueKey(value); + } + + private Geometry getGeometryValue(IomObject object, PathEl[] geometryPath) { + Value objects = new Value(Collections.singletonList(object)); + Collection geometryObjects = EvaluationHelper.evaluateAttributes(validator, objects, geometryPath); + + List geometries = geometryObjects.stream() + .map(g -> { + try { + return Iox2jtsext.multisurface2JTS(g, 0, new OutParam<>(), logger, 0, "warning"); + } catch (Exception e) { + logger.addEvent(logger.logWarningMsg("{0}: Failed to convert surface to JTS: {1}", getQualifiedIliName(), e.getLocalizedMessage())); + return null; + } + }) + .filter(Objects::nonNull) + .collect(Collectors.toList()); + + if (geometries.size() == 1) { + return geometries.get(0); + } else { + return new GeometryFactory().buildGeometry(geometries); + } + } + + private static final class ValueKey { + private final Value value; + + ValueKey(Value value) { + this.value = value; + } + + public Type getType() { + return value.getType(); + } + + public String getStringValue() { + return value.getValue(); + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof ValueKey)) { + return false; + } + ValueKey that = (ValueKey) o; + return Objects.equals(getStringValue(), that.getStringValue()) + && Objects.equals(getType(), that.getType()); + } + + @Override + public int hashCode() { + return Objects.hash(getStringValue()); + } + } + + private static final class InsideAreaKey { + private final List objectIds; + private final String geometryAttribute; + private final String enumAttribute; + + InsideAreaKey(List objectIds, String geometryAttribute, String enumAttribute) { + this.objectIds = objectIds; + this.geometryAttribute = geometryAttribute; + this.enumAttribute = enumAttribute; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof InsideAreaKey)) { + return false; + } + InsideAreaKey that = (InsideAreaKey) o; + return objectIds.equals(that.objectIds) + && geometryAttribute.equals(that.geometryAttribute) + && enumAttribute.equals(that.enumAttribute); + } + + @Override + public int hashCode() { + return Objects.hash(objectIds, geometryAttribute, enumAttribute); + } + } +} diff --git a/src/model/NGK_SO_FunctionsExt.ili b/src/model/NGK_SO_FunctionsExt.ili index e29b058..ba30175 100644 --- a/src/model/NGK_SO_FunctionsExt.ili +++ b/src/model/NGK_SO_FunctionsExt.ili @@ -1,5 +1,9 @@ INTERLIS 2.4; MODEL NGK_SO_FunctionsExt AT "mailto:info@geowerkstatt.ch" VERSION "2024-01-23" = - + !!@ fn.description = "Prüft bei der Objektmenge, dass die gemäss dem geordneten Enum jeweils kleineren Flächen innerhalb der grösseren Flächen liegen. Die Sortierung des Enums muss von der kleinsten zur grössten Fläche erfolgen."; + !!@ fn.param = "Objects: Zu prüfende Objektmenge. GeometryAttr: Pfad zur Geometrie. CodeAttr: Pfad zum Enum"; + !!@ fn.return = "Boolean"; + !!@ fn.since = "2024-01-23"; + FUNCTION IsInsideAreaByCodeEnum (Objects: OBJECTS OF ANYCLASS; GeometryAttr: TEXT; CodeAttr: TEXT): BOOLEAN; END NGK_SO_FunctionsExt. \ No newline at end of file diff --git a/src/model/ilimodels.xml b/src/model/ilimodels.xml new file mode 100644 index 0000000..1a7af5f --- /dev/null +++ b/src/model/ilimodels.xml @@ -0,0 +1,8 @@ + + + + +NGK_SO_FunctionsExtili2_4NGK_SO_FunctionsExt.ili2024-01-232024-01-23mailto:info@geowerkstatt.chfalsefde4446812ef76bd0d2bde502b79ee23 + + + \ No newline at end of file diff --git a/src/test/data/IsInsideAreaByCodeEnum/SetConstraints.ili b/src/test/data/IsInsideAreaByCodeEnum/SetConstraints.ili new file mode 100644 index 0000000..0d627b8 --- /dev/null +++ b/src/test/data/IsInsideAreaByCodeEnum/SetConstraints.ili @@ -0,0 +1,31 @@ +INTERLIS 2.4; + +MODEL TestSuite + AT "mailto:info@geowerkstatt.ch" VERSION "2024-01-23" = + IMPORTS NGK_SO_FunctionsExt; + + TOPIC FunctionTestTopic = + + DOMAIN + Code = ( + code_1, + code_2, + code_3, + code_4 + ) ORDERED; + + !!@CRS=EPSG:2056 + CHKoord = COORD 2460000.000 .. 2870000.000 [INTERLIS.m], + 1045000.000 .. 1310000.000 [INTERLIS.m], + ROTATION 2 -> 1; + + CLASS BaseClass = + code : Code; + surface : SURFACE WITH (STRAIGHTS) VERTEX CHKoord WITHOUT OVERLAPS > 0.001; + + SET CONSTRAINT insideAreaConstraint: NGK_SO_FunctionsExt.IsInsideAreaByCodeEnum(ALL, "surface", "code"); + END BaseClass; + + END FunctionTestTopic; + +END TestSuite. diff --git a/src/test/data/IsInsideAreaByCodeEnum/TestData_Fail.xtf b/src/test/data/IsInsideAreaByCodeEnum/TestData_Fail.xtf new file mode 100644 index 0000000..d40200c --- /dev/null +++ b/src/test/data/IsInsideAreaByCodeEnum/TestData_Fail.xtf @@ -0,0 +1,519 @@ + + + + + NGK_SO_FunctionsExt + TestSuite + + ili2gpkg-4.6.1-63db90def1260a503f0f2d4cb846686cd4851184 + + + + + code_1 + + + + + + 2611323.682 + 1251904.796 + + + 2611291.226 + 1251900.532 + + + 2611289.584 + 1251902.360 + + + 2611278.843 + 1251912.085 + + + 2611273.062 + 1251926.488 + + + 2611271.242 + 1251940.201 + + + 2611271.598 + 1251948.324 + + + 2611276.923 + 1251956.926 + + + 2611306.914 + 1251961.624 + + + 2611326.146 + 1251963.573 + + + 2611328.639 + 1251964.018 + + + 2611331.004 + 1251963.358 + + + 2611330.966 + 1251953.980 + + + 2611331.267 + 1251949.788 + + + 2611331.337 + 1251937.093 + + + 2611329.869 + 1251931.573 + + + 2611323.872 + 1251933.889 + + + 2611313.731 + 1251931.441 + + + 2611302.967 + 1251926.348 + + + 2611306.655 + 1251923.491 + + + 2611317.624 + 1251921.488 + + + 2611318.853 + 1251923.074 + + + 2611320.260 + 1251923.253 + + + 2611321.622 + 1251919.945 + + + 2611323.611 + 1251919.389 + + + 2611328.168 + 1251917.546 + + + 2611327.916 + 1251909.472 + + + 2611323.682 + 1251904.796 + + + + + + + + code_2 + + + + + + 2611252.578 + 1251937.687 + + + 2611252.916 + 1251936.217 + + + 2611255.488 + 1251944.784 + + + 2611257.371 + 1251947.535 + + + 2611276.923 + 1251956.926 + + + 2611306.914 + 1251961.624 + + + 2611326.146 + 1251963.573 + + + 2611328.639 + 1251964.018 + + + 2611331.004 + 1251963.358 + + + 2611330.966 + 1251953.980 + + + 2611331.267 + 1251949.788 + + + 2611331.337 + 1251937.093 + + + 2611329.869 + 1251931.573 + + + 2611323.872 + 1251933.889 + + + 2611313.731 + 1251931.441 + + + 2611302.967 + 1251926.348 + + + 2611306.655 + 1251923.491 + + + 2611317.624 + 1251921.488 + + + 2611318.853 + 1251923.074 + + + 2611320.260 + 1251923.253 + + + 2611321.622 + 1251919.945 + + + 2611323.611 + 1251919.389 + + + 2611328.168 + 1251917.546 + + + 2611327.916 + 1251909.472 + + + 2611323.682 + 1251904.796 + + + 2611291.226 + 1251900.532 + + + 2611280.504 + 1251898.817 + + + 2611263.991 + 1251893.017 + + + 2611259.675 + 1251893.225 + + + 2611235.107 + 1251916.816 + + + 2611222.058 + 1251931.586 + + + 2611225.265 + 1251937.127 + + + 2611240.147 + 1251946.456 + + + 2611255.091 + 1251946.439 + + + 2611255.451 + 1251946.611 + + + 2611252.578 + 1251937.687 + + + + + + + + code_3 + + + + + + 2611323.682 + 1251904.796 + + + 2611291.226 + 1251900.532 + + + 2611280.504 + 1251898.817 + + + 2611274.298 + 1251901.379 + + + 2611261.180 + 1251910.522 + + + 2611257.502 + 1251921.262 + + + 2611254.030 + 1251932.118 + + + 2611257.372 + 1251941.318 + + + 2611261.968 + 1251949.060 + + + 2611276.923 + 1251956.926 + + + 2611306.914 + 1251961.624 + + + 2611326.146 + 1251963.573 + + + 2611328.639 + 1251964.018 + + + 2611331.004 + 1251963.358 + + + 2611330.966 + 1251953.980 + + + 2611331.267 + 1251949.788 + + + 2611331.337 + 1251937.093 + + + 2611329.869 + 1251931.573 + + + 2611323.872 + 1251933.889 + + + 2611313.731 + 1251931.441 + + + 2611302.967 + 1251926.348 + + + 2611306.655 + 1251923.491 + + + 2611317.624 + 1251921.488 + + + 2611318.853 + 1251923.074 + + + 2611320.260 + 1251923.253 + + + 2611321.622 + 1251919.945 + + + 2611323.611 + 1251919.389 + + + 2611328.168 + 1251917.546 + + + 2611327.916 + 1251909.472 + + + 2611323.682 + 1251904.796 + + + + + + + + code_4 + + + + + + 2611276.923 + 1251956.926 + + + 2611271.598 + 1251948.324 + + + 2611271.242 + 1251940.201 + + + 2611273.062 + 1251926.488 + + + 2611278.843 + 1251912.085 + + + 2611289.584 + 1251902.360 + + + 2611291.226 + 1251900.532 + + + 2611280.504 + 1251898.817 + + + 2611263.991 + 1251893.017 + + + 2611259.675 + 1251893.225 + + + 2611239.478 + 1251912.315 + + + 2611222.058 + 1251931.586 + + + 2611225.265 + 1251937.127 + + + 2611240.147 + 1251946.456 + + + 2611255.091 + 1251946.439 + + + 2611255.451 + 1251946.611 + + + 2611252.578 + 1251937.687 + + + 2611252.916 + 1251936.217 + + + 2611255.488 + 1251944.784 + + + 2611257.371 + 1251947.535 + + + 2611276.923 + 1251956.926 + + + + + + + + + diff --git a/src/test/data/IsInsideAreaByCodeEnum/TestData_Ok.xtf b/src/test/data/IsInsideAreaByCodeEnum/TestData_Ok.xtf new file mode 100644 index 0000000..60f4b77 --- /dev/null +++ b/src/test/data/IsInsideAreaByCodeEnum/TestData_Ok.xtf @@ -0,0 +1,216 @@ + + + + + NGK_SO_FunctionsExt + TestSuite + + ili2gpkg-4.6.1-63db90def1260a503f0f2d4cb846686cd4851184 + + + + + code_2 + + + + + + 2610694.709 + 1252827.313 + + + 2610694.702 + 1252837.713 + + + 2610701.303 + 1252857.193 + + + 2610699.983 + 1252867.142 + + + 2610692.587 + 1252885.062 + + + 2610695.983 + 1252881.561 + + + 2610704.247 + 1252876.897 + + + 2610709.701 + 1252872.718 + + + 2610711.759 + 1252856.110 + + + 2610710.200 + 1252847.868 + + + 2610706.521 + 1252846.782 + + + 2610704.147 + 1252829.103 + + + 2610694.709 + 1252827.313 + + + + + + + + code_1 + + + + + + 2610694.709 + 1252827.313 + + + 2610694.702 + 1252837.713 + + + 2610701.303 + 1252857.193 + + + 2610699.983 + 1252867.142 + + + 2610692.587 + 1252885.062 + + + 2610695.983 + 1252881.561 + + + 2610698.789 + 1252879.561 + + + 2610700.537 + 1252877.493 + + + 2610702.749 + 1252872.262 + + + 2610704.808 + 1252870.063 + + + 2610704.917 + 1252859.641 + + + 2610703.413 + 1252857.197 + + + 2610701.661 + 1252846.152 + + + 2610701.078 + 1252838.169 + + + 2610701.136 + 1252828.553 + + + 2610694.709 + 1252827.313 + + + + + + + + code_3 + + + + + + 2610694.709 + 1252827.313 + + + 2610694.702 + 1252837.713 + + + 2610701.303 + 1252857.193 + + + 2610699.983 + 1252867.142 + + + 2610692.587 + 1252885.062 + + + 2610695.983 + 1252881.561 + + + 2610704.247 + 1252876.897 + + + 2610709.701 + 1252872.718 + + + 2610711.759 + 1252856.110 + + + 2610710.200 + 1252847.868 + + + 2610706.521 + 1252846.782 + + + 2610704.147 + 1252829.103 + + + 2610694.709 + 1252827.313 + + + + + + + + + diff --git a/src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/IsInsideAreaByCodeEnumIoxPluginTest.java b/src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/IsInsideAreaByCodeEnumIoxPluginTest.java new file mode 100644 index 0000000..47889d8 --- /dev/null +++ b/src/test/java/ch/geowerkstatt/ilivalidator/extensions/functions/ngk/IsInsideAreaByCodeEnumIoxPluginTest.java @@ -0,0 +1,34 @@ +package ch.geowerkstatt.ilivalidator.extensions.functions.ngk; + +import ch.interlis.ili2c.Ili2cFailure; +import ch.interlis.iox.IoxException; +import com.vividsolutions.jts.util.Assert; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public final class IsInsideAreaByCodeEnumIoxPluginTest { + private static final String ILI_FILE = "IsInsideAreaByCodeEnum/SetConstraints.ili"; + private static final String TEST_DATA_OK = "IsInsideAreaByCodeEnum/TestData_Ok.xtf"; + private static final String TEST_DATA_FAIL = "IsInsideAreaByCodeEnum/TestData_Fail.xtf"; + private ValidationTestHelper vh = null; + + @BeforeEach + public void setUp() { + vh = new ValidationTestHelper(); + vh.addFunction(new IsInsideAreaByCodeEnumIoxPlugin()); + } + + @Test + public void setConstraintOk() throws Ili2cFailure, IoxException { + vh.runValidation(new String[]{TEST_DATA_OK}, new String[]{ILI_FILE}); + Assert.equals(0, vh.getErrs().size()); + AssertionHelper.assertNoConstraintError(vh, "insideAreaConstraint"); + } + + @Test + public void setConstraintFail() throws Ili2cFailure, IoxException { + vh.runValidation(new String[]{TEST_DATA_FAIL}, new String[]{ILI_FILE}); + Assert.equals(1, vh.getErrs().size()); + AssertionHelper.assertConstraintErrors(vh, 1, "insideAreaConstraint"); + } +} From 1fd53a47ba83e6d962969d6cd6d7738472546970 Mon Sep 17 00:00:00 2001 From: Dominic Burger Date: Tue, 30 Jan 2024 08:31:06 +0100 Subject: [PATCH 3/3] Test IsInsideAreaByCodeEnum with gap in codes --- src/test/data/IsInsideAreaByCodeEnum/TestData_Ok.xtf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/data/IsInsideAreaByCodeEnum/TestData_Ok.xtf b/src/test/data/IsInsideAreaByCodeEnum/TestData_Ok.xtf index 60f4b77..2fa12e9 100644 --- a/src/test/data/IsInsideAreaByCodeEnum/TestData_Ok.xtf +++ b/src/test/data/IsInsideAreaByCodeEnum/TestData_Ok.xtf @@ -10,7 +10,7 @@ - + code_2 @@ -149,7 +149,7 @@ - code_3 + code_4