Skip to content

Commit df3d5cf

Browse files
SirCotareThoSap
andauthored
update (#32)
* update versions * add validation tools for new toolbox * Update src/test/java/it/aboutbits/springboot/testing/validation/ValidationAssertTest.java Co-authored-by: Thomas Sapelza <[email protected]> --------- Co-authored-by: Thomas Sapelza <[email protected]>
1 parent 592c73f commit df3d5cf

File tree

9 files changed

+388
-5
lines changed

9 files changed

+388
-5
lines changed

pom.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
2+
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
34
<modelVersion>4.0.0</modelVersion>
45

56
<parent>
67
<groupId>org.springframework.boot</groupId>
78
<artifactId>spring-boot-starter-parent</artifactId>
8-
<version>4.0.1</version>
9+
<version>4.0.2</version>
910
<relativePath/> <!-- lookup parent from repository -->
1011
</parent>
1112

@@ -25,7 +26,7 @@
2526
<dependency>
2627
<groupId>it.aboutbits</groupId>
2728
<artifactId>spring-boot-toolbox</artifactId>
28-
<version>2.1.0-RC1</version>
29+
<version>2.1.0</version>
2930
</dependency>
3031
<dependency>
3132
<groupId>it.aboutbits</groupId>

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,12 @@
1414
import it.aboutbits.springboot.testing.validation.rule.PastRule;
1515
import it.aboutbits.springboot.testing.validation.rule.PositiveOrZeroRule;
1616
import it.aboutbits.springboot.testing.validation.rule.PositiveRule;
17+
import it.aboutbits.springboot.testing.validation.rule.RepeatedFieldRule;
1718
import it.aboutbits.springboot.testing.validation.rule.SizeRule;
1819
import it.aboutbits.springboot.testing.validation.rule.ValidBeanRule;
20+
import it.aboutbits.springboot.testing.validation.rule.ValidDateRangeRule;
21+
import it.aboutbits.springboot.testing.validation.rule.ValidNumericRangeRule;
22+
import it.aboutbits.springboot.testing.validation.rule.ValidPasswordRule;
1923
import lombok.AccessLevel;
2024
import lombok.Getter;
2125
import lombok.Setter;
@@ -39,13 +43,17 @@ public abstract class BaseRuleBuilder<R extends BaseRuleBuilder<R>> implements
3943
NotBlankRule<R>,
4044
NotEmptyRule<R>,
4145
NotNullRule<R>,
46+
NotValidatedRule<R>,
4247
NullableRule<R>,
4348
PastRule<R>,
4449
PositiveOrZeroRule<R>,
4550
PositiveRule<R>,
46-
NotValidatedRule<R>,
51+
RepeatedFieldRule<R>,
4752
SizeRule<R>,
48-
ValidBeanRule<R> {
53+
ValidBeanRule<R>,
54+
ValidDateRangeRule<R>,
55+
ValidNumericRangeRule<R>,
56+
ValidPasswordRule<R> {
4957
@Getter(AccessLevel.PACKAGE)
5058
private final List<Rule> rules = new ArrayList<>();
5159

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package it.aboutbits.springboot.testing.validation.rule;
2+
3+
import it.aboutbits.springboot.testing.validation.core.BaseRuleBuilder;
4+
import it.aboutbits.springboot.testing.validation.core.CustomValidationFunction;
5+
import it.aboutbits.springboot.testing.validation.core.ValidationRulesData;
6+
import it.aboutbits.springboot.toolbox.validation.annotation.RepeatedField;
7+
import org.jspecify.annotations.NullMarked;
8+
9+
import java.util.Arrays;
10+
11+
@SuppressWarnings("unchecked")
12+
@NullMarked
13+
public interface RepeatedFieldRule<V extends BaseRuleBuilder<?>> extends ValidationRulesData {
14+
default V repeatedField(String originalField, String repeatedField) {
15+
addValidationFunction(
16+
(Object o) -> {
17+
var isValid = false;
18+
var currentClass = o.getClass();
19+
20+
while (currentClass != null) {
21+
var annotations = currentClass.getDeclaredAnnotationsByType(RepeatedField.class);
22+
23+
isValid = Arrays.stream(annotations).anyMatch(
24+
a -> a.originalField().equals(originalField) && a.repeatedField()
25+
.equals(repeatedField)
26+
);
27+
28+
if (isValid) {
29+
break;
30+
}
31+
currentClass = currentClass.getSuperclass();
32+
}
33+
34+
return new CustomValidationFunction.Result(
35+
isValid,
36+
"@RepeatedField(originalField = \"%s\", repeatedField = \"%s\") is missing.".formatted(
37+
originalField,
38+
repeatedField
39+
)
40+
);
41+
}
42+
);
43+
44+
return (V) this;
45+
}
46+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package it.aboutbits.springboot.testing.validation.rule;
2+
3+
import it.aboutbits.springboot.testing.validation.core.BaseRuleBuilder;
4+
import it.aboutbits.springboot.testing.validation.core.CustomValidationFunction;
5+
import it.aboutbits.springboot.testing.validation.core.ValidationRulesData;
6+
import it.aboutbits.springboot.toolbox.validation.annotation.ValidDateRange;
7+
import org.jspecify.annotations.NullMarked;
8+
9+
import java.util.Arrays;
10+
11+
@SuppressWarnings("unchecked")
12+
@NullMarked
13+
public interface ValidDateRangeRule<V extends BaseRuleBuilder<?>> extends ValidationRulesData {
14+
default V validDateRange(String fromDateField, String toDateField) {
15+
addValidationFunction(
16+
(Object o) -> {
17+
var isValid = false;
18+
var currentClass = o.getClass();
19+
20+
while (currentClass != null) {
21+
var annotations = currentClass.getDeclaredAnnotationsByType(ValidDateRange.class);
22+
23+
isValid = Arrays.stream(annotations).anyMatch(
24+
a -> a.fromDateField().equals(fromDateField) && a.toDateField()
25+
.equals(toDateField)
26+
);
27+
28+
if (isValid) {
29+
break;
30+
}
31+
currentClass = currentClass.getSuperclass();
32+
}
33+
34+
return new CustomValidationFunction.Result(
35+
isValid,
36+
"@ValidDateRange(fromDateField = \"%s\", toDateField = \"%s\") is missing.".formatted(
37+
fromDateField,
38+
toDateField
39+
)
40+
);
41+
}
42+
);
43+
44+
return (V) this;
45+
}
46+
47+
default V validDateRange(
48+
String fromDateField,
49+
String toDateField,
50+
boolean allowEmptyRange
51+
) {
52+
addValidationFunction(
53+
(Object o) -> {
54+
var isValid = false;
55+
var currentClass = o.getClass();
56+
57+
while (currentClass != null) {
58+
var annotations = currentClass.getDeclaredAnnotationsByType(ValidDateRange.class);
59+
60+
isValid = Arrays.stream(annotations).anyMatch(
61+
a -> a.fromDateField().equals(fromDateField)
62+
&& a.toDateField().equals(toDateField)
63+
&& a.allowEmptyRange() == allowEmptyRange
64+
);
65+
66+
if (isValid) {
67+
break;
68+
}
69+
currentClass = currentClass.getSuperclass();
70+
}
71+
72+
return new CustomValidationFunction.Result(
73+
isValid,
74+
"@ValidDateRange(fromDateField = \"%s\", toDateField = \"%s\", allowEmptyRange = %s) is missing."
75+
.formatted(fromDateField, toDateField, allowEmptyRange)
76+
);
77+
}
78+
);
79+
80+
return (V) this;
81+
}
82+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package it.aboutbits.springboot.testing.validation.rule;
2+
3+
import it.aboutbits.springboot.testing.validation.core.BaseRuleBuilder;
4+
import it.aboutbits.springboot.testing.validation.core.CustomValidationFunction;
5+
import it.aboutbits.springboot.testing.validation.core.ValidationRulesData;
6+
import it.aboutbits.springboot.toolbox.validation.annotation.ValidNumericRange;
7+
import org.jspecify.annotations.NullMarked;
8+
9+
import java.util.Arrays;
10+
11+
@SuppressWarnings("unchecked")
12+
@NullMarked
13+
public interface ValidNumericRangeRule<V extends BaseRuleBuilder<?>> extends ValidationRulesData {
14+
default V validNumericRange(String lowerBoundField, String upperBoundField) {
15+
addValidationFunction(
16+
(Object o) -> {
17+
var isValid = false;
18+
var currentClass = o.getClass();
19+
20+
while (currentClass != null) {
21+
var annotations = currentClass.getDeclaredAnnotationsByType(ValidNumericRange.class);
22+
23+
isValid = Arrays.stream(annotations).anyMatch(
24+
a -> a.lowerBoundField().equals(lowerBoundField) && a.upperBoundField()
25+
.equals(upperBoundField)
26+
);
27+
28+
if (isValid) {
29+
break;
30+
}
31+
currentClass = currentClass.getSuperclass();
32+
}
33+
34+
return new CustomValidationFunction.Result(
35+
isValid,
36+
"@ValidNumericRange(lowerBoundField = \"%s\", upperBoundField = \"%s\") is missing.".formatted(
37+
lowerBoundField,
38+
upperBoundField
39+
)
40+
);
41+
}
42+
);
43+
44+
return (V) this;
45+
}
46+
47+
default V validNumericRange(
48+
String lowerBoundField,
49+
String upperBoundField,
50+
boolean allowEqualValues
51+
) {
52+
addValidationFunction(
53+
(Object o) -> {
54+
var isValid = false;
55+
var currentClass = o.getClass();
56+
57+
while (currentClass != null) {
58+
var annotations = currentClass.getDeclaredAnnotationsByType(ValidNumericRange.class);
59+
60+
isValid = Arrays.stream(annotations).anyMatch(
61+
a -> a.lowerBoundField().equals(lowerBoundField)
62+
&& a.upperBoundField().equals(upperBoundField)
63+
&& a.allowEqualValues() == allowEqualValues
64+
);
65+
66+
if (isValid) {
67+
break;
68+
}
69+
currentClass = currentClass.getSuperclass();
70+
}
71+
72+
return new CustomValidationFunction.Result(
73+
isValid,
74+
"@ValidNumericRange(lowerBoundField = \"%s\", upperBoundField = \"%s\", allowEqualValues = %s) is missing."
75+
.formatted(lowerBoundField, upperBoundField, allowEqualValues)
76+
);
77+
}
78+
);
79+
80+
return (V) this;
81+
}
82+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package it.aboutbits.springboot.testing.validation.rule;
2+
3+
import it.aboutbits.springboot.testing.validation.core.BaseRuleBuilder;
4+
import it.aboutbits.springboot.testing.validation.core.Rule;
5+
import it.aboutbits.springboot.testing.validation.core.ValidationRulesData;
6+
import it.aboutbits.springboot.testing.validation.source.LongerThanValueSource;
7+
import it.aboutbits.springboot.testing.validation.source.ShorterThanValueSource;
8+
import org.jspecify.annotations.NullMarked;
9+
10+
@SuppressWarnings("unchecked")
11+
@NullMarked
12+
public interface ValidPasswordRule<V extends BaseRuleBuilder<?>> extends ValidationRulesData {
13+
default V validPassword(String property, long minLength, long maxLength) {
14+
addRule(
15+
new Rule(property, LongerThanValueSource.class, maxLength)
16+
);
17+
addRule(
18+
new Rule(property, ShorterThanValueSource.class, minLength)
19+
);
20+
return (V) this;
21+
}
22+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package it.aboutbits.springboot.testing.validation.source;
2+
3+
import it.aboutbits.springboot.testing.validation.core.ValueSource;
4+
import org.jspecify.annotations.NullMarked;
5+
6+
import java.util.HashMap;
7+
import java.util.Map;
8+
import java.util.Random;
9+
import java.util.function.Function;
10+
import java.util.stream.Stream;
11+
12+
@NullMarked
13+
public class LongerThanValueSource implements ValueSource {
14+
private static final Map<Class<?>, Function<Object[], Stream<?>>> TYPE_SOURCES = new HashMap<>();
15+
private static final Random RANDOM = new Random();
16+
17+
static {
18+
TYPE_SOURCES.put(String.class, LongerThanValueSource::getStream);
19+
}
20+
21+
@SuppressWarnings("unused")
22+
public static void registerType(Class<?> type, Function<Object[], Stream<?>> source) {
23+
TYPE_SOURCES.put(type, source);
24+
}
25+
26+
@Override
27+
@SuppressWarnings("unchecked")
28+
public <T> Stream<T> values(Class<T> propertyClass, Object... args) {
29+
var sourceFunction = TYPE_SOURCES.get(propertyClass);
30+
if (sourceFunction != null) {
31+
return (Stream<T>) sourceFunction.apply(args);
32+
}
33+
34+
throw new IllegalArgumentException("Property class not supported!");
35+
}
36+
37+
private static Stream<String> getStream(Object[] args) {
38+
var length = Long.valueOf((long) args[0]).intValue();
39+
var minLength = length + 1;
40+
41+
var maxLength = length + 1024;
42+
43+
if (minLength == maxLength) {
44+
return Stream.of(generateRandomString(minLength));
45+
}
46+
47+
var randomLength = RANDOM.nextInt(minLength, maxLength);
48+
49+
return Stream.of(
50+
generateRandomString(minLength),
51+
generateRandomString(maxLength),
52+
generateRandomString(randomLength)
53+
).distinct();
54+
}
55+
56+
private static String generateRandomString(int length) {
57+
return RANDOM.ints(length, 32, 127)
58+
.collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
59+
.toString();
60+
}
61+
}

0 commit comments

Comments
 (0)