Skip to content

Commit f165ea4

Browse files
authored
Merge pull request #10 from aboutbits/add-number-and-date-types
Add new Number and Temporal type validations
2 parents 03419fa + 583173b commit f165ea4

7 files changed

Lines changed: 639 additions & 200 deletions

File tree

src/main/java/it/aboutbits/springboot/testing/validation/core/RuleValidator.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ private static <P> void assertThatValidationIsCompliantForEachProperty(
117117
// Check if there are any violations
118118
assertThat(violations)
119119
.withFailMessage(
120-
"More than one property failed to validate during mutation. The supplied parameter is possibly contains invalid values.")
120+
"More than one property failed to validate during mutation. The supplied parameter possibly contains invalid values."
121+
)
121122
.hasSizeLessThan(2);
122123

123124
assertThat(violations)

src/main/java/it/aboutbits/springboot/testing/validation/source/BiggerThanValueSource.java

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import lombok.NonNull;
66

77
import java.math.BigDecimal;
8+
import java.math.BigInteger;
89
import java.util.HashMap;
910
import java.util.Map;
1011
import java.util.Random;
@@ -16,6 +17,12 @@ public class BiggerThanValueSource implements ValueSource {
1617
private static final Random RANDOM = new Random();
1718

1819
static {
20+
TYPE_SOURCES.put(Byte.class, BiggerThanValueSource::getByteStream);
21+
TYPE_SOURCES.put(byte.class, BiggerThanValueSource::getByteStream);
22+
23+
TYPE_SOURCES.put(Short.class, BiggerThanValueSource::getShortStream);
24+
TYPE_SOURCES.put(short.class, BiggerThanValueSource::getShortStream);
25+
1926
TYPE_SOURCES.put(Integer.class, BiggerThanValueSource::getIntegerStream);
2027
TYPE_SOURCES.put(int.class, BiggerThanValueSource::getIntegerStream);
2128

@@ -28,11 +35,12 @@ public class BiggerThanValueSource implements ValueSource {
2835
TYPE_SOURCES.put(Double.class, BiggerThanValueSource::getDoubleStream);
2936
TYPE_SOURCES.put(double.class, BiggerThanValueSource::getDoubleStream);
3037

38+
TYPE_SOURCES.put(BigInteger.class, BiggerThanValueSource::getBigIntegerStream);
3139
TYPE_SOURCES.put(BigDecimal.class, BiggerThanValueSource::getBigDecimalStream);
3240
TYPE_SOURCES.put(ScaledBigDecimal.class, BiggerThanValueSource::getScaledBigDecimalStream);
3341
}
3442

35-
@SuppressWarnings("unchecked")
43+
@SuppressWarnings("unused")
3644
public static void registerType(Class<?> type, Function<Object[], Stream<?>> source) {
3745
TYPE_SOURCES.put(type, source);
3846
}
@@ -48,14 +56,38 @@ public <T> Stream<T> values(Class<T> propertyClass, Object... args) {
4856
throw new IllegalArgumentException("Property class not supported!");
4957
}
5058

59+
@NonNull
60+
private static Stream<Byte> getByteStream(Object[] args) {
61+
var minValue = (byte) (Long.valueOf((long) args[0]).byteValue() + 1);
62+
var maxValue = Byte.MAX_VALUE;
63+
64+
return Stream.concat(
65+
Stream.of(minValue, maxValue),
66+
RANDOM.ints(1, minValue, maxValue)
67+
.mapToObj(value -> Byte.valueOf((byte) value))
68+
);
69+
}
70+
71+
@NonNull
72+
private static Stream<Short> getShortStream(Object[] args) {
73+
var minValue = (short) (Long.valueOf((long) args[0]).shortValue() + 1);
74+
var maxValue = Short.MAX_VALUE;
75+
76+
return Stream.concat(
77+
Stream.of(minValue, maxValue),
78+
RANDOM.ints(1, minValue, maxValue)
79+
.mapToObj(value -> Short.valueOf((short) value))
80+
);
81+
}
82+
5183
@NonNull
5284
private static Stream<Integer> getIntegerStream(Object[] args) {
5385
var minValue = Long.valueOf((long) args[0]).intValue() + 1;
5486
var maxValue = Integer.MAX_VALUE;
5587

5688
return Stream.concat(
5789
Stream.of(minValue, maxValue),
58-
RANDOM.ints(minValue, maxValue).limit(1).boxed()
90+
RANDOM.ints(1, minValue, maxValue).boxed()
5991
);
6092
}
6193

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

6799
return Stream.concat(
68100
Stream.of(minValue, maxValue),
69-
RANDOM.longs(minValue, maxValue).limit(1).boxed()
101+
RANDOM.longs(1, minValue, maxValue).boxed()
70102
);
71103
}
72104

@@ -77,7 +109,7 @@ private static Stream<Float> getFloatStream(Object[] args) {
77109

78110
return Stream.concat(
79111
Stream.of(minValue, maxValue),
80-
RANDOM.doubles(minValue, maxValue).limit(1).boxed().map(
112+
RANDOM.doubles(1, minValue, maxValue).boxed().map(
81113
Double::floatValue
82114
)
83115
);
@@ -90,18 +122,20 @@ private static Stream<Double> getDoubleStream(Object[] args) {
90122

91123
return Stream.concat(
92124
Stream.of(minValue, maxValue),
93-
RANDOM.doubles(minValue, maxValue).limit(1).boxed()
125+
RANDOM.doubles(1, minValue, maxValue).boxed()
94126
);
95127
}
96128

97129
@NonNull
98-
private static Stream<ScaledBigDecimal> getScaledBigDecimalStream(Object[] args) {
99-
var minValue = Long.valueOf((long) args[0]).doubleValue() + 0.1d;
100-
var maxValue = Double.MAX_VALUE;
130+
private static Stream<BigInteger> getBigIntegerStream(Object[] args) {
131+
var minValue = (long) args[0] + 1;
132+
var maxValue = Long.MAX_VALUE;
101133

102134
return Stream.concat(
103-
Stream.of(ScaledBigDecimal.valueOf(minValue), ScaledBigDecimal.valueOf(maxValue)),
104-
RANDOM.doubles(minValue, maxValue).limit(1).boxed().map(ScaledBigDecimal::valueOf)
135+
Stream.of(BigInteger.valueOf(minValue), BigInteger.valueOf(maxValue)),
136+
RANDOM.longs(1, minValue, maxValue).boxed().map(
137+
BigInteger::valueOf
138+
)
105139
);
106140
}
107141

@@ -112,7 +146,22 @@ private static Stream<BigDecimal> getBigDecimalStream(Object[] args) {
112146

113147
return Stream.concat(
114148
Stream.of(BigDecimal.valueOf(minValue), BigDecimal.valueOf(maxValue)),
115-
RANDOM.doubles(minValue, maxValue).limit(1).boxed().map(BigDecimal::valueOf)
149+
RANDOM.doubles(1, minValue, maxValue).boxed().map(
150+
BigDecimal::valueOf
151+
)
152+
);
153+
}
154+
155+
@NonNull
156+
private static Stream<ScaledBigDecimal> getScaledBigDecimalStream(Object[] args) {
157+
var minValue = Long.valueOf((long) args[0]).doubleValue() + 0.1d;
158+
var maxValue = Double.MAX_VALUE;
159+
160+
return Stream.concat(
161+
Stream.of(ScaledBigDecimal.valueOf(minValue), ScaledBigDecimal.valueOf(maxValue)),
162+
RANDOM.doubles(1, minValue, maxValue).boxed().map(
163+
ScaledBigDecimal::valueOf
164+
)
116165
);
117166
}
118167
}

src/main/java/it/aboutbits/springboot/testing/validation/source/FutureValueSource.java

Lines changed: 61 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,17 @@
22

33
import it.aboutbits.springboot.testing.validation.core.ValueSource;
44

5+
import java.time.Instant;
56
import java.time.LocalDate;
67
import java.time.LocalDateTime;
8+
import java.time.LocalTime;
9+
import java.time.Month;
710
import java.time.OffsetDateTime;
11+
import java.time.OffsetTime;
12+
import java.time.Year;
13+
import java.time.YearMonth;
814
import java.time.ZoneOffset;
15+
import java.time.ZonedDateTime;
916
import java.util.HashMap;
1017
import java.util.Map;
1118
import java.util.function.Function;
@@ -14,10 +21,17 @@
1421
public class FutureValueSource implements ValueSource {
1522
private static final Map<Class<?>, Function<Object[], Stream<?>>> TYPE_SOURCES = new HashMap<>();
1623

24+
// https://jakarta.ee/specifications/bean-validation/3.0/apidocs/jakarta/validation/constraints/future
1725
static {
26+
TYPE_SOURCES.put(Instant.class, FutureValueSource::getInstantStream);
27+
TYPE_SOURCES.put(LocalTime.class, FutureValueSource::getLocalTimeStream);
1828
TYPE_SOURCES.put(LocalDate.class, FutureValueSource::getLocalDateStream);
19-
TYPE_SOURCES.put(LocalDateTime.class, FutureValueSource::getLocalDatetimeStream);
29+
TYPE_SOURCES.put(LocalDateTime.class, FutureValueSource::getLocalDateTimeStream);
30+
TYPE_SOURCES.put(OffsetTime.class, FutureValueSource::getOffsetTimeStream);
2031
TYPE_SOURCES.put(OffsetDateTime.class, FutureValueSource::getOffsetDateTimeStream);
32+
TYPE_SOURCES.put(Year.class, FutureValueSource::getYearStream);
33+
TYPE_SOURCES.put(YearMonth.class, FutureValueSource::getYearMonthStream);
34+
TYPE_SOURCES.put(ZonedDateTime.class, FutureValueSource::getZonedDateTimeStream);
2135
}
2236

2337
@SuppressWarnings("unused")
@@ -36,24 +50,66 @@ public <T> Stream<T> values(Class<T> propertyClass, Object... args) {
3650
throw new IllegalArgumentException("Property class not supported!");
3751
}
3852

53+
private static Stream<Instant> getInstantStream(Object[] args) {
54+
var currentInstant = Instant.now();
55+
var largestInstant = Instant.MAX;
56+
57+
return Stream.of(currentInstant.plusSeconds(1L), largestInstant);
58+
}
59+
60+
private static Stream<LocalTime> getLocalTimeStream(Object[] args) {
61+
var currentLocalTime = LocalTime.now();
62+
var largestLocalTime = LocalTime.MAX;
63+
64+
return Stream.of(currentLocalTime.plusSeconds(1L), largestLocalTime);
65+
}
66+
3967
private static Stream<LocalDate> getLocalDateStream(Object[] args) {
4068
var currentDate = LocalDate.now();
4169
var largestDate = LocalDate.MAX;
4270

43-
return Stream.of(currentDate.plusDays(1), largestDate);
71+
return Stream.of(currentDate.plusDays(1L), largestDate);
4472
}
4573

46-
private static Stream<LocalDateTime> getLocalDatetimeStream(Object[] args) {
74+
private static Stream<LocalDateTime> getLocalDateTimeStream(Object[] args) {
4775
var currentDateTime = LocalDateTime.now();
4876
var largestDateTime = LocalDateTime.MAX;
4977

50-
return Stream.of(currentDateTime.plusSeconds(1), largestDateTime);
78+
return Stream.of(currentDateTime.plusSeconds(1L), largestDateTime);
79+
}
80+
81+
private static Stream<OffsetTime> getOffsetTimeStream(Object[] args) {
82+
var currentOffsetTime = OffsetTime.now(ZoneOffset.UTC);
83+
var largestOffsetTime = OffsetTime.MAX;
84+
85+
return Stream.of(currentOffsetTime.plusSeconds(1L), largestOffsetTime);
5186
}
5287

5388
private static Stream<OffsetDateTime> getOffsetDateTimeStream(Object[] args) {
5489
var currentOffsetDateTime = OffsetDateTime.now(ZoneOffset.UTC);
5590
var largestOffsetDateTime = OffsetDateTime.MAX;
5691

57-
return Stream.of(currentOffsetDateTime.plusSeconds(1), largestOffsetDateTime);
92+
return Stream.of(currentOffsetDateTime.plusSeconds(1L), largestOffsetDateTime);
93+
}
94+
95+
private static Stream<Year> getYearStream(Object[] args) {
96+
var currentYear = Year.now();
97+
var largestYear = Year.of(Year.MAX_VALUE);
98+
99+
return Stream.of(currentYear.plusYears(1L), largestYear);
100+
}
101+
102+
private static Stream<YearMonth> getYearMonthStream(Object[] args) {
103+
var currentYearMonth = YearMonth.now();
104+
var largestYearMonth = YearMonth.of(Year.MAX_VALUE, Month.DECEMBER);
105+
106+
return Stream.of(currentYearMonth.plusMonths(1L), largestYearMonth);
107+
}
108+
109+
private static Stream<ZonedDateTime> getZonedDateTimeStream(Object[] args) {
110+
var currentZonedDateTime = ZonedDateTime.now(ZoneOffset.UTC);
111+
var largestZonedDateTime = LocalDateTime.MAX.atZone(ZoneOffset.MIN);
112+
113+
return Stream.of(currentZonedDateTime.plusSeconds(1L), largestZonedDateTime);
58114
}
59115
}

src/main/java/it/aboutbits/springboot/testing/validation/source/LessThanValueSource.java

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import lombok.NonNull;
66

77
import java.math.BigDecimal;
8+
import java.math.BigInteger;
89
import java.util.HashMap;
910
import java.util.Map;
1011
import java.util.Random;
@@ -17,6 +18,12 @@ public class LessThanValueSource implements ValueSource {
1718
private static final Random RANDOM = new Random();
1819

1920
static {
21+
TYPE_SOURCES.put(Byte.class, LessThanValueSource::getByteStream);
22+
TYPE_SOURCES.put(byte.class, LessThanValueSource::getByteStream);
23+
24+
TYPE_SOURCES.put(Short.class, LessThanValueSource::getShortStream);
25+
TYPE_SOURCES.put(short.class, LessThanValueSource::getShortStream);
26+
2027
TYPE_SOURCES.put(Integer.class, LessThanValueSource::getIntegerStream);
2128
TYPE_SOURCES.put(int.class, LessThanValueSource::getIntegerStream);
2229

@@ -29,6 +36,7 @@ public class LessThanValueSource implements ValueSource {
2936
TYPE_SOURCES.put(Double.class, LessThanValueSource::getDoubleStream);
3037
TYPE_SOURCES.put(double.class, LessThanValueSource::getDoubleStream);
3138

39+
TYPE_SOURCES.put(BigInteger.class, LessThanValueSource::getBigIntegerStream);
3240
TYPE_SOURCES.put(BigDecimal.class, LessThanValueSource::getBigDecimalStream);
3341
TYPE_SOURCES.put(ScaledBigDecimal.class, LessThanValueSource::getScaledBigDecimalStream);
3442
}
@@ -49,14 +57,38 @@ public <T> Stream<T> values(Class<T> propertyClass, Object... args) {
4957
throw new IllegalArgumentException("Property class not supported!");
5058
}
5159

60+
@NonNull
61+
private static Stream<Byte> getByteStream(Object[] args) {
62+
var minValue = Byte.MIN_VALUE;
63+
var maxValue = (byte) (Long.valueOf((long) args[0]).byteValue() - 1);
64+
65+
return Stream.concat(
66+
Stream.of(minValue, maxValue),
67+
RANDOM.ints(1, minValue, maxValue)
68+
.mapToObj(value -> Byte.valueOf((byte) value))
69+
);
70+
}
71+
72+
@NonNull
73+
private static Stream<Short> getShortStream(Object[] args) {
74+
var minValue = Short.MIN_VALUE;
75+
var maxValue = (short) (Long.valueOf((long) args[0]).shortValue() - 1);
76+
77+
return Stream.concat(
78+
Stream.of(minValue, maxValue),
79+
RANDOM.ints(1, minValue, maxValue)
80+
.mapToObj(value -> Short.valueOf((short) value))
81+
);
82+
}
83+
5284
@NonNull
5385
private static Stream<Integer> getIntegerStream(Object[] args) {
5486
var minValue = Integer.MIN_VALUE;
5587
var maxValue = Long.valueOf((long) args[0]).intValue() - 1;
5688

5789
return Stream.concat(
5890
Stream.of(minValue, maxValue),
59-
RANDOM.ints(minValue, maxValue).limit(1).boxed()
91+
RANDOM.ints(1, minValue, maxValue).boxed()
6092
);
6193
}
6294

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

68100
return Stream.concat(
69101
Stream.of(minValue, maxValue),
70-
RANDOM.longs(minValue, maxValue).limit(1).boxed()
102+
RANDOM.longs(1, minValue, maxValue).boxed()
71103
);
72104
}
73105

@@ -78,7 +110,7 @@ private static Stream<Float> getFloatStream(Object[] args) {
78110

79111
return Stream.concat(
80112
Stream.of(minValue, maxValue),
81-
RANDOM.doubles(1).map(d -> minValue + (maxValue - minValue) * d).boxed().map(
113+
RANDOM.doubles(1, minValue, maxValue).boxed().map(
82114
Double::floatValue
83115
)
84116
);
@@ -91,7 +123,20 @@ private static Stream<Double> getDoubleStream(Object[] args) {
91123

92124
return Stream.concat(
93125
Stream.of(minValue, maxValue),
94-
RANDOM.doubles(1).map(d -> minValue + (maxValue - minValue) * d).boxed()
126+
RANDOM.doubles(1, minValue, maxValue).boxed()
127+
);
128+
}
129+
130+
@NonNull
131+
private static Stream<BigInteger> getBigIntegerStream(Object[] args) {
132+
var minValue = Long.MIN_VALUE;
133+
var maxValue = (long) args[0] - 1;
134+
135+
return Stream.concat(
136+
Stream.of(BigInteger.valueOf(minValue), BigInteger.valueOf(maxValue)),
137+
RANDOM.longs(1, minValue, maxValue).boxed().map(
138+
BigInteger::valueOf
139+
)
95140
);
96141
}
97142

@@ -102,7 +147,9 @@ private static Stream<BigDecimal> getBigDecimalStream(Object[] args) {
102147

103148
return Stream.concat(
104149
Stream.of(BigDecimal.valueOf(minValue), BigDecimal.valueOf(maxValue)),
105-
RANDOM.doubles(1).map(d -> minValue + (maxValue - minValue) * d).boxed().map(BigDecimal::valueOf)
150+
RANDOM.doubles(1, minValue, maxValue).boxed().map(
151+
BigDecimal::valueOf
152+
)
106153
);
107154
}
108155

@@ -113,7 +160,9 @@ private static Stream<ScaledBigDecimal> getScaledBigDecimalStream(Object[] args)
113160

114161
return Stream.concat(
115162
Stream.of(ScaledBigDecimal.valueOf(minValue), ScaledBigDecimal.valueOf(maxValue)),
116-
RANDOM.doubles(1).map(d -> minValue + (maxValue - minValue) * d).boxed().map(ScaledBigDecimal::valueOf)
163+
RANDOM.doubles(1, minValue, maxValue).boxed().map(
164+
ScaledBigDecimal::valueOf
165+
)
117166
);
118167
}
119168
}

0 commit comments

Comments
 (0)