Skip to content

Commit

Permalink
Merge pull request #10 from aboutbits/add-number-and-date-types
Browse files Browse the repository at this point in the history
Add new Number and Temporal type validations
  • Loading branch information
ThoSap authored Jan 13, 2025
2 parents 03419fa + 583173b commit f165ea4
Show file tree
Hide file tree
Showing 7 changed files with 639 additions and 200 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ private static <P> 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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);

Expand All @@ -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<Object[], Stream<?>> source) {
TYPE_SOURCES.put(type, source);
}
Expand All @@ -48,14 +56,38 @@ public <T> Stream<T> values(Class<T> propertyClass, Object... args) {
throw new IllegalArgumentException("Property class not supported!");
}

@NonNull
private static Stream<Byte> 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<Short> 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<Integer> getIntegerStream(Object[] args) {
var minValue = Long.valueOf((long) args[0]).intValue() + 1;
var maxValue = Integer.MAX_VALUE;

return Stream.concat(
Stream.of(minValue, maxValue),
RANDOM.ints(minValue, maxValue).limit(1).boxed()
RANDOM.ints(1, minValue, maxValue).boxed()
);
}

Expand All @@ -66,7 +98,7 @@ private static Stream<Long> getLongStream(Object[] args) {

return Stream.concat(
Stream.of(minValue, maxValue),
RANDOM.longs(minValue, maxValue).limit(1).boxed()
RANDOM.longs(1, minValue, maxValue).boxed()
);
}

Expand All @@ -77,7 +109,7 @@ private static Stream<Float> 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
)
);
Expand All @@ -90,18 +122,20 @@ private static Stream<Double> 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<ScaledBigDecimal> getScaledBigDecimalStream(Object[] args) {
var minValue = Long.valueOf((long) args[0]).doubleValue() + 0.1d;
var maxValue = Double.MAX_VALUE;
private static Stream<BigInteger> 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
)
);
}

Expand All @@ -112,7 +146,22 @@ private static Stream<BigDecimal> 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<ScaledBigDecimal> 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
)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -14,10 +21,17 @@
public class FutureValueSource implements ValueSource {
private static final Map<Class<?>, Function<Object[], Stream<?>>> 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")
Expand All @@ -36,24 +50,66 @@ public <T> Stream<T> values(Class<T> propertyClass, Object... args) {
throw new IllegalArgumentException("Property class not supported!");
}

private static Stream<Instant> getInstantStream(Object[] args) {
var currentInstant = Instant.now();
var largestInstant = Instant.MAX;

return Stream.of(currentInstant.plusSeconds(1L), largestInstant);
}

private static Stream<LocalTime> getLocalTimeStream(Object[] args) {
var currentLocalTime = LocalTime.now();
var largestLocalTime = LocalTime.MAX;

return Stream.of(currentLocalTime.plusSeconds(1L), largestLocalTime);
}

private static Stream<LocalDate> 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<LocalDateTime> getLocalDatetimeStream(Object[] args) {
private static Stream<LocalDateTime> 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<OffsetTime> getOffsetTimeStream(Object[] args) {
var currentOffsetTime = OffsetTime.now(ZoneOffset.UTC);
var largestOffsetTime = OffsetTime.MAX;

return Stream.of(currentOffsetTime.plusSeconds(1L), largestOffsetTime);
}

private static Stream<OffsetDateTime> 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<Year> getYearStream(Object[] args) {
var currentYear = Year.now();
var largestYear = Year.of(Year.MAX_VALUE);

return Stream.of(currentYear.plusYears(1L), largestYear);
}

private static Stream<YearMonth> 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<ZonedDateTime> getZonedDateTimeStream(Object[] args) {
var currentZonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
var largestZonedDateTime = LocalDateTime.MAX.atZone(ZoneOffset.MIN);

return Stream.of(currentZonedDateTime.plusSeconds(1L), largestZonedDateTime);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);

Expand All @@ -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);
}
Expand All @@ -49,14 +57,38 @@ public <T> Stream<T> values(Class<T> propertyClass, Object... args) {
throw new IllegalArgumentException("Property class not supported!");
}

@NonNull
private static Stream<Byte> 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<Short> 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<Integer> getIntegerStream(Object[] args) {
var minValue = Integer.MIN_VALUE;
var maxValue = Long.valueOf((long) args[0]).intValue() - 1;

return Stream.concat(
Stream.of(minValue, maxValue),
RANDOM.ints(minValue, maxValue).limit(1).boxed()
RANDOM.ints(1, minValue, maxValue).boxed()
);
}

Expand All @@ -67,7 +99,7 @@ private static Stream<Long> getLongStream(Object[] args) {

return Stream.concat(
Stream.of(minValue, maxValue),
RANDOM.longs(minValue, maxValue).limit(1).boxed()
RANDOM.longs(1, minValue, maxValue).boxed()
);
}

Expand All @@ -78,7 +110,7 @@ private static Stream<Float> 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
)
);
Expand All @@ -91,7 +123,20 @@ private static Stream<Double> 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<BigInteger> 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
)
);
}

Expand All @@ -102,7 +147,9 @@ private static Stream<BigDecimal> 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
)
);
}

Expand All @@ -113,7 +160,9 @@ private static Stream<ScaledBigDecimal> 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
)
);
}
}
Loading

0 comments on commit f165ea4

Please sign in to comment.