diff --git a/src/main/java/it/aboutbits/springboot/testing/validation/core/RuleValidator.java b/src/main/java/it/aboutbits/springboot/testing/validation/core/RuleValidator.java index 48bd79c..1d51f77 100644 --- a/src/main/java/it/aboutbits/springboot/testing/validation/core/RuleValidator.java +++ b/src/main/java/it/aboutbits/springboot/testing/validation/core/RuleValidator.java @@ -117,7 +117,8 @@ private static

void assertThatValidationIsCompliantForEachProperty( // Check if there are any violations assertThat(violations) .withFailMessage( - "More than one property failed to validate during mutation. The supplied parameter is possibly contains invalid values.") + "More than one property failed to validate during mutation. The supplied parameter possibly contains invalid values." + ) .hasSizeLessThan(2); assertThat(violations) diff --git a/src/main/java/it/aboutbits/springboot/testing/validation/source/BiggerThanValueSource.java b/src/main/java/it/aboutbits/springboot/testing/validation/source/BiggerThanValueSource.java index 2072ed2..62f5667 100644 --- a/src/main/java/it/aboutbits/springboot/testing/validation/source/BiggerThanValueSource.java +++ b/src/main/java/it/aboutbits/springboot/testing/validation/source/BiggerThanValueSource.java @@ -5,6 +5,7 @@ import lombok.NonNull; import java.math.BigDecimal; +import java.math.BigInteger; import java.util.HashMap; import java.util.Map; import java.util.Random; @@ -16,6 +17,12 @@ public class BiggerThanValueSource implements ValueSource { private static final Random RANDOM = new Random(); static { + TYPE_SOURCES.put(Byte.class, BiggerThanValueSource::getByteStream); + TYPE_SOURCES.put(byte.class, BiggerThanValueSource::getByteStream); + + TYPE_SOURCES.put(Short.class, BiggerThanValueSource::getShortStream); + TYPE_SOURCES.put(short.class, BiggerThanValueSource::getShortStream); + TYPE_SOURCES.put(Integer.class, BiggerThanValueSource::getIntegerStream); TYPE_SOURCES.put(int.class, BiggerThanValueSource::getIntegerStream); @@ -28,11 +35,12 @@ public class BiggerThanValueSource implements ValueSource { TYPE_SOURCES.put(Double.class, BiggerThanValueSource::getDoubleStream); TYPE_SOURCES.put(double.class, BiggerThanValueSource::getDoubleStream); + TYPE_SOURCES.put(BigInteger.class, BiggerThanValueSource::getBigIntegerStream); TYPE_SOURCES.put(BigDecimal.class, BiggerThanValueSource::getBigDecimalStream); TYPE_SOURCES.put(ScaledBigDecimal.class, BiggerThanValueSource::getScaledBigDecimalStream); } - @SuppressWarnings("unchecked") + @SuppressWarnings("unused") public static void registerType(Class type, Function> source) { TYPE_SOURCES.put(type, source); } @@ -48,6 +56,30 @@ public Stream values(Class propertyClass, Object... args) { throw new IllegalArgumentException("Property class not supported!"); } + @NonNull + private static Stream getByteStream(Object[] args) { + var minValue = (byte) (Long.valueOf((long) args[0]).byteValue() + 1); + var maxValue = Byte.MAX_VALUE; + + return Stream.concat( + Stream.of(minValue, maxValue), + RANDOM.ints(1, minValue, maxValue) + .mapToObj(value -> Byte.valueOf((byte) value)) + ); + } + + @NonNull + private static Stream getShortStream(Object[] args) { + var minValue = (short) (Long.valueOf((long) args[0]).shortValue() + 1); + var maxValue = Short.MAX_VALUE; + + return Stream.concat( + Stream.of(minValue, maxValue), + RANDOM.ints(1, minValue, maxValue) + .mapToObj(value -> Short.valueOf((short) value)) + ); + } + @NonNull private static Stream getIntegerStream(Object[] args) { var minValue = Long.valueOf((long) args[0]).intValue() + 1; @@ -55,7 +87,7 @@ private static Stream getIntegerStream(Object[] args) { return Stream.concat( Stream.of(minValue, maxValue), - RANDOM.ints(minValue, maxValue).limit(1).boxed() + RANDOM.ints(1, minValue, maxValue).boxed() ); } @@ -66,7 +98,7 @@ private static Stream getLongStream(Object[] args) { return Stream.concat( Stream.of(minValue, maxValue), - RANDOM.longs(minValue, maxValue).limit(1).boxed() + RANDOM.longs(1, minValue, maxValue).boxed() ); } @@ -77,7 +109,7 @@ private static Stream getFloatStream(Object[] args) { return Stream.concat( Stream.of(minValue, maxValue), - RANDOM.doubles(minValue, maxValue).limit(1).boxed().map( + RANDOM.doubles(1, minValue, maxValue).boxed().map( Double::floatValue ) ); @@ -90,18 +122,20 @@ private static Stream getDoubleStream(Object[] args) { return Stream.concat( Stream.of(minValue, maxValue), - RANDOM.doubles(minValue, maxValue).limit(1).boxed() + RANDOM.doubles(1, minValue, maxValue).boxed() ); } @NonNull - private static Stream getScaledBigDecimalStream(Object[] args) { - var minValue = Long.valueOf((long) args[0]).doubleValue() + 0.1d; - var maxValue = Double.MAX_VALUE; + private static Stream getBigIntegerStream(Object[] args) { + var minValue = (long) args[0] + 1; + var maxValue = Long.MAX_VALUE; return Stream.concat( - Stream.of(ScaledBigDecimal.valueOf(minValue), ScaledBigDecimal.valueOf(maxValue)), - RANDOM.doubles(minValue, maxValue).limit(1).boxed().map(ScaledBigDecimal::valueOf) + Stream.of(BigInteger.valueOf(minValue), BigInteger.valueOf(maxValue)), + RANDOM.longs(1, minValue, maxValue).boxed().map( + BigInteger::valueOf + ) ); } @@ -112,7 +146,22 @@ private static Stream getBigDecimalStream(Object[] args) { return Stream.concat( Stream.of(BigDecimal.valueOf(minValue), BigDecimal.valueOf(maxValue)), - RANDOM.doubles(minValue, maxValue).limit(1).boxed().map(BigDecimal::valueOf) + RANDOM.doubles(1, minValue, maxValue).boxed().map( + BigDecimal::valueOf + ) + ); + } + + @NonNull + private static Stream getScaledBigDecimalStream(Object[] args) { + var minValue = Long.valueOf((long) args[0]).doubleValue() + 0.1d; + var maxValue = Double.MAX_VALUE; + + return Stream.concat( + Stream.of(ScaledBigDecimal.valueOf(minValue), ScaledBigDecimal.valueOf(maxValue)), + RANDOM.doubles(1, minValue, maxValue).boxed().map( + ScaledBigDecimal::valueOf + ) ); } } diff --git a/src/main/java/it/aboutbits/springboot/testing/validation/source/FutureValueSource.java b/src/main/java/it/aboutbits/springboot/testing/validation/source/FutureValueSource.java index 59d73f6..d1d5db1 100644 --- a/src/main/java/it/aboutbits/springboot/testing/validation/source/FutureValueSource.java +++ b/src/main/java/it/aboutbits/springboot/testing/validation/source/FutureValueSource.java @@ -2,10 +2,17 @@ import it.aboutbits.springboot.testing.validation.core.ValueSource; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Year; +import java.time.YearMonth; import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.util.HashMap; import java.util.Map; import java.util.function.Function; @@ -14,10 +21,17 @@ public class FutureValueSource implements ValueSource { private static final Map, Function>> TYPE_SOURCES = new HashMap<>(); + // https://jakarta.ee/specifications/bean-validation/3.0/apidocs/jakarta/validation/constraints/future static { + TYPE_SOURCES.put(Instant.class, FutureValueSource::getInstantStream); + TYPE_SOURCES.put(LocalTime.class, FutureValueSource::getLocalTimeStream); TYPE_SOURCES.put(LocalDate.class, FutureValueSource::getLocalDateStream); - TYPE_SOURCES.put(LocalDateTime.class, FutureValueSource::getLocalDatetimeStream); + TYPE_SOURCES.put(LocalDateTime.class, FutureValueSource::getLocalDateTimeStream); + TYPE_SOURCES.put(OffsetTime.class, FutureValueSource::getOffsetTimeStream); TYPE_SOURCES.put(OffsetDateTime.class, FutureValueSource::getOffsetDateTimeStream); + TYPE_SOURCES.put(Year.class, FutureValueSource::getYearStream); + TYPE_SOURCES.put(YearMonth.class, FutureValueSource::getYearMonthStream); + TYPE_SOURCES.put(ZonedDateTime.class, FutureValueSource::getZonedDateTimeStream); } @SuppressWarnings("unused") @@ -36,24 +50,66 @@ public Stream values(Class propertyClass, Object... args) { throw new IllegalArgumentException("Property class not supported!"); } + private static Stream getInstantStream(Object[] args) { + var currentInstant = Instant.now(); + var largestInstant = Instant.MAX; + + return Stream.of(currentInstant.plusSeconds(1L), largestInstant); + } + + private static Stream getLocalTimeStream(Object[] args) { + var currentLocalTime = LocalTime.now(); + var largestLocalTime = LocalTime.MAX; + + return Stream.of(currentLocalTime.plusSeconds(1L), largestLocalTime); + } + private static Stream getLocalDateStream(Object[] args) { var currentDate = LocalDate.now(); var largestDate = LocalDate.MAX; - return Stream.of(currentDate.plusDays(1), largestDate); + return Stream.of(currentDate.plusDays(1L), largestDate); } - private static Stream getLocalDatetimeStream(Object[] args) { + private static Stream getLocalDateTimeStream(Object[] args) { var currentDateTime = LocalDateTime.now(); var largestDateTime = LocalDateTime.MAX; - return Stream.of(currentDateTime.plusSeconds(1), largestDateTime); + return Stream.of(currentDateTime.plusSeconds(1L), largestDateTime); + } + + private static Stream getOffsetTimeStream(Object[] args) { + var currentOffsetTime = OffsetTime.now(ZoneOffset.UTC); + var largestOffsetTime = OffsetTime.MAX; + + return Stream.of(currentOffsetTime.plusSeconds(1L), largestOffsetTime); } private static Stream getOffsetDateTimeStream(Object[] args) { var currentOffsetDateTime = OffsetDateTime.now(ZoneOffset.UTC); var largestOffsetDateTime = OffsetDateTime.MAX; - return Stream.of(currentOffsetDateTime.plusSeconds(1), largestOffsetDateTime); + return Stream.of(currentOffsetDateTime.plusSeconds(1L), largestOffsetDateTime); + } + + private static Stream getYearStream(Object[] args) { + var currentYear = Year.now(); + var largestYear = Year.of(Year.MAX_VALUE); + + return Stream.of(currentYear.plusYears(1L), largestYear); + } + + private static Stream getYearMonthStream(Object[] args) { + var currentYearMonth = YearMonth.now(); + var largestYearMonth = YearMonth.of(Year.MAX_VALUE, Month.DECEMBER); + + return Stream.of(currentYearMonth.plusMonths(1L), largestYearMonth); + } + + private static Stream getZonedDateTimeStream(Object[] args) { + var currentZonedDateTime = ZonedDateTime.now(ZoneOffset.UTC); + var largestZonedDateTime = LocalDateTime.MAX.atZone(ZoneOffset.MIN); + + return Stream.of(currentZonedDateTime.plusSeconds(1L), largestZonedDateTime); } } diff --git a/src/main/java/it/aboutbits/springboot/testing/validation/source/LessThanValueSource.java b/src/main/java/it/aboutbits/springboot/testing/validation/source/LessThanValueSource.java index 17bae11..6f68e89 100644 --- a/src/main/java/it/aboutbits/springboot/testing/validation/source/LessThanValueSource.java +++ b/src/main/java/it/aboutbits/springboot/testing/validation/source/LessThanValueSource.java @@ -5,6 +5,7 @@ import lombok.NonNull; import java.math.BigDecimal; +import java.math.BigInteger; import java.util.HashMap; import java.util.Map; import java.util.Random; @@ -17,6 +18,12 @@ public class LessThanValueSource implements ValueSource { private static final Random RANDOM = new Random(); static { + TYPE_SOURCES.put(Byte.class, LessThanValueSource::getByteStream); + TYPE_SOURCES.put(byte.class, LessThanValueSource::getByteStream); + + TYPE_SOURCES.put(Short.class, LessThanValueSource::getShortStream); + TYPE_SOURCES.put(short.class, LessThanValueSource::getShortStream); + TYPE_SOURCES.put(Integer.class, LessThanValueSource::getIntegerStream); TYPE_SOURCES.put(int.class, LessThanValueSource::getIntegerStream); @@ -29,6 +36,7 @@ public class LessThanValueSource implements ValueSource { TYPE_SOURCES.put(Double.class, LessThanValueSource::getDoubleStream); TYPE_SOURCES.put(double.class, LessThanValueSource::getDoubleStream); + TYPE_SOURCES.put(BigInteger.class, LessThanValueSource::getBigIntegerStream); TYPE_SOURCES.put(BigDecimal.class, LessThanValueSource::getBigDecimalStream); TYPE_SOURCES.put(ScaledBigDecimal.class, LessThanValueSource::getScaledBigDecimalStream); } @@ -49,6 +57,30 @@ public Stream values(Class propertyClass, Object... args) { throw new IllegalArgumentException("Property class not supported!"); } + @NonNull + private static Stream getByteStream(Object[] args) { + var minValue = Byte.MIN_VALUE; + var maxValue = (byte) (Long.valueOf((long) args[0]).byteValue() - 1); + + return Stream.concat( + Stream.of(minValue, maxValue), + RANDOM.ints(1, minValue, maxValue) + .mapToObj(value -> Byte.valueOf((byte) value)) + ); + } + + @NonNull + private static Stream getShortStream(Object[] args) { + var minValue = Short.MIN_VALUE; + var maxValue = (short) (Long.valueOf((long) args[0]).shortValue() - 1); + + return Stream.concat( + Stream.of(minValue, maxValue), + RANDOM.ints(1, minValue, maxValue) + .mapToObj(value -> Short.valueOf((short) value)) + ); + } + @NonNull private static Stream getIntegerStream(Object[] args) { var minValue = Integer.MIN_VALUE; @@ -56,7 +88,7 @@ private static Stream getIntegerStream(Object[] args) { return Stream.concat( Stream.of(minValue, maxValue), - RANDOM.ints(minValue, maxValue).limit(1).boxed() + RANDOM.ints(1, minValue, maxValue).boxed() ); } @@ -67,7 +99,7 @@ private static Stream getLongStream(Object[] args) { return Stream.concat( Stream.of(minValue, maxValue), - RANDOM.longs(minValue, maxValue).limit(1).boxed() + RANDOM.longs(1, minValue, maxValue).boxed() ); } @@ -78,7 +110,7 @@ private static Stream getFloatStream(Object[] args) { return Stream.concat( Stream.of(minValue, maxValue), - RANDOM.doubles(1).map(d -> minValue + (maxValue - minValue) * d).boxed().map( + RANDOM.doubles(1, minValue, maxValue).boxed().map( Double::floatValue ) ); @@ -91,7 +123,20 @@ private static Stream getDoubleStream(Object[] args) { return Stream.concat( Stream.of(minValue, maxValue), - RANDOM.doubles(1).map(d -> minValue + (maxValue - minValue) * d).boxed() + RANDOM.doubles(1, minValue, maxValue).boxed() + ); + } + + @NonNull + private static Stream getBigIntegerStream(Object[] args) { + var minValue = Long.MIN_VALUE; + var maxValue = (long) args[0] - 1; + + return Stream.concat( + Stream.of(BigInteger.valueOf(minValue), BigInteger.valueOf(maxValue)), + RANDOM.longs(1, minValue, maxValue).boxed().map( + BigInteger::valueOf + ) ); } @@ -102,7 +147,9 @@ private static Stream getBigDecimalStream(Object[] args) { return Stream.concat( Stream.of(BigDecimal.valueOf(minValue), BigDecimal.valueOf(maxValue)), - RANDOM.doubles(1).map(d -> minValue + (maxValue - minValue) * d).boxed().map(BigDecimal::valueOf) + RANDOM.doubles(1, minValue, maxValue).boxed().map( + BigDecimal::valueOf + ) ); } @@ -113,7 +160,9 @@ private static Stream getScaledBigDecimalStream(Object[] args) return Stream.concat( Stream.of(ScaledBigDecimal.valueOf(minValue), ScaledBigDecimal.valueOf(maxValue)), - RANDOM.doubles(1).map(d -> minValue + (maxValue - minValue) * d).boxed().map(ScaledBigDecimal::valueOf) + RANDOM.doubles(1, minValue, maxValue).boxed().map( + ScaledBigDecimal::valueOf + ) ); } } diff --git a/src/main/java/it/aboutbits/springboot/testing/validation/source/PastValueSource.java b/src/main/java/it/aboutbits/springboot/testing/validation/source/PastValueSource.java index d50edd8..d63ba46 100644 --- a/src/main/java/it/aboutbits/springboot/testing/validation/source/PastValueSource.java +++ b/src/main/java/it/aboutbits/springboot/testing/validation/source/PastValueSource.java @@ -2,10 +2,17 @@ import it.aboutbits.springboot.testing.validation.core.ValueSource; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.Month; import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Year; +import java.time.YearMonth; import java.time.ZoneOffset; +import java.time.ZonedDateTime; import java.util.HashMap; import java.util.Map; import java.util.function.Function; @@ -14,10 +21,17 @@ public class PastValueSource implements ValueSource { private static final Map, Function>> TYPE_SOURCES = new HashMap<>(); + // https://jakarta.ee/specifications/bean-validation/3.0/apidocs/jakarta/validation/constraints/past static { + TYPE_SOURCES.put(Instant.class, PastValueSource::getInstantStream); + TYPE_SOURCES.put(LocalTime.class, PastValueSource::getLocalTimeStream); TYPE_SOURCES.put(LocalDate.class, PastValueSource::getLocalDateStream); - TYPE_SOURCES.put(LocalDateTime.class, PastValueSource::getLocalDatetimeStream); + TYPE_SOURCES.put(LocalDateTime.class, PastValueSource::getLocalDateTimeStream); + TYPE_SOURCES.put(OffsetTime.class, PastValueSource::getOffsetTimeStream); TYPE_SOURCES.put(OffsetDateTime.class, PastValueSource::getOffsetDateTimeStream); + TYPE_SOURCES.put(Year.class, PastValueSource::getYearStream); + TYPE_SOURCES.put(YearMonth.class, PastValueSource::getYearMonthStream); + TYPE_SOURCES.put(ZonedDateTime.class, PastValueSource::getZonedDateTimeStream); } @SuppressWarnings("unused") @@ -36,25 +50,66 @@ public Stream values(Class propertyClass, Object... args) { throw new IllegalArgumentException("Property class not supported!"); } + private static Stream getInstantStream(Object[] args) { + var currentInstant = Instant.now(); + var smallestInstant = Instant.MIN; + + return Stream.of(smallestInstant, currentInstant.minusSeconds(1L)); + } + + private static Stream getLocalTimeStream(Object[] args) { + var currentLocalTime = LocalTime.now(); + var smallestLocalTime = LocalTime.MIN; + + return Stream.of(smallestLocalTime, currentLocalTime.minusSeconds(1L)); + } private static Stream getLocalDateStream(Object[] args) { var currentDate = LocalDate.now(); var smallestDate = LocalDate.MIN; - return Stream.of(smallestDate, currentDate.minusDays(1)); + return Stream.of(smallestDate, currentDate.minusDays(1L)); } - private static Stream getLocalDatetimeStream(Object[] args) { + private static Stream getLocalDateTimeStream(Object[] args) { var currentDateTime = LocalDateTime.now(); var smallestDateTime = LocalDateTime.MIN; - return Stream.of(smallestDateTime, currentDateTime.minusSeconds(1)); + return Stream.of(smallestDateTime, currentDateTime.minusSeconds(1L)); + } + + private static Stream getOffsetTimeStream(Object[] args) { + var currentOffsetTime = OffsetTime.now(ZoneOffset.UTC); + var smallestOffsetTime = OffsetTime.MIN; + + return Stream.of(smallestOffsetTime, currentOffsetTime.minusSeconds(1L)); } private static Stream getOffsetDateTimeStream(Object[] args) { var currentOffsetDateTime = OffsetDateTime.now(ZoneOffset.UTC); var smallestOffsetDateTime = OffsetDateTime.MIN; - return Stream.of(smallestOffsetDateTime, currentOffsetDateTime.minusSeconds(1)); + return Stream.of(smallestOffsetDateTime, currentOffsetDateTime.minusSeconds(1L)); + } + + private static Stream getYearStream(Object[] args) { + var currentYear = Year.now(); + var smallestYear = Year.of(Year.MIN_VALUE); + + return Stream.of(smallestYear, currentYear.minusYears(1L)); + } + + private static Stream getYearMonthStream(Object[] args) { + var currentYearMonth = YearMonth.now(); + var smallestYearMonth = YearMonth.of(Year.MIN_VALUE, Month.JANUARY); + + return Stream.of(smallestYearMonth, currentYearMonth.minusMonths(1L)); + } + + private static Stream getZonedDateTimeStream(Object[] args) { + var currentZonedDateTime = ZonedDateTime.now(ZoneOffset.UTC); + var smallestZonedDateTime = LocalDateTime.MIN.atZone(ZoneOffset.MAX); + + return Stream.of(smallestZonedDateTime, currentZonedDateTime.minusSeconds(1L)); } } diff --git a/src/main/java/it/aboutbits/springboot/testing/validation/source/ZeroValueSource.java b/src/main/java/it/aboutbits/springboot/testing/validation/source/ZeroValueSource.java index ecaa312..fc15b06 100644 --- a/src/main/java/it/aboutbits/springboot/testing/validation/source/ZeroValueSource.java +++ b/src/main/java/it/aboutbits/springboot/testing/validation/source/ZeroValueSource.java @@ -4,6 +4,7 @@ import it.aboutbits.springboot.toolbox.type.ScaledBigDecimal; import java.math.BigDecimal; +import java.math.BigInteger; import java.util.HashMap; import java.util.Map; import java.util.function.Function; @@ -13,20 +14,27 @@ public class ZeroValueSource implements ValueSource { private static final Map, Function>> TYPE_SOURCES = new HashMap<>(); static { + TYPE_SOURCES.put(Byte.class, (Object[] args) -> Stream.of((byte) 0)); + TYPE_SOURCES.put(byte.class, (Object[] args) -> Stream.of((byte) 0)); + + TYPE_SOURCES.put(Short.class, (Object[] args) -> Stream.of((short) 0)); + TYPE_SOURCES.put(short.class, (Object[] args) -> Stream.of((short) 0)); + TYPE_SOURCES.put(Integer.class, (Object[] args) -> Stream.of(0)); TYPE_SOURCES.put(int.class, (Object[] args) -> Stream.of(0)); TYPE_SOURCES.put(Long.class, (Object[] args) -> Stream.of(0L)); TYPE_SOURCES.put(long.class, (Object[] args) -> Stream.of(0L)); - TYPE_SOURCES.put(Float.class, (Object[] args) -> Stream.of(0F)); - TYPE_SOURCES.put(float.class, (Object[] args) -> Stream.of(0F)); + TYPE_SOURCES.put(Float.class, (Object[] args) -> Stream.of(0f)); + TYPE_SOURCES.put(float.class, (Object[] args) -> Stream.of(0f)); - TYPE_SOURCES.put(Double.class, (Object[] args) -> Stream.of(0D)); - TYPE_SOURCES.put(double.class, (Object[] args) -> Stream.of(0D)); + TYPE_SOURCES.put(Double.class, (Object[] args) -> Stream.of(0d)); + TYPE_SOURCES.put(double.class, (Object[] args) -> Stream.of(0d)); - TYPE_SOURCES.put(BigDecimal.class, (Object[] args) -> Stream.of(BigDecimal.valueOf(0))); - TYPE_SOURCES.put(ScaledBigDecimal.class, (Object[] args) -> Stream.of(ScaledBigDecimal.valueOf(0))); + TYPE_SOURCES.put(BigInteger.class, (Object[] args) -> Stream.of(BigInteger.ZERO)); + TYPE_SOURCES.put(BigDecimal.class, (Object[] args) -> Stream.of(BigDecimal.ZERO)); + TYPE_SOURCES.put(ScaledBigDecimal.class, (Object[] args) -> Stream.of(ScaledBigDecimal.ZERO)); } @SuppressWarnings("unused") diff --git a/src/test/java/it/aboutbits/springboot/testing/validation/ValidationAssertTest.java b/src/test/java/it/aboutbits/springboot/testing/validation/ValidationAssertTest.java index e59d945..4fbfef3 100644 --- a/src/test/java/it/aboutbits/springboot/testing/validation/ValidationAssertTest.java +++ b/src/test/java/it/aboutbits/springboot/testing/validation/ValidationAssertTest.java @@ -19,9 +19,17 @@ import org.springframework.lang.Nullable; import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.Year; +import java.time.YearMonth; +import java.time.ZonedDateTime; +import java.time.temporal.ChronoUnit; import static it.aboutbits.springboot.testing.validation.ValidationAssertTest.TestValidationAssert.assertThatValidation; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; @@ -29,116 +37,118 @@ class ValidationAssertTest { @With public record SomeValidParameter( - @NotNull - String notNullable, - @NotBlank - String notBlank, - @Min(5) - int biggerThanInt, - @Min(5) - long biggerThanLong, - @Min(5) - float biggerThanFloat, - @Min(5) - double biggerThanDouble, - @Min(5) - BigDecimal biggerThanBigDecimal, - @Min(5) - ScaledBigDecimal biggerThanScaledBigDecimal, - @Max(5) - int lessThanInt, - @Max(5) - long lessThanLong, - @Max(5) - float lessThanFloat, - @Max(5) - double lessThanDouble, - @Max(5) - BigDecimal lessThanBigDecimal, - @Max(5) - ScaledBigDecimal lessThanScaledBigDecimal, - @Min(-3) - @Max(5) - int betweenInt, - @Min(-3) - @Max(5) - long betweenLong, - @Min(-3) - @Max(5) - float betweenFloat, - @Min(-3) - @Max(5) - double betweenDouble, - @Min(-3) - @Max(5) - BigDecimal betweenBigDecimal, - @Min(-3) - @Max(5) - ScaledBigDecimal betweenScaledBigDecimal, - @Positive - int positiveInt, - @Positive - long positiveLong, - @Positive - float positiveFloat, - @Positive - double positiveDouble, - @Positive - BigDecimal positiveBigDecimal, - @Positive - ScaledBigDecimal positiveScaledBigDecimal, - @Negative - int negativeInt, - @Negative - long negativeLong, - @Negative - float negativeFloat, - @Negative - double negativeDouble, - @Negative - BigDecimal negativeBigDecimal, - @Negative - ScaledBigDecimal negativeScaledBigDecimal, - @PositiveOrZero - int positiveOrZeroInt, - @PositiveOrZero - long positiveOrZeroLong, - @PositiveOrZero - float positiveOrZeroFloat, - @PositiveOrZero - double positiveOrZeroDouble, - @PositiveOrZero - BigDecimal positiveOrZeroBigDecimal, - @PositiveOrZero - ScaledBigDecimal positiveOrZeroScaledBigDecimal, - @NegativeOrZero - int negativeOrZeroInt, - @NegativeOrZero - long negativeOrZeroLong, - @NegativeOrZero - float negativeOrZeroFloat, - @NegativeOrZero - double negativeOrZeroDouble, - @NegativeOrZero - BigDecimal negativeOrZeroBigDecimal, - @NegativeOrZero - ScaledBigDecimal negativeOrZeroScaledBigDecimal, - @Future - LocalDate futureDate, - @Future - LocalDateTime futureDateTime, - @Future - OffsetDateTime futureOffsetDateTime, - @Past - LocalDate pastDate, - @Past - LocalDateTime pastDateTime, - @Past - OffsetDateTime pastOffsetDateTime, - @Valid - Object validObject, - @Nullable - Object nullable, + // NotNull + @NotNull String notNullable, + + // NotBlank + @NotBlank String notBlank, + + // Min + @Min(5) byte biggerThanByte, + @Min(5) short biggerThanShort, + @Min(5) int biggerThanInt, + @Min(5) long biggerThanLong, + @Min(5) float biggerThanFloat, + @Min(5) double biggerThanDouble, + @Min(5) BigInteger biggerThanBigInteger, + @Min(5) BigDecimal biggerThanBigDecimal, + @Min(5) ScaledBigDecimal biggerThanScaledBigDecimal, + + // Max + @Max(5) byte lessThanByte, + @Max(5) short lessThanShort, + @Max(5) int lessThanInt, + @Max(5) long lessThanLong, + @Max(5) float lessThanFloat, + @Max(5) double lessThanDouble, + @Max(5) BigInteger lessThanBigInteger, + @Max(5) BigDecimal lessThanBigDecimal, + @Max(5) ScaledBigDecimal lessThanScaledBigDecimal, + + // Between + @Min(-3) @Max(5) byte betweenByte, + @Min(-3) @Max(5) short betweenShort, + @Min(-3) @Max(5) int betweenInt, + @Min(-3) @Max(5) long betweenLong, + @Min(-3) @Max(5) float betweenFloat, + @Min(-3) @Max(5) double betweenDouble, + @Min(-3) @Max(5) BigInteger betweenBigInteger, + @Min(-3) @Max(5) BigDecimal betweenBigDecimal, + @Min(-3) @Max(5) ScaledBigDecimal betweenScaledBigDecimal, + + // Positive + @Positive byte positiveByte, + @Positive short positiveShort, + @Positive int positiveInt, + @Positive long positiveLong, + @Positive float positiveFloat, + @Positive double positiveDouble, + @Positive BigInteger positiveBigInteger, + @Positive BigDecimal positiveBigDecimal, + @Positive ScaledBigDecimal positiveScaledBigDecimal, + + // Negative + @Negative byte negativeByte, + @Negative short negativeShort, + @Negative int negativeInt, + @Negative long negativeLong, + @Negative float negativeFloat, + @Negative double negativeDouble, + @Negative BigInteger negativeBigInteger, + @Negative BigDecimal negativeBigDecimal, + @Negative ScaledBigDecimal negativeScaledBigDecimal, + + // PositiveOrZero + @PositiveOrZero byte positiveOrZeroByte, + @PositiveOrZero short positiveOrZeroShort, + @PositiveOrZero int positiveOrZeroInt, + @PositiveOrZero long positiveOrZeroLong, + @PositiveOrZero float positiveOrZeroFloat, + @PositiveOrZero double positiveOrZeroDouble, + @PositiveOrZero BigInteger positiveOrZeroBigInteger, + @PositiveOrZero BigDecimal positiveOrZeroBigDecimal, + @PositiveOrZero ScaledBigDecimal positiveOrZeroScaledBigDecimal, + + // NegativeOrZero + @NegativeOrZero byte negativeOrZeroByte, + @NegativeOrZero short negativeOrZeroShort, + @NegativeOrZero int negativeOrZeroInt, + @NegativeOrZero long negativeOrZeroLong, + @NegativeOrZero float negativeOrZeroFloat, + @NegativeOrZero double negativeOrZeroDouble, + @NegativeOrZero BigInteger negativeOrZeroBigInteger, + @NegativeOrZero BigDecimal negativeOrZeroBigDecimal, + @NegativeOrZero ScaledBigDecimal negativeOrZeroScaledBigDecimal, + + // Future + @Future Instant futureInstant, + @Future LocalTime futureTime, + @Future LocalDate futureDate, + @Future LocalDateTime futureDateTime, + @Future OffsetTime futureOffsetTime, + @Future OffsetDateTime futureOffsetDateTime, + @Future Year futureYear, + @Future YearMonth futureYearMonth, + @Future ZonedDateTime futureZonedDateTime, + + // Past + @Past Instant pastInstant, + @Past LocalTime pastTime, + @Past LocalDate pastDate, + @Past LocalDateTime pastDateTime, + @Past OffsetTime pastOffsetTime, + @Past OffsetDateTime pastOffsetDateTime, + @Past Year pastYear, + @Past YearMonth pastYearMonth, + @Past ZonedDateTime pastZonedDateTime, + + // Valid + @Valid Object validObject, + + // Nullable + @Nullable Object nullable, + + // Not validated Object notValidated ) { @@ -151,58 +161,118 @@ void testWithBeanValidation() { assertThatValidation().of(validParameter) .usingBeanValidation() + // NotNull .notNull("notNullable") + + // NotBlank .notBlank("notBlank") + + // Min + .min("biggerThanByte", 5) + .min("biggerThanShort", 5) .min("biggerThanInt", 5) .min("biggerThanLong", 5) .min("biggerThanFloat", 5) .min("biggerThanDouble", 5) + .min("biggerThanBigInteger", 5) .min("biggerThanBigDecimal", 5) .min("biggerThanScaledBigDecimal", 5) + + // Max + .max("lessThanByte", 5) + .max("lessThanShort", 5) .max("lessThanInt", 5) .max("lessThanLong", 5) .max("lessThanFloat", 5) .max("lessThanDouble", 5) + .max("lessThanBigInteger", 5) .max("lessThanBigDecimal", 5) .max("lessThanScaledBigDecimal", 5) + + // Positive + .positive("positiveByte") + .positive("positiveShort") .positive("positiveInt") .positive("positiveLong") .positive("positiveFloat") .positive("positiveDouble") + .positive("positiveBigInteger") .positive("positiveBigDecimal") .positive("positiveScaledBigDecimal") + + // Negative + .negative("negativeByte") + .negative("negativeShort") .negative("negativeInt") .negative("negativeLong") .negative("negativeFloat") .negative("negativeDouble") + .negative("negativeBigInteger") .negative("negativeBigDecimal") .negative("negativeScaledBigDecimal") + + // Between + .between("betweenByte", -3, 5) + .between("betweenShort", -3, 5) .between("betweenInt", -3, 5) .between("betweenLong", -3, 5) .between("betweenFloat", -3, 5) .between("betweenDouble", -3, 5) + .between("betweenBigInteger", -3, 5) .between("betweenBigDecimal", -3, 5) .between("betweenScaledBigDecimal", -3, 5) + + // PositiveOrZero + .positiveOrZero("positiveOrZeroByte") + .positiveOrZero("positiveOrZeroShort") .positiveOrZero("positiveOrZeroInt") .positiveOrZero("positiveOrZeroLong") .positiveOrZero("positiveOrZeroFloat") .positiveOrZero("positiveOrZeroDouble") + .positiveOrZero("positiveOrZeroBigInteger") .positiveOrZero("positiveOrZeroBigDecimal") .positiveOrZero("positiveOrZeroScaledBigDecimal") + + // NegativeOrZero + .negativeOrZero("negativeOrZeroByte") + .negativeOrZero("negativeOrZeroShort") .negativeOrZero("negativeOrZeroInt") .negativeOrZero("negativeOrZeroLong") .negativeOrZero("negativeOrZeroFloat") .negativeOrZero("negativeOrZeroDouble") + .negativeOrZero("negativeOrZeroBigInteger") .negativeOrZero("negativeOrZeroBigDecimal") .negativeOrZero("negativeOrZeroScaledBigDecimal") + + // Future + .future("futureInstant") + .future("futureTime") .future("futureDate") .future("futureDateTime") + .future("futureOffsetTime") .future("futureOffsetDateTime") + .future("futureYear") + .future("futureYearMonth") + .future("futureZonedDateTime") + + // Past + .past("pastInstant") + .past("pastTime") .past("pastDate") .past("pastDateTime") + .past("pastOffsetTime") .past("pastOffsetDateTime") + .past("pastYear") + .past("pastYearMonth") + .past("pastZonedDateTime") + + // Valid .validBean("validObject") + + // Nullable .nullable("nullable") + + // Not validated .notValidated("notValidated") .isCompliant(); } @@ -216,58 +286,118 @@ void invalidParameter_shouldFail() { assertThatExceptionOfType(AssertionError.class).isThrownBy( () -> assertThatValidation().of(invalidParameter) .usingBeanValidation() + // NotNull .notNull("notNullable") + + // NotBlank .notBlank("notBlank") + + // Min + .min("biggerThanByte", 5) + .min("biggerThanShort", 5) .min("biggerThanInt", 5) .min("biggerThanLong", 5) .min("biggerThanFloat", 5) .min("biggerThanDouble", 5) + .min("biggerThanBigInteger", 5) .min("biggerThanBigDecimal", 5) .min("biggerThanScaledBigDecimal", 5) + + // Max + .max("lessThanByte", 5) + .max("lessThanShort", 5) .max("lessThanInt", 5) .max("lessThanLong", 5) .max("lessThanFloat", 5) .max("lessThanDouble", 5) + .max("lessThanBigInteger", 5) .max("lessThanBigDecimal", 5) .max("lessThanScaledBigDecimal", 5) + + // Positive + .positive("positiveByte") + .positive("positiveShort") .positive("positiveInt") .positive("positiveLong") .positive("positiveFloat") .positive("positiveDouble") + .positive("positiveBigInteger") .positive("positiveBigDecimal") .positive("positiveScaledBigDecimal") + + // Negative + .negative("negativeByte") + .negative("negativeShort") .negative("negativeInt") .negative("negativeLong") .negative("negativeFloat") .negative("negativeDouble") + .negative("negativeBigInteger") .negative("negativeBigDecimal") .negative("negativeScaledBigDecimal") + + // Between + .between("betweenByte", -3, 5) + .between("betweenShort", -3, 5) .between("betweenInt", -3, 5) .between("betweenLong", -3, 5) .between("betweenFloat", -3, 5) .between("betweenDouble", -3, 5) + .between("betweenBigInteger", -3, 5) .between("betweenBigDecimal", -3, 5) .between("betweenScaledBigDecimal", -3, 5) + + // PositiveOrZero + .positiveOrZero("positiveOrZeroByte") + .positiveOrZero("positiveOrZeroShort") .positiveOrZero("positiveOrZeroInt") .positiveOrZero("positiveOrZeroLong") .positiveOrZero("positiveOrZeroFloat") .positiveOrZero("positiveOrZeroDouble") + .positiveOrZero("positiveOrZeroBigInteger") .positiveOrZero("positiveOrZeroBigDecimal") .positiveOrZero("positiveOrZeroScaledBigDecimal") + + // NegativeOrZero + .negativeOrZero("negativeOrZeroByte") + .negativeOrZero("negativeOrZeroShort") .negativeOrZero("negativeOrZeroInt") .negativeOrZero("negativeOrZeroLong") .negativeOrZero("negativeOrZeroFloat") .negativeOrZero("negativeOrZeroDouble") + .negativeOrZero("negativeOrZeroBigInteger") .negativeOrZero("negativeOrZeroBigDecimal") .negativeOrZero("negativeOrZeroScaledBigDecimal") + + // Future + .future("futureInstant") + .future("futureTime") .future("futureDate") .future("futureDateTime") + .future("futureOffsetTime") .future("futureOffsetDateTime") + .future("futureYear") + .future("futureYearMonth") + .future("futureZonedDateTime") + + // Past + .past("pastInstant") + .past("pastTime") .past("pastDate") .past("pastDateTime") + .past("pastOffsetTime") .past("pastOffsetDateTime") + .past("pastYear") + .past("pastYearMonth") + .past("pastZonedDateTime") + + // Valid .validBean("validObject") + + // Nullable .nullable("nullable") + + // Not validated .notValidated("notValidated") .isCompliant()); } @@ -279,143 +409,235 @@ void propertyMissingRule_shouldFail() { assertThatExceptionOfType(AssertionError.class).isThrownBy( () -> assertThatValidation().of(validParameter) .usingBeanValidation() + // NotNull .notNull("notNullable") + + // NotBlank // this is now missing: .notBlank("notBlank") + + // Min + .min("biggerThanByte", 5) + .min("biggerThanShort", 5) .min("biggerThanInt", 5) .min("biggerThanLong", 5) .min("biggerThanFloat", 5) .min("biggerThanDouble", 5) + .min("biggerThanBigInteger", 5) .min("biggerThanBigDecimal", 5) .min("biggerThanScaledBigDecimal", 5) + + // Max + .max("lessThanByte", 5) + .max("lessThanShort", 5) .max("lessThanInt", 5) .max("lessThanLong", 5) .max("lessThanFloat", 5) .max("lessThanDouble", 5) + .max("lessThanBigInteger", 5) .max("lessThanBigDecimal", 5) .max("lessThanScaledBigDecimal", 5) + + // Positive + .positive("positiveByte") + .positive("positiveShort") .positive("positiveInt") .positive("positiveLong") .positive("positiveFloat") .positive("positiveDouble") + .positive("positiveBigInteger") .positive("positiveBigDecimal") .positive("positiveScaledBigDecimal") + + // Negative + .negative("negativeByte") + .negative("negativeShort") .negative("negativeInt") .negative("negativeLong") .negative("negativeFloat") .negative("negativeDouble") + .negative("negativeBigInteger") .negative("negativeBigDecimal") .negative("negativeScaledBigDecimal") + + // Between + .between("betweenByte", -3, 5) + .between("betweenShort", -3, 5) .between("betweenInt", -3, 5) .between("betweenLong", -3, 5) .between("betweenFloat", -3, 5) .between("betweenDouble", -3, 5) + .between("betweenBigInteger", -3, 5) .between("betweenBigDecimal", -3, 5) .between("betweenScaledBigDecimal", -3, 5) + + // PositiveOrZero + .positiveOrZero("positiveOrZeroByte") + .positiveOrZero("positiveOrZeroShort") .positiveOrZero("positiveOrZeroInt") .positiveOrZero("positiveOrZeroLong") .positiveOrZero("positiveOrZeroFloat") .positiveOrZero("positiveOrZeroDouble") + .positiveOrZero("positiveOrZeroBigInteger") .positiveOrZero("positiveOrZeroBigDecimal") .positiveOrZero("positiveOrZeroScaledBigDecimal") + + // NegativeOrZero + .negativeOrZero("negativeOrZeroByte") + .negativeOrZero("negativeOrZeroShort") .negativeOrZero("negativeOrZeroInt") .negativeOrZero("negativeOrZeroLong") .negativeOrZero("negativeOrZeroFloat") .negativeOrZero("negativeOrZeroDouble") + .negativeOrZero("negativeOrZeroBigInteger") .negativeOrZero("negativeOrZeroBigDecimal") .negativeOrZero("negativeOrZeroScaledBigDecimal") + + // Future + .future("futureInstant") + .future("futureTime") .future("futureDate") .future("futureDateTime") + .future("futureOffsetTime") .future("futureOffsetDateTime") + .future("futureYear") + .future("futureYearMonth") + .future("futureZonedDateTime") + + // Past + .past("pastInstant") + .past("pastTime") .past("pastDate") .past("pastDateTime") + .past("pastOffsetTime") .past("pastOffsetDateTime") + .past("pastYear") + .past("pastYearMonth") + .past("pastZonedDateTime") + // Valid .validBean("validObject") + + // Nullable .nullable("nullable") + + // Not validated .notValidated("notValidated") .isCompliant()); } private static SomeValidParameter getSomeValidParameter() { return new SomeValidParameter( - // notNull + // NotNull "", - // notBlank + // NotBlank "something", - // min + // Min + (byte) 6, + (short) 6, 6, - 6, - 6, - 6, - BigDecimal.valueOf(6), - ScaledBigDecimal.valueOf(6), + 6L, + 6.0f, + 6.0d, + BigInteger.valueOf(6L), + BigDecimal.valueOf(6.0d), + ScaledBigDecimal.valueOf(6.0d), - // max - 4, + // Max + (byte) 4, + (short) 4, 4, - 4, - 4, - BigDecimal.valueOf(4), - ScaledBigDecimal.valueOf(4), + 4L, + 4.0f, + 4.0d, + BigInteger.valueOf(4L), + BigDecimal.valueOf(4.0d), + ScaledBigDecimal.valueOf(4.0d), - // positive - 4, - 4, - 4, + // Positive + (byte) 4, + (short) 4, 4, - BigDecimal.valueOf(4), - ScaledBigDecimal.valueOf(4), + 4L, + 4.0f, + 4.0d, + BigInteger.valueOf(4L), + BigDecimal.valueOf(4.0d), + ScaledBigDecimal.valueOf(4.0d), - // negative + // Negative + (byte) 1, + (short) 1, 1, - 1, - 1, - 1, - BigDecimal.valueOf(1), - ScaledBigDecimal.valueOf(1), + 1L, + 1.0f, + 1.0d, + BigInteger.valueOf(1L), + BigDecimal.valueOf(1.0d), + ScaledBigDecimal.valueOf(1.0d), - // between - -1, + // Between + (byte) -1, + (short) -1, -1, - -1, - -1, - BigDecimal.valueOf(-1), - ScaledBigDecimal.valueOf(-1), + -1L, + -1.0f, + -1.0d, + BigInteger.valueOf(-1L), + BigDecimal.valueOf(-1.0d), + ScaledBigDecimal.valueOf(-1.0d), - // positiveOrZero - 0, - 0, - 0, + // PositiveOrZero + (byte) 0, + (short) 0, 0, - BigDecimal.valueOf(0), - ScaledBigDecimal.valueOf(0), + 0L, + 0.0f, + 0.0d, + BigInteger.valueOf(0L), + BigDecimal.valueOf(0.0d), + ScaledBigDecimal.valueOf(0.0d), - // negativeOrZero + // NegativeOrZero + (byte) 0, + (short) 0, 0, - 0, - 0, - 0, - BigDecimal.valueOf(0), - ScaledBigDecimal.valueOf(0), + 0L, + 0.0f, + 0.0d, + BigInteger.valueOf(0L), + BigDecimal.valueOf(0.0d), + ScaledBigDecimal.valueOf(0.0d), - // future - LocalDate.now().plusDays(1), - LocalDateTime.now().plusDays(1), - OffsetDateTime.now().plusDays(1), + // Future + Instant.now().plus(1L, ChronoUnit.DAYS), + LocalTime.now().plusMinutes(1L), + LocalDate.now().plusDays(1L), + LocalDateTime.now().plusDays(1L), + OffsetTime.now().plusMinutes(1L), + OffsetDateTime.now().plusDays(1L), + Year.now().plusYears(1L), + YearMonth.now().plusMonths(1L), + ZonedDateTime.now().plusDays(1L), - // past - LocalDate.now().minusDays(1), - LocalDateTime.now().minusDays(1), - OffsetDateTime.now().minusDays(1), + // Past + Instant.now().minus(1L, ChronoUnit.DAYS), + LocalTime.now().minusMinutes(1L), + LocalDate.now().minusDays(1L), + LocalDateTime.now().minusDays(1L), + OffsetTime.now().minusMinutes(1L), + OffsetDateTime.now().minusDays(1L), + Year.now().minusYears(1L), + YearMonth.now().minusMonths(1L), + ZonedDateTime.now().minusDays(1L), - // valid + // Valid null, - // nullable + // Nullable null, - // not validated + // Not validated null ); } @@ -430,7 +652,6 @@ public static TestValidationAssert assertThatValidation() { } public static final class TestRuleBuilder extends BaseRuleBuilder { - } } }