diff --git a/xapi-model/pom.xml b/xapi-model/pom.xml index 2a473e5e..f5cfe6b4 100644 --- a/xapi-model/pom.xml +++ b/xapi-model/pom.xml @@ -31,7 +31,7 @@ org.hibernate.validator hibernate-validator true - + org.springframework.boot spring-boot-starter-test diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/Result.java b/xapi-model/src/main/java/dev/learning/xapi/model/Result.java index 4772f353..f6d63ebd 100644 --- a/xapi-model/src/main/java/dev/learning/xapi/model/Result.java +++ b/xapi-model/src/main/java/dev/learning/xapi/model/Result.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import dev.learning.xapi.model.validation.constraints.HasScheme; +import dev.learning.xapi.model.validation.constraints.VaildScore; import jakarta.validation.Valid; import jakarta.validation.constraints.Pattern; import java.net.URI; @@ -32,6 +33,7 @@ public class Result { * The score of the Agent in relation to the success or quality of the experience. */ @Valid + @VaildScore private Score score; /** diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/validation/constraints/VaildScore.java b/xapi-model/src/main/java/dev/learning/xapi/model/validation/constraints/VaildScore.java new file mode 100644 index 00000000..65d15240 --- /dev/null +++ b/xapi-model/src/main/java/dev/learning/xapi/model/validation/constraints/VaildScore.java @@ -0,0 +1,44 @@ +/* + * Copyright 2016-2019 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.model.validation.constraints; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import jakarta.validation.Constraint; +import jakarta.validation.Payload; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * The annotated element must be a valid score. + * + * @author Thomas Turrell-Croft + * + * @see Score + */ +@Documented +@Constraint(validatedBy = {}) +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface VaildScore { + + /** + * Error Message. + */ + String message() default "must be a valid score"; + + /** + * Groups. + */ + Class[] groups() default {}; + + /** + * Payload. + */ + Class[] payload() default {}; +} diff --git a/xapi-model/src/main/java/dev/learning/xapi/model/validation/internal/validators/ScoreValidator.java b/xapi-model/src/main/java/dev/learning/xapi/model/validation/internal/validators/ScoreValidator.java new file mode 100644 index 00000000..746d6915 --- /dev/null +++ b/xapi-model/src/main/java/dev/learning/xapi/model/validation/internal/validators/ScoreValidator.java @@ -0,0 +1,30 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.model.validation.internal.validators; + +import dev.learning.xapi.model.Score; +import dev.learning.xapi.model.validation.constraints.VaildScore; +import jakarta.validation.ConstraintValidator; +import jakarta.validation.ConstraintValidatorContext; + +/** + * The raw score must be greater or equal to min and less or equal to max. + * + * @author István Rátkai (Selindek) + */ +public class ScoreValidator implements ConstraintValidator { + + @Override + public boolean isValid(Score value, ConstraintValidatorContext context) { + + if (value == null) { + return true; + } + + return (value.getMax() == null || value.getMax() >= value.getRaw()) + && (value.getMin() == null || value.getMin() <= value.getRaw()); + } + +} diff --git a/xapi-model/src/main/resources/META-INF/services/jakarta.validation.ConstraintValidator b/xapi-model/src/main/resources/META-INF/services/jakarta.validation.ConstraintValidator index 77c1c051..fd019e08 100644 --- a/xapi-model/src/main/resources/META-INF/services/jakarta.validation.ConstraintValidator +++ b/xapi-model/src/main/resources/META-INF/services/jakarta.validation.ConstraintValidator @@ -10,3 +10,4 @@ dev.learning.xapi.model.validation.internal.validators.StatementRevisionValidato dev.learning.xapi.model.validation.internal.validators.StatementPlatformValidator dev.learning.xapi.model.validation.internal.validators.StatementVerbValidator dev.learning.xapi.model.validation.internal.validators.StatementsValidator +dev.learning.xapi.model.validation.internal.validators.ScoreValidator diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/validation/internal/validators/ScaledScoreValidatorTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/validation/internal/validators/ScaledScoreValidatorTests.java index 76378e17..9f6a36df 100644 --- a/xapi-model/src/test/java/dev/learning/xapi/model/validation/internal/validators/ScaledScoreValidatorTests.java +++ b/xapi-model/src/test/java/dev/learning/xapi/model/validation/internal/validators/ScaledScoreValidatorTests.java @@ -15,7 +15,7 @@ * * @author István Rátkai (Selindek) */ -@DisplayName("ScaledSoreValidator tests") +@DisplayName("ScaledScoreValidator tests") class ScaledScoreValidatorTests { private static final ScaledScoreValidator validator = new ScaledScoreValidator(); diff --git a/xapi-model/src/test/java/dev/learning/xapi/model/validation/internal/validators/ScoreValidatorTests.java b/xapi-model/src/test/java/dev/learning/xapi/model/validation/internal/validators/ScoreValidatorTests.java new file mode 100644 index 00000000..41b7b854 --- /dev/null +++ b/xapi-model/src/test/java/dev/learning/xapi/model/validation/internal/validators/ScoreValidatorTests.java @@ -0,0 +1,88 @@ +/* + * Copyright 2016-2023 Berry Cloud Ltd. All rights reserved. + */ + +package dev.learning.xapi.model.validation.internal.validators; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import dev.learning.xapi.model.Score; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +/** + * ScoreValidator Tests. + * + * @author Thomas Turrell-Croft + */ +@DisplayName("ScoreValidator tests") +class ScoreValidatorTests { + + private static final ScoreValidator validator = new ScoreValidator(); + + @Test + void whenValueIsNullThenResultIsTrue() { + + // When Value Is Null + final var result = validator.isValid(null, null); + + // Then Result Is True + assertTrue(result); + } + + @ParameterizedTest + @CsvSource({"0,100,50", "0,100,0", "0,100,100", "-100,0,-50"}) + void whenCallingIsValidWithValidScoreThenResultIsTrue(float min, float max, float raw) { + + final var s = Score.builder().min(min).max(max).raw(raw).build(); + + // When Calling Is Valid With Valid Score + final var result = validator.isValid(s, null); + + // Then Result Is True + assertTrue(result); + } + + @ParameterizedTest + @CsvSource({"0,100,101", "0,100,-1"}) + void whenCallingIsValidWithInvalidScoreThenResultIsFalse(float min, float max, float raw) { + + final var s = Score.builder().min(min).max(max).raw(raw).build(); + + // When Calling Is Valid With Invalid Score + final var result = validator.isValid(s, null); + + // Then Result Is False + assertFalse(result); + } + + @Test + void whenCallingIsValidWithAScoreWithMinNullThenResultIsTrue() { + + final var s = Score.builder().min(null).max(100F).raw(50F).build(); + + // When Calling Is Valid With A Score With Min Null + final var result = validator.isValid(s, null); + + // Then Result Is True + assertTrue(result); + } + + @Test + void whenCallingIsValidWithAScoreWithMaxNullThenResultIsTrue() { + + final var s = Score.builder().min(0F).max(null).raw(50F).build(); + + // When Calling Is Valid With A Score With Max Null + final var result = validator.isValid(s, null); + + // Then Result Is True + assertTrue(result); + } + + + +}