From 71874ddbd1a06a8d5edd3d791b0d0d875bf7e4ac Mon Sep 17 00:00:00 2001 From: MBorne Date: Wed, 30 Jun 2021 17:37:37 +0200 Subject: [PATCH] validator-core - AttributeContraints - add minLength constraints (refs #154) --- .../ign/validator/error/CoreErrorCodes.java | 2 + .../validator/model/AttributeConstraints.java | 15 +- .../validator/model/type/FilenameType.java | 2 + .../fr/ign/validator/model/type/PathType.java | 2 + .../ign/validator/model/type/StringType.java | 4 + .../fr/ign/validator/model/type/UrlType.java | 2 + .../attribute/MinLengthValidator.java | 42 +++++ .../src/main/resources/error-code.json | 6 + .../ign/validator/io/JsonModelReaderTest.java | 4 + .../attribute/MinLengthValidatorTest.java | 156 ++++++++++++++++++ .../config-json/adresse/types/ADRESSE.json | 1 + 11 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 validator-core/src/main/java/fr/ign/validator/validation/attribute/MinLengthValidator.java create mode 100644 validator-core/src/test/java/fr/ign/validator/validation/attribute/MinLengthValidatorTest.java diff --git a/validator-core/src/main/java/fr/ign/validator/error/CoreErrorCodes.java b/validator-core/src/main/java/fr/ign/validator/error/CoreErrorCodes.java index 60a60c65..39e54a46 100644 --- a/validator-core/src/main/java/fr/ign/validator/error/CoreErrorCodes.java +++ b/validator-core/src/main/java/fr/ign/validator/error/CoreErrorCodes.java @@ -176,7 +176,9 @@ public class CoreErrorCodes { * ErrorCode for error in Features and Attributes */ public static final ErrorCode ATTRIBUTE_INVALID_FORMAT = ErrorCode.valueOf("ATTRIBUTE_INVALID_FORMAT"); + public static final ErrorCode ATTRIBUTE_SIZE_TOO_SHORT = ErrorCode.valueOf("ATTRIBUTE_SIZE_TOO_SHORT"); public static final ErrorCode ATTRIBUTE_SIZE_EXCEEDED = ErrorCode.valueOf("ATTRIBUTE_SIZE_EXCEEDED"); + public static final ErrorCode ATTRIBUTE_INVALID_REGEXP = ErrorCode.valueOf("ATTRIBUTE_INVALID_REGEXP"); public static final ErrorCode ATTRIBUTE_UNEXPECTED_VALUE = ErrorCode.valueOf("ATTRIBUTE_UNEXPECTED_VALUE"); public static final ErrorCode ATTRIBUTE_UNEXPECTED_NULL = ErrorCode.valueOf("ATTRIBUTE_UNEXPECTED_NULL"); diff --git a/validator-core/src/main/java/fr/ign/validator/model/AttributeConstraints.java b/validator-core/src/main/java/fr/ign/validator/model/AttributeConstraints.java index 979968db..64d82960 100644 --- a/validator-core/src/main/java/fr/ign/validator/model/AttributeConstraints.java +++ b/validator-core/src/main/java/fr/ign/validator/model/AttributeConstraints.java @@ -46,7 +46,12 @@ public class AttributeConstraints { */ private String pattern; - // TODO add private Integer minLength + /** + * Minimum length of the value + * + * @since 4.1 + */ + private Integer minLength; /** * Maximum length of the value @@ -113,6 +118,14 @@ public void setMaxLength(Integer maxLength) { this.maxLength = maxLength; } + public Integer getMinLength() { + return minLength; + } + + public void setMinLength(Integer minLength) { + this.minLength = minLength; + } + /** * Tell if enum restriction is defined * diff --git a/validator-core/src/main/java/fr/ign/validator/model/type/FilenameType.java b/validator-core/src/main/java/fr/ign/validator/model/type/FilenameType.java index 7a4a1bde..ced5d802 100644 --- a/validator-core/src/main/java/fr/ign/validator/model/type/FilenameType.java +++ b/validator-core/src/main/java/fr/ign/validator/model/type/FilenameType.java @@ -8,6 +8,7 @@ import fr.ign.validator.model.AttributeType; import fr.ign.validator.validation.attribute.FilenameExistsValidator; import fr.ign.validator.validation.attribute.MaxLengthValidator; +import fr.ign.validator.validation.attribute.MinLengthValidator; /** * @@ -24,6 +25,7 @@ public class FilenameType extends AttributeType { public FilenameType() { super(File.class); + addValidator(new MinLengthValidator()); addValidator(new MaxLengthValidator()); addValidator(new FilenameExistsValidator()); } diff --git a/validator-core/src/main/java/fr/ign/validator/model/type/PathType.java b/validator-core/src/main/java/fr/ign/validator/model/type/PathType.java index 2e362efa..e4f50d7c 100644 --- a/validator-core/src/main/java/fr/ign/validator/model/type/PathType.java +++ b/validator-core/src/main/java/fr/ign/validator/model/type/PathType.java @@ -8,6 +8,7 @@ import fr.ign.validator.model.AttributeType; import fr.ign.validator.validation.attribute.PathExistsValidator; import fr.ign.validator.validation.attribute.MaxLengthValidator; +import fr.ign.validator.validation.attribute.MinLengthValidator; /** * @@ -22,6 +23,7 @@ public class PathType extends AttributeType { public PathType() { super(File.class); + addValidator(new MinLengthValidator()); addValidator(new MaxLengthValidator()); addValidator(new PathExistsValidator()); } diff --git a/validator-core/src/main/java/fr/ign/validator/model/type/StringType.java b/validator-core/src/main/java/fr/ign/validator/model/type/StringType.java index 881be83a..9e259c66 100644 --- a/validator-core/src/main/java/fr/ign/validator/model/type/StringType.java +++ b/validator-core/src/main/java/fr/ign/validator/model/type/StringType.java @@ -1,11 +1,14 @@ package fr.ign.validator.model.type; +import java.io.File; + import com.fasterxml.jackson.annotation.JsonTypeName; import fr.ign.validator.model.AttributeType; import fr.ign.validator.validation.attribute.StringEnumValuesValidator; import fr.ign.validator.validation.attribute.StringPatternValidator; import fr.ign.validator.validation.attribute.MaxLengthValidator; +import fr.ign.validator.validation.attribute.MinLengthValidator; /** * Represents a character string @@ -20,6 +23,7 @@ public class StringType extends AttributeType { public StringType() { super(String.class); + addValidator(new MinLengthValidator()); addValidator(new MaxLengthValidator()); addValidator(new StringPatternValidator()); addValidator(new StringEnumValuesValidator()); diff --git a/validator-core/src/main/java/fr/ign/validator/model/type/UrlType.java b/validator-core/src/main/java/fr/ign/validator/model/type/UrlType.java index 24d54e97..96e5ae33 100644 --- a/validator-core/src/main/java/fr/ign/validator/model/type/UrlType.java +++ b/validator-core/src/main/java/fr/ign/validator/model/type/UrlType.java @@ -7,6 +7,7 @@ import fr.ign.validator.model.AttributeType; import fr.ign.validator.validation.attribute.MaxLengthValidator; +import fr.ign.validator.validation.attribute.MinLengthValidator; /** * Location of a file @@ -20,6 +21,7 @@ public class UrlType extends AttributeType { public UrlType() { super(URL.class); + addValidator(new MinLengthValidator()); addValidator(new MaxLengthValidator()); } diff --git a/validator-core/src/main/java/fr/ign/validator/validation/attribute/MinLengthValidator.java b/validator-core/src/main/java/fr/ign/validator/validation/attribute/MinLengthValidator.java new file mode 100644 index 00000000..7310a60e --- /dev/null +++ b/validator-core/src/main/java/fr/ign/validator/validation/attribute/MinLengthValidator.java @@ -0,0 +1,42 @@ +package fr.ign.validator.validation.attribute; + +import fr.ign.validator.Context; +import fr.ign.validator.data.Attribute; +import fr.ign.validator.error.CoreErrorCodes; +import fr.ign.validator.model.AttributeConstraints; +import fr.ign.validator.validation.Validator; + +/** + * + * Validates the size of a StringType Attribute + * + * @author MBorne + * + */ +public class MinLengthValidator implements Validator> { + + @Override + public void validate(Context context, Attribute attribute) { + T value = attribute.getBindedValue(); + + if (value == null) { + return; + } + + AttributeConstraints constraints = attribute.getType().getConstraints(); + Integer minLength = constraints.getMinLength(); + if (minLength == null || minLength < 0) { + return; + } + + int length = value.toString().length(); + if (length < minLength) { + context.report( + context.createError(CoreErrorCodes.ATTRIBUTE_SIZE_TOO_SHORT) + .setMessageParam("VALUE_LENGTH", String.valueOf(length)) + .setMessageParam("EXPECTED_LENGTH", minLength.toString()) + ); + } + } + +} diff --git a/validator-core/src/main/resources/error-code.json b/validator-core/src/main/resources/error-code.json index 1bdfc0b0..6c0820ff 100644 --- a/validator-core/src/main/resources/error-code.json +++ b/validator-core/src/main/resources/error-code.json @@ -141,6 +141,12 @@ "message": "La valeur ({VALUE}) ne correspond pas à l'expression régulière ({REGEXP}).", "documentation": "Cette erreur se produit lorsqu'un champ contient une chaine de caractère qui ne correspond pas à la règle d'écriture du modèle." }, + { + "name": "ATTRIBUTE_SIZE_TOO_SHORT", + "level": "ERROR", + "message": "La taille de l'attribut ({VALUE_LENGTH}) est en dessous la taille minimale autorisée ({EXPECTED_LENGTH}).", + "documentation": "Cette erreur se produit lorsqu'un champ contient une valeur dont la longueur est inférieure à la taille minimale autorisée par le modèle" + }, { "name": "ATTRIBUTE_SIZE_EXCEEDED", "level": "ERROR", diff --git a/validator-core/src/test/java/fr/ign/validator/io/JsonModelReaderTest.java b/validator-core/src/test/java/fr/ign/validator/io/JsonModelReaderTest.java index 5947b8b1..ff71cdbf 100644 --- a/validator-core/src/test/java/fr/ign/validator/io/JsonModelReaderTest.java +++ b/validator-core/src/test/java/fr/ign/validator/io/JsonModelReaderTest.java @@ -158,6 +158,10 @@ private void assertExceptedFeatureTypeAdresse(FeatureType featureType) { Assert.assertFalse( attribute.getConstraints().isUnique() ); + Assert.assertEquals( + Integer.valueOf(5), + attribute.getConstraints().getMinLength() + ); Assert.assertEquals( Integer.valueOf(254), attribute.getConstraints().getMaxLength() diff --git a/validator-core/src/test/java/fr/ign/validator/validation/attribute/MinLengthValidatorTest.java b/validator-core/src/test/java/fr/ign/validator/validation/attribute/MinLengthValidatorTest.java new file mode 100644 index 00000000..0e9e7681 --- /dev/null +++ b/validator-core/src/test/java/fr/ign/validator/validation/attribute/MinLengthValidatorTest.java @@ -0,0 +1,156 @@ +package fr.ign.validator.validation.attribute; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import fr.ign.validator.Context; +import fr.ign.validator.data.Attribute; +import fr.ign.validator.error.ValidatorError; +import fr.ign.validator.model.type.FilenameType; +import fr.ign.validator.model.type.PathType; +import fr.ign.validator.model.type.StringType; +import fr.ign.validator.model.type.UrlType; +import fr.ign.validator.report.InMemoryReportBuilder; + +public class MinLengthValidatorTest { + + private Context context; + + private InMemoryReportBuilder report; + + @Before + public void setUp() throws Exception { + context = new Context(); + report = new InMemoryReportBuilder(); + context.setReportBuilder(report); + } + + @Test + public void testStringTypeNoLimit() { + MinLengthValidator validator = new MinLengthValidator<>(); + StringType type = new StringType(); + Attribute attribute = new Attribute(type, "abc"); + validator.validate(context, attribute); + Assert.assertEquals(0, report.countErrors()); + } + + @Test + public void testStringTypeMoreThanLimit() { + MinLengthValidator validator = new MinLengthValidator<>(); + StringType type = new StringType(); + type.getConstraints().setMinLength(2); + Attribute attribute = new Attribute(type, "abc"); + validator.validate(context, attribute); + Assert.assertEquals(0, report.countErrors()); + } + + @Test + public void testStringTypeEqualLimit() { + MinLengthValidator validator = new MinLengthValidator<>(); + StringType type = new StringType(); + type.getConstraints().setMinLength(5); + Attribute attribute = new Attribute(type, "abcde"); + validator.validate(context, attribute); + Assert.assertEquals(0, report.countErrors()); + } + + @Test + public void testStringTypeLessThanLimit() { + MinLengthValidator validator = new MinLengthValidator<>(); + StringType type = new StringType(); + type.getConstraints().setMinLength(5); + Attribute attribute = new Attribute(type, "abcd"); + validator.validate(context, attribute); + Assert.assertEquals(1, report.countErrors()); + + ValidatorError error = report.getErrors().get(0); + Assert.assertEquals( + "La taille de l'attribut (4) est en dessous la taille minimale autorisée (5).", + error.getMessage() + ); + } + + @Test + public void testUrlTypeNull() { + MinLengthValidator validator = new MinLengthValidator<>(); + UrlType type = new UrlType(); + type.getConstraints().setMinLength(10); + Attribute attribute = new Attribute(type, null); + validator.validate(context, attribute); + Assert.assertEquals(0, report.countErrors()); + } + + @Test + public void testUrlTypeMoreThanLimit() throws MalformedURLException { + MinLengthValidator validator = new MinLengthValidator<>(); + UrlType type = new UrlType(); + type.getConstraints().setMinLength(50); + Attribute attribute = new Attribute(type, new URL("https://example.org/something")); + validator.validate(context, attribute); + Assert.assertEquals(1, report.countErrors()); + + ValidatorError error = report.getErrors().get(0); + Assert.assertEquals( + "La taille de l'attribut (29) est en dessous la taille minimale autorisée (50).", + error.getMessage() + ); + } + + @Test + public void testPathTypeNull() { + MinLengthValidator validator = new MinLengthValidator<>(); + PathType type = new PathType(); + type.getConstraints().setMinLength(5); + Attribute attribute = new Attribute(type, null); + validator.validate(context, attribute); + Assert.assertEquals(0, report.countErrors()); + } + + @Test + public void testPathTypeLessThanLimit() { + MinLengthValidator validator = new MinLengthValidator<>(); + PathType type = new PathType(); + type.getConstraints().setMinLength(10); + Attribute attribute = new Attribute(type, new File("abcd.pdf")); + validator.validate(context, attribute); + Assert.assertEquals(1, report.countErrors()); + + ValidatorError error = report.getErrors().get(0); + Assert.assertEquals( + "La taille de l'attribut (8) est en dessous la taille minimale autorisée (10).", + error.getMessage() + ); + } + + @Test + public void testFilenameTypeNull() { + MinLengthValidator validator = new MinLengthValidator<>(); + FilenameType type = new FilenameType(); + type.getConstraints().setMinLength(5); + Attribute attribute = new Attribute(type, null); + validator.validate(context, attribute); + Assert.assertEquals(0, report.countErrors()); + } + + @Test + public void testFilenameTypeLessThanLimit() { + MinLengthValidator validator = new MinLengthValidator<>(); + FilenameType type = new FilenameType(); + type.getConstraints().setMinLength(10); + Attribute attribute = new Attribute(type, new File("abcd.pdf")); + validator.validate(context, attribute); + Assert.assertEquals(1, report.countErrors()); + + ValidatorError error = report.getErrors().get(0); + Assert.assertEquals( + "La taille de l'attribut (8) est en dessous la taille minimale autorisée (10).", + error.getMessage() + ); + } + +} diff --git a/validator-core/src/test/resources/config-json/adresse/types/ADRESSE.json b/validator-core/src/test/resources/config-json/adresse/types/ADRESSE.json index 1d8c46dc..e68fc755 100644 --- a/validator-core/src/test/resources/config-json/adresse/types/ADRESSE.json +++ b/validator-core/src/test/resources/config-json/adresse/types/ADRESSE.json @@ -17,6 +17,7 @@ "type": "String", "constraints": { "required": false, + "minLength": 5, "maxLength": 254 } },