Compare commits

..

6 Commits
dev ... dev

Author SHA1 Message Date
7f4f5748f8 feat(validator): 添加 notEqual 校验方法并优化 equalTo
- 新增 `notEqual` 校验方法,用于判断属性值不等于给定值。
- 优化 `equalTo` 方法的空值判断逻辑,当属性值为空时不进行校验。
2025-06-01 20:35:41 +08:00
88b3226b17 feat: 添加数组长度和集合大小的校验功能
- 在 ArrayPropertyValidator 中添加了 length 方法,用于校验数组长度。
- 在 CollectionPropertyValidator 中添加了 size 方法,用于校验集合大小。
2025-06-01 20:18:36 +08:00
0a83116e81 refactor: 将方法调用与返回语句合并,简化了代码结构 2025-06-01 20:16:42 +08:00
907d883be8 feat: 添加数组属性校验器
- 新增 `ArrayPropertyValidator` 类,提供针对数组类型的属性校验功能。
- 在 `BaseValidator` 中添加 `ruleForArray` 方法,用于创建数组属性校验器。
2025-06-01 19:00:10 +08:00
7a9e15fd45 refactor: 优化集合属性校验器
- 更新类注释
- 优化 allMatch 方法的实现,使用 forEach 替代 stream().forEach()
2025-06-01 18:57:58 +08:00
b29e1e07aa feat: 为 CollectionPropertyValidator 添加 allMatch 方法
- 新增 allMatch 方法,用于校验集合中的所有元素是否满足指定条件。支持自定义异常信息和异常类型。
- 添加相关单元测试用例。
2025-06-01 18:10:36 +08:00
13 changed files with 1402 additions and 73 deletions

View File

@ -0,0 +1,299 @@
/*
* Copyright 2023-2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.zhouxy.plusone.validator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import xyz.zhouxy.plusone.commons.util.ArrayTools;
import xyz.zhouxy.plusone.commons.util.AssertTools;
/**
* 针对数组类型的属性校验器
*
* <p>
* 内置数组相关的校验规则
*
* @author ZhouXY
*/
public class ArrayPropertyValidator<T, TElement>
extends BasePropertyValidator<T, TElement[], ArrayPropertyValidator<T, TElement>> {
ArrayPropertyValidator(Function<T, TElement[]> getter) {
super(getter);
}
// ================================
// #region - notEmpty
// ================================
/**
* 添加一条校验属性的规则校验属性是否非空
*
* @return 属性校验器
*/
public ArrayPropertyValidator<T, TElement> notEmpty() {
return notEmpty("The input must not be empty.");
}
/**
* 添加一条校验属性的规则校验属性是否非空
*
* @param errMsg 异常信息
* @return 属性校验器
*/
public ArrayPropertyValidator<T, TElement> notEmpty(String errMsg) {
return notEmpty(convertToExceptionFunction(errMsg));
}
/**
* 添加一条校验属性的规则校验属性是否非空
*
* @param <E> 自定义异常类型
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> notEmpty(
Supplier<E> e) {
return notEmpty(convertToExceptionFunction(e));
}
/**
* 添加一条校验属性的规则校验属性是否非空
*
* @param <E> 自定义异常类型
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> notEmpty(
Function<TElement[], E> e) {
return withRule(ArrayTools::isNotEmpty, e);
}
// ================================
// #endregion - notEmpty
// ================================
// ================================
// #region - isEmpty
// ================================
/**
* 添加一条校验属性的规则校验属性是否为空
*
* @return 属性校验器
*/
public ArrayPropertyValidator<T, TElement> isEmpty() {
return isEmpty("The input must be empty.");
}
/**
* 添加一条校验属性的规则校验属性是否为空
*
* @param errMsg 异常信息
* @return 属性校验器
*/
public ArrayPropertyValidator<T, TElement> isEmpty(String errMsg) {
return isEmpty(convertToExceptionFunction(errMsg));
}
/**
* 添加一条校验属性的规则校验属性是否为空
*
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> isEmpty(
Supplier<E> e) {
return isEmpty(convertToExceptionFunction(e));
}
/**
* 添加一条校验属性的规则校验属性是否为空
*
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> isEmpty(
Function<TElement[], E> e) {
return withRule(ArrayTools::isEmpty, e);
}
// ================================
// #endregion - isEmpty
// ================================
// ================================
// #region - allMatch
// ================================
/**
* 添加一条校验属性的规则校验是否所有元素都满足条件
*
* @param condition 校验规则
* @return 属性校验器
*/
public ArrayPropertyValidator<T, TElement> allMatch(Predicate<TElement> condition) {
return allMatch(condition, convertToExceptionFunction("All elements must match the condition."));
}
/**
* 添加一条校验属性的规则校验是否所有元素都满足条件
*
* @param condition 校验规则
* @param errMsg 异常信息
* @return 属性校验器
*/
public ArrayPropertyValidator<T, TElement> allMatch(Predicate<TElement> condition, String errMsg) {
return allMatch(condition, convertToExceptionFunction(errMsg));
}
/**
* 添加一条校验属性的规则校验是否所有元素都满足条件
*
* @param condition 校验规则
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> allMatch(
Predicate<TElement> condition, Supplier<E> e) {
return allMatch(condition, convertToExceptionFunction(e));
}
/**
* 添加一条校验属性的规则校验是否所有元素都满足条件
*
* @param condition 校验规则
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> allMatch(
Predicate<TElement> condition, Function<TElement, E> e) {
return withRule(c -> {
for (TElement element : c) {
if (!condition.test(element)) {
throw e.apply(element);
}
}
});
}
// ================================
// #endregion - allMatch
// ================================
// ================================
// #region - length
// ================================
/**
* 添加一条校验属性的规则校验属性长度是否等于指定长度
*
* @param length 指定长度
* @param errMsg 异常信息
* @return 属性校验器
*/
public ArrayPropertyValidator<T, TElement> length(int length, String errMsg) {
return length(length, convertToExceptionFunction(errMsg));
}
/**
* 添加一条校验属性的规则校验属性长度是否等于指定长度
*
* @param <E> 异常类型
* @param length 指定长度
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> length(
int length, Supplier<E> e) {
return length(length, convertToExceptionFunction(e));
}
/**
* 添加一条校验属性的规则校验属性长度是否等于指定长度
*
* @param <E> 异常类型
* @param length 指定长度
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> length(
int length, Function<TElement[], E> e) {
AssertTools.checkArgument(length >= 0,
"The expected length must be greater than or equal to 0.");
return withRule(s -> s == null || s.length == length, e);
}
static <TElement> boolean checkLength(TElement[] str, int min, int max) {
if (str == null) {
return true;
}
final int len = str.length;
return len >= min && len <= max;
}
/**
* 添加一条校验属性的规则校验属性的长度范围
*
* @param min 最小长度
* @param max 最大长度
* @param errMsg 错误信息
* @return 属性校验器
*/
public ArrayPropertyValidator<T, TElement> length(int min, int max, String errMsg) {
return length(min, max, convertToExceptionFunction(errMsg));
}
/**
* 添加一条校验属性的规则校验属性的长度范围
*
* @param min 最小长度
* @param max 最大长度
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> length(
int min, int max, Supplier<E> e) {
return length(min, max, convertToExceptionFunction(e));
}
/**
* 添加一条校验属性的规则校验属性的长度范围
*
* @param min 最小长度
* @param max 最大长度
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> ArrayPropertyValidator<T, TElement> length(
int min, int max, Function<TElement[], E> e) {
AssertTools.checkArgument(min >= 0, "min must be non-negative.");
AssertTools.checkArgument(min <= max, "min must be less than or equal to max.");
return withRule(s -> checkLength(s, min, max), e);
}
// ================================
// #endregion - length
// ================================
@Override
protected ArrayPropertyValidator<T, TElement> thisObject() {
return this;
}
}

View File

@ -53,11 +53,22 @@ public abstract class BasePropertyValidator<T, TProperty, TPropertyValidator ext
*/
protected final <E extends RuntimeException> TPropertyValidator withRule(
Predicate<? super TProperty> rule, Function<TProperty, E> e) {
this.consumers.add(v -> {
return withRule(v -> {
if (!rule.test(v)) {
throw e.apply(v);
}
});
}
/**
* 添加一条校验属性的规则
*
* @param rule 校验规则
* @param e 自定义异常
* @return 属性校验器
*/
protected final TPropertyValidator withRule(Consumer<? super TProperty> rule) {
this.consumers.add(rule);
return thisObject();
}
@ -226,7 +237,7 @@ public abstract class BasePropertyValidator<T, TProperty, TPropertyValidator ext
*/
public <E extends RuntimeException> TPropertyValidator equalTo(
Object that, Function<TProperty, E> e) {
withRule(value -> Objects.equals(value, that), e);
withRule(value -> value == null || value.equals(that), e);
return thisObject();
}
@ -234,6 +245,63 @@ public abstract class BasePropertyValidator<T, TProperty, TPropertyValidator ext
// #endregion - equalTo
// ================================
// ================================
// #region - notEqual
// ================================
/**
* 添加一条校验属性的规则校验属性是否等于给定值
*
* @param that 给定值
* @return 属性校验器
*/
public TPropertyValidator notEqual(Object that) {
return notEqual(that, value -> ValidationException
.withMessage("The input must not equal '%s'.", that));
}
/**
* 添加一条校验属性的规则校验属性是否等于给定值
*
* @param that 给定值
* @param errMsg 错误信息
* @return 属性校验器
*/
public TPropertyValidator notEqual(Object that, String errMsg) {
return notEqual(that, convertToExceptionFunction(errMsg));
}
/**
* 添加一条校验属性的规则校验属性是否等于给定值
*
* @param <E> 自定义异常类型
* @param that 给定值
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> TPropertyValidator notEqual(
Object that, Supplier<E> e) {
return notEqual(that, convertToExceptionFunction(e));
}
/**
* 添加一条校验属性的规则校验属性是否等于给定值
*
* @param <E> 自定义异常类型
* @param that 给定值
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> TPropertyValidator notEqual(
Object that, Function<TProperty, E> e) {
withRule(value -> value == null || !value.equals(that), e);
return thisObject();
}
// ================================
// #endregion - notEqual
// ================================
// ================================
// #region - must
// ================================

View File

@ -247,6 +247,18 @@ public abstract class BaseValidator<T> implements IValidator<T> {
return validator;
}
/**
* 添加一个针对数组属性的校验器
*
* @param getter 获取属性值的函数
* @return 集合属性校验器
*/
protected final <E> ArrayPropertyValidator<T, E> ruleForArray(Function<T, E[]> getter) {
ArrayPropertyValidator<T, E> validator = new ArrayPropertyValidator<>(getter);
this.rules.add(validator::validate);
return validator;
}
/**
* 添加一个针对二元组的校验器
* @param <V1> 第一个元素的类型

View File

@ -74,8 +74,7 @@ public class BoolPropertyValidator<T> extends BasePropertyValidator<T, Boolean,
* @return 属性校验器
*/
public <E extends RuntimeException> BoolPropertyValidator<T> isTrueValue(Function<Boolean, E> e) {
withRule(Boolean.TRUE::equals, e);
return this;
return withRule(Boolean.TRUE::equals, e);
}
// ====== isFalseValue ======
@ -118,8 +117,7 @@ public class BoolPropertyValidator<T> extends BasePropertyValidator<T, Boolean,
* @return 属性校验器
*/
public <E extends RuntimeException> BoolPropertyValidator<T> isFalseValue(Function<Boolean, E> e) {
withRule(Boolean.FALSE::equals, e);
return this;
return withRule(Boolean.FALSE::equals, e);
}
@Override

View File

@ -18,15 +18,17 @@ package xyz.zhouxy.plusone.validator;
import java.util.Collection;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;
import xyz.zhouxy.plusone.commons.collection.CollectionTools;
import xyz.zhouxy.plusone.commons.util.AssertTools;
/**
* 针对集合类型的属性校验器
*
* <p>
* 内置判断集合是否为空的校验规则
* 内置集合相关的校验规则
*
* @author ZhouXY
*/
@ -37,7 +39,9 @@ public class CollectionPropertyValidator<T, TElement>
super(getter);
}
// ====== notEmpty =====
// ================================
// #region - notEmpty
// ================================
/**
* 添加一条校验属性的规则校验属性是否非空
@ -79,11 +83,16 @@ public class CollectionPropertyValidator<T, TElement>
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> notEmpty(
Function<Collection<TElement>, E> e) {
withRule(CollectionTools::isNotEmpty, e);
return this;
return withRule(CollectionTools::isNotEmpty, e);
}
// ====== isEmpty =====
// ================================
// #endregion - notEmpty
// ================================
// ================================
// #region - isEmpty
// ================================
/**
* 添加一条校验属性的规则校验属性是否为空
@ -123,10 +132,165 @@ public class CollectionPropertyValidator<T, TElement>
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> isEmpty(
Function<Collection<TElement>, E> e) {
withRule(CollectionTools::isEmpty, e);
return this;
return withRule(CollectionTools::isEmpty, e);
}
// ================================
// #endregion - isEmpty
// ================================
// ================================
// #region - allMatch
// ================================
/**
* 添加一条校验属性的规则校验是否所有元素都满足条件
*
* @param condition 校验规则
* @return 属性校验器
*/
public CollectionPropertyValidator<T, TElement> allMatch(Predicate<TElement> condition) {
return allMatch(condition, convertToExceptionFunction("All elements must match the condition."));
}
/**
* 添加一条校验属性的规则校验是否所有元素都满足条件
*
* @param condition 校验规则
* @param errMsg 异常信息
* @return 属性校验器
*/
public CollectionPropertyValidator<T, TElement> allMatch(Predicate<TElement> condition, String errMsg) {
return allMatch(condition, convertToExceptionFunction(errMsg));
}
/**
* 添加一条校验属性的规则校验是否所有元素都满足条件
*
* @param condition 校验规则
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> allMatch(
Predicate<TElement> condition, Supplier<E> e) {
return allMatch(condition, convertToExceptionFunction(e));
}
/**
* 添加一条校验属性的规则校验是否所有元素都满足条件
*
* @param condition 校验规则
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> allMatch(
Predicate<TElement> condition, Function<TElement, E> e) {
return withRule(c -> c.forEach(element -> {
if (!condition.test(element)) {
throw e.apply(element);
}
}));
}
// ================================
// #endregion - allMatch
// ================================
// ================================
// #region - size
// ================================
/**
* 添加一条校验属性的规则校验属性大小是否等于指定大小
*
* @param size 指定大小
* @param errMsg 异常信息
* @return 属性校验器
*/
public CollectionPropertyValidator<T, TElement> size(int size, String errMsg) {
return size(size, convertToExceptionFunction(errMsg));
}
/**
* 添加一条校验属性的规则校验属性大小是否等于指定大小
*
* @param <E> 异常类型
* @param size 指定大小
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> size(
int size, Supplier<E> e) {
return size(size, convertToExceptionFunction(e));
}
/**
* 添加一条校验属性的规则校验属性大小是否等于指定大小
*
* @param <E> 异常类型
* @param size 指定大小
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> size(
int size, Function<Collection<TElement>, E> e) {
AssertTools.checkArgument(size >= 0,
"The expected size must be greater than or equal to 0.");
return withRule(s -> s == null || s.size() == size, e);
}
static <TElement> boolean checkSize(Collection<TElement> str, int min, int max) {
if (str == null) {
return true;
}
final int size = str.size();
return size >= min && size <= max;
}
/**
* 添加一条校验属性的规则校验属性的大小范围
*
* @param min 最小大小
* @param max 最大大小
* @param errMsg 错误信息
* @return 属性校验器
*/
public CollectionPropertyValidator<T, TElement> size(int min, int max, String errMsg) {
return size(min, max, convertToExceptionFunction(errMsg));
}
/**
* 添加一条校验属性的规则校验属性的大小范围
*
* @param min 最小大小
* @param max 最大大小
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> size(
int min, int max, Supplier<E> e) {
return size(min, max, convertToExceptionFunction(e));
}
/**
* 添加一条校验属性的规则校验属性的大小范围
*
* @param min 最小大小
* @param max 最大大小
* @param e 自定义异常
* @return 属性校验器
*/
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> size(
int min, int max, Function<Collection<TElement>, E> e) {
AssertTools.checkArgument(min >= 0, "min must be non-negative.");
AssertTools.checkArgument(min <= max, "min must be less than or equal to max.");
return withRule(s -> checkSize(s, min, max), e);
}
// ================================
// #endregion - size
// ================================
@Override
protected CollectionPropertyValidator<T, TElement> thisObject() {
return this;

View File

@ -80,8 +80,7 @@ public class DoublePropertyValidator<T>
* @return 属性校验器
*/
public <E extends RuntimeException> DoublePropertyValidator<T> gt(double min, Function<Double, E> e) {
withRule(value -> (value != null && value > min), e);
return this;
return withRule(value -> (value != null && value > min), e);
}
// ================================
@ -134,8 +133,7 @@ public class DoublePropertyValidator<T>
* @return 属性校验器
*/
public <E extends RuntimeException> DoublePropertyValidator<T> ge(double min, Function<Double, E> e) {
withRule(value -> (value != null && value >= min), e);
return this;
return withRule(value -> (value != null && value >= min), e);
}
// ================================
@ -188,8 +186,7 @@ public class DoublePropertyValidator<T>
* @return 属性校验器
*/
public <E extends RuntimeException> DoublePropertyValidator<T> lt(double max, Function<Double, E> e) {
withRule(value -> (value != null && value < max), e);
return this;
return withRule(value -> (value != null && value < max), e);
}
// ================================
@ -242,8 +239,7 @@ public class DoublePropertyValidator<T>
* @return 属性校验器
*/
public <E extends RuntimeException> DoublePropertyValidator<T> le(double max, Function<Double, E> e) {
withRule(value -> (value != null && value <= max), e);
return this;
return withRule(value -> (value != null && value <= max), e);
}
// ================================

View File

@ -80,8 +80,7 @@ public class IntPropertyValidator<T>
* @return 属性校验器
*/
public <E extends RuntimeException> IntPropertyValidator<T> gt(int min, Function<Integer, E> e) {
withRule(value -> (value != null && value > min), e);
return this;
return withRule(value -> (value != null && value > min), e);
}
// ================================
@ -134,8 +133,7 @@ public class IntPropertyValidator<T>
* @return 属性校验器
*/
public <E extends RuntimeException> IntPropertyValidator<T> ge(int min, Function<Integer, E> e) {
withRule(value -> (value != null && value >= min), e);
return this;
return withRule(value -> (value != null && value >= min), e);
}
// ================================
@ -188,8 +186,7 @@ public class IntPropertyValidator<T>
* @return 属性校验器
*/
public <E extends RuntimeException> IntPropertyValidator<T> lt(int max, Function<Integer, E> e) {
withRule(value -> (value != null && value < max), e);
return this;
return withRule(value -> (value != null && value < max), e);
}
// ================================
@ -242,8 +239,7 @@ public class IntPropertyValidator<T>
* @return 属性校验器
*/
public <E extends RuntimeException> IntPropertyValidator<T> le(int max, Function<Integer, E> e) {
withRule(value -> (value != null && value <= max), e);
return this;
return withRule(value -> (value != null && value <= max), e);
}
// ================================

View File

@ -80,8 +80,7 @@ public class LongPropertyValidator<T>
* @return 属性校验器
*/
public <E extends RuntimeException> LongPropertyValidator<T> gt(long min, Function<Long, E> e) {
withRule(value -> (value != null && value > min), e);
return this;
return withRule(value -> (value != null && value > min), e);
}
// ================================
@ -134,8 +133,7 @@ public class LongPropertyValidator<T>
* @return 属性校验器
*/
public <E extends RuntimeException> LongPropertyValidator<T> ge(long min, Function<Long, E> e) {
withRule(value -> (value != null && value >= min), e);
return this;
return withRule(value -> (value != null && value >= min), e);
}
// ================================
@ -188,8 +186,7 @@ public class LongPropertyValidator<T>
* @return 属性校验器
*/
public <E extends RuntimeException> LongPropertyValidator<T> lt(long max, Function<Long, E> e) {
withRule(value -> (value != null && value < max), e);
return this;
return withRule(value -> (value != null && value < max), e);
}
// ================================
@ -242,8 +239,7 @@ public class LongPropertyValidator<T>
* @return 属性校验器
*/
public <E extends RuntimeException> LongPropertyValidator<T> le(long max, Function<Long, E> e) {
withRule(value -> (value != null && value <= max), e);
return this;
return withRule(value -> (value != null && value <= max), e);
}
// ================================

View File

@ -80,8 +80,7 @@ public class StringPropertyValidator<T> extends BaseComparablePropertyValidator<
*/
public <E extends RuntimeException> StringPropertyValidator<T> matches(
Pattern regex, Function<String, E> e) {
withRule(input -> (input == null || RegexTools.matches(input, regex)), e);
return this;
return withRule(input -> (input == null || RegexTools.matches(input, regex)), e);
}
// ================================
@ -126,8 +125,7 @@ public class StringPropertyValidator<T> extends BaseComparablePropertyValidator<
*/
public <E extends RuntimeException> StringPropertyValidator<T> matchesOne(
Pattern[] regexs, Function<String, E> e) {
withRule(input -> input == null || RegexTools.matchesOne(input, regexs), e);
return this;
return withRule(input -> input == null || RegexTools.matchesOne(input, regexs), e);
}
/**
@ -164,8 +162,7 @@ public class StringPropertyValidator<T> extends BaseComparablePropertyValidator<
*/
public <E extends RuntimeException> StringPropertyValidator<T> matchesOne(
List<Pattern> regexs, Function<String, E> e) {
withRule(input -> input == null || RegexTools.matchesOne(input, regexs.toArray(new Pattern[regexs.size()])), e);
return this;
return withRule(input -> input == null || RegexTools.matchesOne(input, regexs.toArray(new Pattern[regexs.size()])), e);
}
// ================================
@ -210,8 +207,7 @@ public class StringPropertyValidator<T> extends BaseComparablePropertyValidator<
*/
public <E extends RuntimeException> StringPropertyValidator<T> matchesAll(
Pattern[] regexs, Function<String, E> e) {
withRule(input -> input == null || RegexTools.matchesAll(input, regexs), e);
return this;
return withRule(input -> input == null || RegexTools.matchesAll(input, regexs), e);
}
/**
@ -248,8 +244,7 @@ public class StringPropertyValidator<T> extends BaseComparablePropertyValidator<
*/
public <E extends RuntimeException> StringPropertyValidator<T> matchesAll(
Collection<Pattern> regexs, Function<String, E> e) {
withRule(input -> input == null || RegexTools.matchesAll(input, regexs.toArray(new Pattern[regexs.size()])), e);
return this;
return withRule(input -> input == null || RegexTools.matchesAll(input, regexs.toArray(new Pattern[regexs.size()])), e);
}
// ================================
@ -298,8 +293,7 @@ public class StringPropertyValidator<T> extends BaseComparablePropertyValidator<
* @return 属性校验器
*/
public <E extends RuntimeException> StringPropertyValidator<T> notBlank(Function<String, E> e) {
withRule(StringTools::isNotBlank, e);
return this;
return withRule(StringTools::isNotBlank, e);
}
// ================================
@ -399,8 +393,7 @@ public class StringPropertyValidator<T> extends BaseComparablePropertyValidator<
*/
public <E extends RuntimeException> StringPropertyValidator<T> notEmpty(
Function<String, E> e) {
withRule(s -> s != null && !s.isEmpty(), e);
return this;
return withRule(s -> s != null && !s.isEmpty(), e);
}
// ================================
@ -445,11 +438,10 @@ public class StringPropertyValidator<T> extends BaseComparablePropertyValidator<
public <E extends RuntimeException> StringPropertyValidator<T> length(int length, Function<String, E> e) {
AssertTools.checkArgument(length >= 0,
"The expected length must be greater than or equal to 0.");
withRule(s -> s == null || s.length() == length, e);
return this;
return withRule(s -> s == null || s.length() == length, e);
}
static boolean length(String str, int min, int max) {
static boolean checkLength(String str, int min, int max) {
if (str == null) {
return true;
}
@ -494,8 +486,7 @@ public class StringPropertyValidator<T> extends BaseComparablePropertyValidator<
Function<String, E> e) {
AssertTools.checkArgument(min >= 0, "min must be non-negative.");
AssertTools.checkArgument(min <= max, "min must be less than or equal to max.");
withRule(s -> length(s, min, max), e);
return this;
return withRule(s -> checkLength(s, min, max), e);
}
// ================================

View File

@ -16,6 +16,7 @@
package xyz.zhouxy.plusone.example;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
/**
@ -30,13 +31,14 @@ public class ExampleCommand {
private LocalDateTime dateTimeProperty;
private Foo objectProperty;
private List<String> stringListProperty;
private String[] stringArrayProperty;
public ExampleCommand() {
}
public ExampleCommand(Boolean boolProperty, Integer intProperty, Long longProperty, Double doubleProperty,
String stringProperty, LocalDateTime dateTimeProperty, Foo objectProperty,
List<String> stringListProperty) {
List<String> stringListProperty, String[] stringArrayProperty) {
this.boolProperty = boolProperty;
this.intProperty = intProperty;
this.longProperty = longProperty;
@ -45,6 +47,7 @@ public class ExampleCommand {
this.dateTimeProperty = dateTimeProperty;
this.objectProperty = objectProperty;
this.stringListProperty = stringListProperty;
this.stringArrayProperty = stringArrayProperty;
}
public Boolean getBoolProperty() {
@ -111,11 +114,20 @@ public class ExampleCommand {
this.stringListProperty = stringListProperty;
}
public String[] getStringArrayProperty() {
return stringArrayProperty;
}
public void setStringArrayProperty(String[] stringArrayProperty) {
this.stringArrayProperty = stringArrayProperty;
}
@Override
public String toString() {
return "ExampleCommand [boolProperty=" + boolProperty + ", intProperty=" + intProperty + ", longProperty="
+ longProperty + ", doubleProperty=" + doubleProperty + ", stringProperty=" + stringProperty
+ ", dateTimeProperty=" + dateTimeProperty + ", objectProperty=" + objectProperty
+ ", stringListProperty=" + stringListProperty + "]";
+ ", stringListProperty=" + stringListProperty + ", stringArrayProperty="
+ Arrays.toString(stringArrayProperty) + "]";
}
}

View File

@ -0,0 +1,516 @@
/*
* Copyright 2025 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xyz.zhouxy.plusone.example.validator;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.Arrays;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import xyz.zhouxy.plusone.ExampleException;
import xyz.zhouxy.plusone.example.ExampleCommand;
import xyz.zhouxy.plusone.validator.BaseValidator;
import xyz.zhouxy.plusone.validator.IValidator;
import xyz.zhouxy.plusone.validator.ValidationException;
public class ArrayPropertyValidatorTests {
static final String MESSAGE_NOT_EMPTY = "The stringArrayProperty should not be empty.";
static final String MESSAGE_EMPTY = "The stringArrayProperty should be empty.";
// ================================
// #region - notEmpty
// ================================
@Test
void notEmpty_stringListIsNotEmpty() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty).notEmpty();
ruleForArray(ExampleCommand::getStringArrayProperty).notEmpty(MESSAGE_NOT_EMPTY);
ruleForArray(ExampleCommand::getStringArrayProperty)
.notEmpty(() -> ExampleException.withMessage(MESSAGE_NOT_EMPTY));
ruleForArray(ExampleCommand::getStringArrayProperty)
.notEmpty(strList -> ExampleException.withMessage(
"The stringArrayProperty should not be empty, but it is %s.", Arrays.toString(strList)));
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] {"A", "B", "C"});
assertDoesNotThrow(() -> validator.validate(command));
}
@Test
void notEmpty_default_stringListIsEmpty() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty).notEmpty();
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] {});
ValidationException e = assertThrows(ValidationException.class, () -> validator.validate(command));
assertEquals("The input must not be empty.", e.getMessage());
}
@Test
void notEmpty_message_stringListIsEmpty() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty).notEmpty(MESSAGE_NOT_EMPTY);
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] {});
ValidationException e = assertThrows(ValidationException.class, () -> validator.validate(command));
assertEquals(MESSAGE_NOT_EMPTY, e.getMessage());
}
@Test
void notEmpty_exceptionSupplier_stringListIsEmpty() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.notEmpty(() -> ExampleException.withMessage(MESSAGE_NOT_EMPTY));
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] {});
ExampleException e = assertThrows(ExampleException.class, () -> validator.validate(command));
assertEquals(MESSAGE_NOT_EMPTY, e.getMessage());
}
@Test
void notEmpty_exceptionFunction_stringListIsEmpty() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.notEmpty(strList -> ExampleException.withMessage(
"The stringArrayProperty should not be empty, but it is %s.", Arrays.toString(strList)));
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] {});
ExampleException e = assertThrows(ExampleException.class, () -> validator.validate(command));
assertEquals("The stringArrayProperty should not be empty, but it is [].", e.getMessage());
}
@Test
void notEmpty_message_stringListIsNull() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty).notEmpty(MESSAGE_NOT_EMPTY);
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(null);
ValidationException e = assertThrows(ValidationException.class, () -> validator.validate(command));
assertEquals(MESSAGE_NOT_EMPTY, e.getMessage());
}
@Test
void notEmpty_exceptionSupplier_stringListIsNull() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.notEmpty(() -> ExampleException.withMessage(MESSAGE_NOT_EMPTY));
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(null);
ExampleException e = assertThrows(ExampleException.class, () -> validator.validate(command));
assertEquals(MESSAGE_NOT_EMPTY, e.getMessage());
}
@Test
void notEmpty_exceptionFunction_stringListIsNull() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.notEmpty(strList -> ExampleException.withMessage(
"The stringArrayProperty should not be empty, but it is %s.", Arrays.toString(strList)));
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(null);
ExampleException e = assertThrows(ExampleException.class, () -> validator.validate(command));
assertEquals("The stringArrayProperty should not be empty, but it is null.", e.getMessage());
}
// ================================
// #endregion - notEmpty
// ================================
// ================================
// #region - isEmpty
// ================================
@Test
void isEmpty_stringListIsEmpty() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty).isEmpty();
ruleForArray(ExampleCommand::getStringArrayProperty).isEmpty(MESSAGE_EMPTY);
ruleForArray(ExampleCommand::getStringArrayProperty)
.isEmpty(() -> ExampleException.withMessage(MESSAGE_EMPTY));
ruleForArray(ExampleCommand::getStringArrayProperty)
.isEmpty(strList -> ExampleException.withMessage(
"The stringArrayProperty should be empty, but it is %s.", Arrays.toString(strList)));
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] {});
assertDoesNotThrow(() -> validator.validate(command));
}
@Test
void isEmpty_stringListIsNull() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty).isEmpty();
ruleForArray(ExampleCommand::getStringArrayProperty).isEmpty(MESSAGE_EMPTY);
ruleForArray(ExampleCommand::getStringArrayProperty)
.isEmpty(() -> ExampleException.withMessage(MESSAGE_EMPTY));
ruleForArray(ExampleCommand::getStringArrayProperty)
.isEmpty(strList -> ExampleException.withMessage(
"The stringArrayProperty should be empty, but it is %s.", Arrays.toString(strList)));
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(null);
assertDoesNotThrow(() -> validator.validate(command));
}
@Test
void isEmpty_default_stringListIsNotEmpty() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty).isEmpty();
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] { "A", "B", "C" });
ValidationException e = assertThrows(ValidationException.class, () -> validator.validate(command));
assertEquals("The input must be empty.", e.getMessage());
}
@Test
void isEmpty_message_stringListIsNotEmpty() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty).isEmpty(MESSAGE_EMPTY);
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] { "A", "B", "C" });
ValidationException e = assertThrows(ValidationException.class, () -> validator.validate(command));
assertEquals(MESSAGE_EMPTY, e.getMessage());
}
@Test
void isEmpty_exceptionSupplier_stringListIsNotEmpty() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.isEmpty(() -> ExampleException.withMessage(MESSAGE_EMPTY));
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] { "A", "B", "C" });
ExampleException e = assertThrows(ExampleException.class, () -> validator.validate(command));
assertEquals(MESSAGE_EMPTY, e.getMessage());
}
@Test
void isEmpty_exceptionFunction_stringListIsNotEmpty() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.isEmpty(strList -> ExampleException.withMessage(
"The stringArrayProperty should be empty, but it is %s.", Arrays.toString(strList)));
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] { "A", "B", "C" });
ExampleException e = assertThrows(ExampleException.class, () -> validator.validate(command));
assertEquals("The stringArrayProperty should be empty, but it is [A, B, C].", e.getMessage());
}
// ================================
// #endregion - isEmpty
// ================================
// ================================
// #region - allMatch
// ================================
static boolean checkStringLength(String str, int min, int max) {
return str != null && (str.length() >= min && str.length() <= max);
}
@Test
void allMatch_validInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.allMatch(str -> checkStringLength(str, 4, 6))
.allMatch(str -> checkStringLength(str, 4, 6),
"String length must in the interval [4,6].")
.allMatch(str -> checkStringLength(str, 4, 6),
() -> ExampleException.withMessage("String length must in the interval [4,6]."))
.allMatch(str -> checkStringLength(str, 4, 6),
str -> ExampleException.withMessage("Validation failed: '%s'.", str));
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] { "1234", "12345", "123456" });
assertDoesNotThrow(() -> validator.validate(command));
}
@Test
void allMatch_default_invalidInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.allMatch(str -> checkStringLength(str, 4, 6));
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] { null, "1234", "12345", "123456" });
ValidationException e = assertThrows(ValidationException.class, () -> validator.validate(command));
assertEquals("All elements must match the condition.", e.getMessage());
}
@Test
void allMatch_specifiedMessage_invalidInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.allMatch(str -> checkStringLength(str, 4, 6),
"String length must in the interval [4,6].");
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] { "1234", "", "12345", "123456" });
ValidationException e = assertThrows(ValidationException.class, () -> validator.validate(command));
assertEquals("String length must in the interval [4,6].", e.getMessage());
}
@Test
void allMatch_specifiedExceptionSupplier_invalidInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.allMatch(str -> checkStringLength(str, 4, 6),
() -> ExampleException.withMessage("String length must in the interval [4,6]."));
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] { "1234", "12345", "123", "123456" });
ExampleException e = assertThrows(ExampleException.class, () -> validator.validate(command));
assertEquals("String length must in the interval [4,6].", e.getMessage());
}
@Test
void allMatch_specifiedExceptionFunction_invalidInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.allMatch(str -> checkStringLength(str, 4, 6),
str -> ExampleException.withMessage("Validation failed: '%s'.", str));
}
};
ExampleCommand command = exampleCommandWithStringArrayProperty(new String[] { "1234", "12345", "123456", "1234567" });
ExampleException e = assertThrows(ExampleException.class, () -> validator.validate(command));
assertEquals("Validation failed: '1234567'.", e.getMessage());
}
// ================================
// #endregion - allMatch
// ================================
// ================================
// #region - length
// ================================
private static final int MIN_LENGTH = 6;
private static final int MAX_LENGTH = 8;
@Test
void length_specifiedLength_validLength() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, "The length of the array must be 6")
.length(MIN_LENGTH, () -> ExampleException.withMessage("The length of the array must be 6"))
.length(MIN_LENGTH, arr -> ExampleException.withMessage("The length of the array must be 6, but it was %d", arr.length));
}
};
ExampleCommand validCommand = exampleCommandWithStringArrayProperty(6);
assertDoesNotThrow(() -> validator.validate(validCommand));
ExampleCommand commandWithNullStringProperty = exampleCommandWithStringArrayProperty(null);
assertDoesNotThrow(() -> validator.validate(commandWithNullStringProperty));
}
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2, 3, 4, 5, 7, 8, 9, 10 })
void length_specifiedLength_invalidLength(int length) {
ExampleCommand command = exampleCommandWithStringArrayProperty(length);
IValidator<ExampleCommand> ruleWithMessage = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, "The length of the array must be 6");
}
};
ValidationException eWithSpecifiedMessage = assertThrows(
ValidationException.class,
() -> ruleWithMessage.validate(command));
assertEquals("The length of the array must be 6", eWithSpecifiedMessage.getMessage());
IValidator<ExampleCommand> ruleWithExceptionSupplier = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, () -> ExampleException.withMessage("The length of the array must be 6"));
}
};
ExampleException specifiedException = assertThrows(
ExampleException.class,
() -> ruleWithExceptionSupplier.validate(command));
assertEquals("The length of the array must be 6", specifiedException.getMessage());
IValidator<ExampleCommand> ruleWithExceptionFunction = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, arr -> ExampleException.withMessage("The length of the array must be 6, but it was %d", arr.length));
}
};
ExampleException specifiedException2 = assertThrows(
ExampleException.class,
() -> ruleWithExceptionFunction.validate(command));
assertEquals(
String.format("The length of the array must be 6, but it was %d", length),
specifiedException2.getMessage());
}
@ParameterizedTest
@ValueSource(ints = { 6, 7, 8 })
void length_specifiedMinLengthAndMaxLength_validLength(int length) {
ExampleCommand command = exampleCommandWithStringArrayProperty(length);
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, MAX_LENGTH, String.format("Min length is %d, max length is %d", MIN_LENGTH, MAX_LENGTH))
.length(MIN_LENGTH, MAX_LENGTH, () -> ExampleException.withMessage("Min length is %d, max length is %d", MIN_LENGTH, MAX_LENGTH))
.length(MIN_LENGTH, MAX_LENGTH, arr -> ExampleException.withMessage("Length of stringArrayProperty is %d, min length is %d, max length is %d", arr.length, MIN_LENGTH, MAX_LENGTH));
}
};
assertDoesNotThrow(() -> validator.validate(command));
}
@Test
void length_specifiedMinLengthAndMaxLength_null() {
ExampleCommand command = exampleCommandWithStringArrayProperty(null);
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, MAX_LENGTH, String.format("Min length is %d, max length is %d", MIN_LENGTH, MAX_LENGTH))
.length(MIN_LENGTH, MAX_LENGTH, () -> ExampleException.withMessage("Min length is %d, max length is %d", MIN_LENGTH, MAX_LENGTH))
.length(MIN_LENGTH, MAX_LENGTH, arr -> ExampleException.withMessage("Length of stringArrayProperty is %d, min length is %d, max length is %d", arr.length, MIN_LENGTH, MAX_LENGTH));
}
};
assertDoesNotThrow(() -> validator.validate(command));
}
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2, 3, 4, 5, 9, 10, 11, 12 })
void length_specifiedMinLengthAndMaxLength_invalidLength(int length) {
ExampleCommand command = exampleCommandWithStringArrayProperty(length);
IValidator<ExampleCommand> ruleWithMessage = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, MAX_LENGTH, String.format("Min length is %d, max length is %d", MIN_LENGTH, MAX_LENGTH));
}
};
ValidationException eWithSpecifiedMessage = assertThrows(
ValidationException.class,
() -> ruleWithMessage.validate(command));
assertEquals("Min length is 6, max length is 8", eWithSpecifiedMessage.getMessage());
IValidator<ExampleCommand> ruleWithExceptionSupplier = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, MAX_LENGTH, () -> ExampleException.withMessage("Min length is %d, max length is %d", MIN_LENGTH, MAX_LENGTH));
}
};
ExampleException specifiedException = assertThrows(
ExampleException.class,
() -> ruleWithExceptionSupplier.validate(command));
assertEquals("Min length is 6, max length is 8", specifiedException.getMessage());
IValidator<ExampleCommand> ruleWithExceptionFunction = new BaseValidator<ExampleCommand>() {
{
ruleForArray(ExampleCommand::getStringArrayProperty)
.length(MIN_LENGTH, MAX_LENGTH, arr -> ExampleException.withMessage("Length of stringArrayProperty is %d, min length is %d, max length is %d", arr.length, MIN_LENGTH, MAX_LENGTH));
}
};
ExampleException specifiedException2 = assertThrows(
ExampleException.class,
() -> ruleWithExceptionFunction.validate(command));
assertEquals(
String.format("Length of stringArrayProperty is %d, min length is %d, max length is %d", length, MIN_LENGTH, MAX_LENGTH),
specifiedException2.getMessage());
}
// ================================
// #endregion - length
// ================================
static ExampleCommand exampleCommandWithStringArrayProperty(String[] property) {
ExampleCommand exampleCommand = new ExampleCommand();
exampleCommand.setStringArrayProperty(property);
return exampleCommand;
}
static ExampleCommand exampleCommandWithStringArrayProperty(int specifiedLength) {
ExampleCommand exampleCommand = new ExampleCommand();
String[] arr = new String[specifiedLength];
Arrays.fill(arr, "a");
exampleCommand.setStringArrayProperty(arr);
return exampleCommand;
}
}

View File

@ -20,10 +20,13 @@ import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import com.google.common.collect.Lists;
@ -271,9 +274,247 @@ public class CollectionPropertyValidatorTests {
// #endregion - isEmpty
// ================================
// ================================
// #region - allMatch
// ================================
static boolean checkStringLength(String str, int min, int max) {
return str != null && (str.length() >= min && str.length() <= max);
}
@Test
void allMatch_validInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.allMatch(str -> checkStringLength(str, 4, 6))
.allMatch(str -> checkStringLength(str, 4, 6),
"String length must in the interval [4,6].")
.allMatch(str -> checkStringLength(str, 4, 6),
() -> ExampleException.withMessage("String length must in the interval [4,6]."))
.allMatch(str -> checkStringLength(str, 4, 6),
str -> ExampleException.withMessage("Validation failed: '%s'.", str));
}
};
ExampleCommand command = exampleCommandWithStringListProperty(Lists.newArrayList("1234", "12345", "123456"));
assertDoesNotThrow(() -> validator.validate(command));
}
@Test
void allMatch_default_invalidInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.allMatch(str -> checkStringLength(str, 4, 6));
}
};
ExampleCommand command = exampleCommandWithStringListProperty(Lists.newArrayList(null, "1234", "12345", "123456"));
ValidationException e = assertThrows(ValidationException.class, () -> validator.validate(command));
assertEquals("All elements must match the condition.", e.getMessage());
}
@Test
void allMatch_specifiedMessage_invalidInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.allMatch(str -> checkStringLength(str, 4, 6),
"String length must in the interval [4,6].");
}
};
ExampleCommand command = exampleCommandWithStringListProperty(Lists.newArrayList("1234", "", "12345", "123456"));
ValidationException e = assertThrows(ValidationException.class, () -> validator.validate(command));
assertEquals("String length must in the interval [4,6].", e.getMessage());
}
@Test
void allMatch_specifiedExceptionSupplier_invalidInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.allMatch(str -> checkStringLength(str, 4, 6),
() -> ExampleException.withMessage("String length must in the interval [4,6]."));
}
};
ExampleCommand command = exampleCommandWithStringListProperty(Lists.newArrayList("1234", "12345", "123", "123456"));
ExampleException e = assertThrows(ExampleException.class, () -> validator.validate(command));
assertEquals("String length must in the interval [4,6].", e.getMessage());
}
@Test
void allMatch_specifiedExceptionFunction_invalidInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.allMatch(str -> checkStringLength(str, 4, 6),
str -> ExampleException.withMessage("Validation failed: '%s'.", str));
}
};
ExampleCommand command = exampleCommandWithStringListProperty(Lists.newArrayList("1234", "12345", "123456", "1234567"));
ExampleException e = assertThrows(ExampleException.class, () -> validator.validate(command));
assertEquals("Validation failed: '1234567'.", e.getMessage());
}
// ================================
// #endregion - allMatch
// ================================
// ================================
// #region - size
// ================================
private static final int MIN_SIZE = 6;
private static final int MAX_SIZE = 8;
@Test
void size_specifiedSize_validSize() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, "The size of the collection must be 6")
.size(MIN_SIZE, () -> ExampleException.withMessage("The size of the collection must be 6"))
.size(MIN_SIZE, c -> ExampleException.withMessage("The size of the collection must be 6, but it was %d", c.size()));
}
};
ExampleCommand validCommand = exampleCommandWithStringListProperty(6);
assertDoesNotThrow(() -> validator.validate(validCommand));
ExampleCommand commandWithNullStringProperty = exampleCommandWithStringListProperty(null);
assertDoesNotThrow(() -> validator.validate(commandWithNullStringProperty));
}
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2, 3, 4, 5, 7, 8, 9, 10 })
void size_specifiedSize_invalidSize(int size) {
ExampleCommand command = exampleCommandWithStringListProperty(size);
IValidator<ExampleCommand> ruleWithMessage = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, "The size of the collection must be 6");
}
};
ValidationException eWithSpecifiedMessage = assertThrows(
ValidationException.class,
() -> ruleWithMessage.validate(command));
assertEquals("The size of the collection must be 6", eWithSpecifiedMessage.getMessage());
IValidator<ExampleCommand> ruleWithExceptionSupplier = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, () -> ExampleException.withMessage("The size of the collection must be 6"));
}
};
ExampleException specifiedException = assertThrows(
ExampleException.class,
() -> ruleWithExceptionSupplier.validate(command));
assertEquals("The size of the collection must be 6", specifiedException.getMessage());
IValidator<ExampleCommand> ruleWithExceptionFunction = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, c -> ExampleException.withMessage("The size of the collection must be 6, but it was %d", c.size()));
}
};
ExampleException specifiedException2 = assertThrows(
ExampleException.class,
() -> ruleWithExceptionFunction.validate(command));
assertEquals(
String.format("The size of the collection must be 6, but it was %d", size),
specifiedException2.getMessage());
}
@ParameterizedTest
@ValueSource(ints = { 6, 7, 8 })
void size_specifiedMinSizeAndMaxSize_validSize(int size) {
ExampleCommand command = exampleCommandWithStringListProperty(size);
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, MAX_SIZE, String.format("Min size is %d, max size is %d", MIN_SIZE, MAX_SIZE))
.size(MIN_SIZE, MAX_SIZE, () -> ExampleException.withMessage("Min size is %d, max size is %d", MIN_SIZE, MAX_SIZE))
.size(MIN_SIZE, MAX_SIZE, c -> ExampleException.withMessage("Size of stringCollectionProperty is %d, min size is %d, max size is %d", c.size(), MIN_SIZE, MAX_SIZE));
}
};
assertDoesNotThrow(() -> validator.validate(command));
}
@Test
void size_specifiedMinSizeAndMaxSize_null() {
ExampleCommand command = exampleCommandWithStringListProperty(null);
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, MAX_SIZE, String.format("Min size is %d, max size is %d", MIN_SIZE, MAX_SIZE))
.size(MIN_SIZE, MAX_SIZE, () -> ExampleException.withMessage("Min size is %d, max size is %d", MIN_SIZE, MAX_SIZE))
.size(MIN_SIZE, MAX_SIZE, c -> ExampleException.withMessage("Size of stringCollectionProperty is %d, min size is %d, max size is %d", c.size(), MIN_SIZE, MAX_SIZE));
}
};
assertDoesNotThrow(() -> validator.validate(command));
}
@ParameterizedTest
@ValueSource(ints = { 0, 1, 2, 3, 4, 5, 9, 10, 11, 12 })
void size_specifiedMinSizeAndMaxSize_invalidSize(int size) {
ExampleCommand command = exampleCommandWithStringListProperty(size);
IValidator<ExampleCommand> ruleWithMessage = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, MAX_SIZE, String.format("Min size is %d, max size is %d", MIN_SIZE, MAX_SIZE));
}
};
ValidationException eWithSpecifiedMessage = assertThrows(
ValidationException.class,
() -> ruleWithMessage.validate(command));
assertEquals("Min size is 6, max size is 8", eWithSpecifiedMessage.getMessage());
IValidator<ExampleCommand> ruleWithExceptionSupplier = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, MAX_SIZE, () -> ExampleException.withMessage("Min size is %d, max size is %d", MIN_SIZE, MAX_SIZE));
}
};
ExampleException specifiedException = assertThrows(
ExampleException.class,
() -> ruleWithExceptionSupplier.validate(command));
assertEquals("Min size is 6, max size is 8", specifiedException.getMessage());
IValidator<ExampleCommand> ruleWithExceptionFunction = new BaseValidator<ExampleCommand>() {
{
ruleForCollection(ExampleCommand::getStringListProperty)
.size(MIN_SIZE, MAX_SIZE, c -> ExampleException.withMessage("Size of stringCollectionProperty is %d, min size is %d, max size is %d", c.size(), MIN_SIZE, MAX_SIZE));
}
};
ExampleException specifiedException2 = assertThrows(
ExampleException.class,
() -> ruleWithExceptionFunction.validate(command));
assertEquals(
String.format("Size of stringCollectionProperty is %d, min size is %d, max size is %d", size, MIN_SIZE, MAX_SIZE),
specifiedException2.getMessage());
}
// ================================
// #endregion - size
// ================================
static ExampleCommand exampleCommandWithStringListProperty(List<String> property) {
ExampleCommand exampleCommand = new ExampleCommand();
exampleCommand.setStringListProperty(property);
return exampleCommand;
}
static ExampleCommand exampleCommandWithStringListProperty(int specifiedSize) {
ExampleCommand exampleCommand = new ExampleCommand();
String[] arr = new String[specifiedSize];
Arrays.fill(arr, "a");
exampleCommand.setStringListProperty(Arrays.asList(arr));
return exampleCommand;
}
}

View File

@ -21,6 +21,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Objects;
import org.junit.jupiter.api.Test;
@ -62,6 +63,8 @@ public class ObjectPropertyValidatorTests {
.notNull(() -> ExampleException.withMessage("The objectProperty cannot be null"));
ruleFor(ExampleCommand::getStringListProperty)
.notNull(d -> ExampleException.withMessage("The stringListProperty cannot be null, but it was %s", d));
ruleFor(ExampleCommand::getStringArrayProperty)
.notNull(d -> ExampleException.withMessage("The stringListProperty cannot be null, but it was %s", Arrays.toString(d)));
}
};
ExampleCommand command = new ExampleCommand(
@ -72,7 +75,8 @@ public class ObjectPropertyValidatorTests {
"StringValue",
LocalDateTime.now().plusDays(1),
new Foo(Integer.MAX_VALUE, "StringValue"),
Lists.newArrayList("ABC", "DEF"));
Lists.newArrayList("ABC", "DEF"),
new String[] { "ABC", "DEF" });
assertDoesNotThrow(() -> validator.validate(command));
}
@ -150,6 +154,8 @@ public class ObjectPropertyValidatorTests {
.isNull(() -> ExampleException.withMessage("The objectProperty should be null"));
ruleFor(ExampleCommand::getStringListProperty)
.isNull(d -> ExampleException.withMessage("The stringListProperty should be null, but it was %s", d));
ruleFor(ExampleCommand::getStringArrayProperty)
.isNull(d -> ExampleException.withMessage("The stringListProperty should be null, but it was %s", Arrays.toString(d)));
}
};
ExampleCommand command = new ExampleCommand();
@ -225,8 +231,11 @@ public class ObjectPropertyValidatorTests {
}
};
ExampleCommand command = new ExampleCommand();
command.setStringProperty("Foo");
command.setStringProperty(null);
assertDoesNotThrow(() -> validator.validate(command));
command.setStringProperty("Foo");
assertDoesNotThrow(() -> validator.validate(command));
}
@ -275,52 +284,83 @@ public class ObjectPropertyValidatorTests {
assertEquals("The stringProperty should be equal to 'Foo', but is was 'Bar'.", specifiedException2.getMessage());
}
// ================================
// #endregion - equalTo
// ================================
// ================================
// #region - notEqual
// ================================
@Test
void equalTo_nullInput() {
void notEqual_validInput() {
IValidator<ExampleCommand> validator = new BaseValidator<ExampleCommand>() {
{
ruleForString(ExampleCommand::getStringProperty)
.notEqual("Foo")
.notEqual("Foo", "The stringProperty should not equal 'Foo'.")
.notEqual("Foo", () ->
ExampleException.withMessage("The stringProperty should not equal 'Foo'."))
.notEqual("Foo", str ->
ExampleException.withMessage("The stringProperty should not equal 'Foo', but is was '%s'.", str));
}
};
ExampleCommand command = new ExampleCommand();
command.setStringProperty(null);
assertDoesNotThrow(() -> validator.validate(command));
command.setStringProperty("Bar");
assertDoesNotThrow(() -> validator.validate(command));
}
@Test
void notEqual_invalidInput() {
ExampleCommand command = new ExampleCommand();
command.setStringProperty("Foo");
IValidator<ExampleCommand> defaultRule = new BaseValidator<ExampleCommand>() {
{
ruleForString(ExampleCommand::getStringProperty).equalTo("Foo");
ruleForString(ExampleCommand::getStringProperty).notEqual("Foo");
}
};
ValidationException eWithDefaultMessage = assertThrows(
ValidationException.class, () -> defaultRule.validate(command));
assertEquals("The input must be equal to 'Foo'.", eWithDefaultMessage.getMessage());
assertEquals("The input must not equal 'Foo'.", eWithDefaultMessage.getMessage());
IValidator<ExampleCommand> ruleWithMessage = new BaseValidator<ExampleCommand>() {
{
ruleForString(ExampleCommand::getStringProperty).equalTo("Foo",
"The stringProperty should be equal to 'Foo'.");
ruleForString(ExampleCommand::getStringProperty).notEqual("Foo",
"The stringProperty should not equal 'Foo'.");
}
};
ValidationException eWithSpecifiedMessage = assertThrows(
ValidationException.class, () -> ruleWithMessage.validate(command));
assertEquals("The stringProperty should be equal to 'Foo'.", eWithSpecifiedMessage.getMessage());
assertEquals("The stringProperty should not equal 'Foo'.", eWithSpecifiedMessage.getMessage());
IValidator<ExampleCommand> ruleWithExceptionSupplier = new BaseValidator<ExampleCommand>() {
{
ruleForString(ExampleCommand::getStringProperty).equalTo("Foo",
() -> ExampleException.withMessage("The stringProperty should be equal to 'Foo'."));
ruleForString(ExampleCommand::getStringProperty).notEqual("Foo",
() -> ExampleException.withMessage("The stringProperty should not equal 'Foo'."));
}
};
ExampleException specifiedException = assertThrows(
ExampleException.class, () -> ruleWithExceptionSupplier.validate(command));
assertEquals("The stringProperty should be equal to 'Foo'.", specifiedException.getMessage());
assertEquals("The stringProperty should not equal 'Foo'.", specifiedException.getMessage());
IValidator<ExampleCommand> ruleWithExceptionFunction = new BaseValidator<ExampleCommand>() {
{
ruleForString(ExampleCommand::getStringProperty).equalTo("Foo",
str -> ExampleException.withMessage("The stringProperty should be equal to 'Foo', but is was '%s'.", str));
ruleForString(ExampleCommand::getStringProperty).notEqual("Foo",
str -> ExampleException.withMessage("The stringProperty should not equal 'Foo', but is was '%s'.", str));
}
};
ExampleException specifiedException2 = assertThrows(
ExampleException.class, () -> ruleWithExceptionFunction.validate(command));
assertEquals("The stringProperty should be equal to 'Foo', but is was 'null'.", specifiedException2.getMessage());
assertEquals("The stringProperty should not equal 'Foo', but is was 'Foo'.", specifiedException2.getMessage());
}
// ================================
// #endregion - equalTo
// #endregion - notEqual
// ================================
// ================================