Compare commits

...

5 Commits

Author SHA1 Message Date
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 1296 additions and 58 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( protected final <E extends RuntimeException> TPropertyValidator withRule(
Predicate<? super TProperty> rule, Function<TProperty, E> e) { Predicate<? super TProperty> rule, Function<TProperty, E> e) {
this.consumers.add(v -> { return withRule(v -> {
if (!rule.test(v)) { if (!rule.test(v)) {
throw e.apply(v); throw e.apply(v);
} }
}); });
}
/**
* 添加一条校验属性的规则
*
* @param rule 校验规则
* @param e 自定义异常
* @return 属性校验器
*/
protected final TPropertyValidator withRule(Consumer<? super TProperty> rule) {
this.consumers.add(rule);
return thisObject(); return thisObject();
} }

View File

@@ -247,6 +247,18 @@ public abstract class BaseValidator<T> implements IValidator<T> {
return validator; 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> 第一个元素的类型 * @param <V1> 第一个元素的类型

View File

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

View File

@@ -18,15 +18,17 @@ package xyz.zhouxy.plusone.validator;
import java.util.Collection; import java.util.Collection;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier; import java.util.function.Supplier;
import xyz.zhouxy.plusone.commons.collection.CollectionTools; import xyz.zhouxy.plusone.commons.collection.CollectionTools;
import xyz.zhouxy.plusone.commons.util.AssertTools;
/** /**
* 针对集合类型的属性校验器 * 针对集合类型的属性校验器
* *
* <p> * <p>
* 内置判断集合是否为空的校验规则。 * 内置集合相关的校验规则。
* *
* @author ZhouXY * @author ZhouXY
*/ */
@@ -37,7 +39,9 @@ public class CollectionPropertyValidator<T, TElement>
super(getter); super(getter);
} }
// ====== notEmpty ===== // ================================
// #region - notEmpty
// ================================
/** /**
* 添加一条校验属性的规则,校验属性是否非空 * 添加一条校验属性的规则,校验属性是否非空
@@ -79,11 +83,16 @@ public class CollectionPropertyValidator<T, TElement>
*/ */
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> notEmpty( public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> notEmpty(
Function<Collection<TElement>, E> e) { Function<Collection<TElement>, E> e) {
withRule(CollectionTools::isNotEmpty, e); return withRule(CollectionTools::isNotEmpty, e);
return this;
} }
// ====== isEmpty ===== // ================================
// #endregion - notEmpty
// ================================
// ================================
// #region - isEmpty
// ================================
/** /**
* 添加一条校验属性的规则,校验属性是否为空 * 添加一条校验属性的规则,校验属性是否为空
@@ -123,10 +132,165 @@ public class CollectionPropertyValidator<T, TElement>
*/ */
public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> isEmpty( public <E extends RuntimeException> CollectionPropertyValidator<T, TElement> isEmpty(
Function<Collection<TElement>, E> e) { Function<Collection<TElement>, E> e) {
withRule(CollectionTools::isEmpty, e); return withRule(CollectionTools::isEmpty, e);
return this;
} }
// ================================
// #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 @Override
protected CollectionPropertyValidator<T, TElement> thisObject() { protected CollectionPropertyValidator<T, TElement> thisObject() {
return this; return this;

View File

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

View File

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

View File

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

View File

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

View File

@@ -16,6 +16,7 @@
package xyz.zhouxy.plusone.example; package xyz.zhouxy.plusone.example;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List; import java.util.List;
/** /**
@@ -30,13 +31,14 @@ public class ExampleCommand {
private LocalDateTime dateTimeProperty; private LocalDateTime dateTimeProperty;
private Foo objectProperty; private Foo objectProperty;
private List<String> stringListProperty; private List<String> stringListProperty;
private String[] stringArrayProperty;
public ExampleCommand() { public ExampleCommand() {
} }
public ExampleCommand(Boolean boolProperty, Integer intProperty, Long longProperty, Double doubleProperty, public ExampleCommand(Boolean boolProperty, Integer intProperty, Long longProperty, Double doubleProperty,
String stringProperty, LocalDateTime dateTimeProperty, Foo objectProperty, String stringProperty, LocalDateTime dateTimeProperty, Foo objectProperty,
List<String> stringListProperty) { List<String> stringListProperty, String[] stringArrayProperty) {
this.boolProperty = boolProperty; this.boolProperty = boolProperty;
this.intProperty = intProperty; this.intProperty = intProperty;
this.longProperty = longProperty; this.longProperty = longProperty;
@@ -45,6 +47,7 @@ public class ExampleCommand {
this.dateTimeProperty = dateTimeProperty; this.dateTimeProperty = dateTimeProperty;
this.objectProperty = objectProperty; this.objectProperty = objectProperty;
this.stringListProperty = stringListProperty; this.stringListProperty = stringListProperty;
this.stringArrayProperty = stringArrayProperty;
} }
public Boolean getBoolProperty() { public Boolean getBoolProperty() {
@@ -111,11 +114,20 @@ public class ExampleCommand {
this.stringListProperty = stringListProperty; this.stringListProperty = stringListProperty;
} }
public String[] getStringArrayProperty() {
return stringArrayProperty;
}
public void setStringArrayProperty(String[] stringArrayProperty) {
this.stringArrayProperty = stringArrayProperty;
}
@Override @Override
public String toString() { public String toString() {
return "ExampleCommand [boolProperty=" + boolProperty + ", intProperty=" + intProperty + ", longProperty=" return "ExampleCommand [boolProperty=" + boolProperty + ", intProperty=" + intProperty + ", longProperty="
+ longProperty + ", doubleProperty=" + doubleProperty + ", stringProperty=" + stringProperty + longProperty + ", doubleProperty=" + doubleProperty + ", stringProperty=" + stringProperty
+ ", dateTimeProperty=" + dateTimeProperty + ", objectProperty=" + objectProperty + ", 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.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertThrows;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.junit.jupiter.api.Test; 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; import com.google.common.collect.Lists;
@@ -271,9 +274,247 @@ public class CollectionPropertyValidatorTests {
// #endregion - isEmpty // #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) { static ExampleCommand exampleCommandWithStringListProperty(List<String> property) {
ExampleCommand exampleCommand = new ExampleCommand(); ExampleCommand exampleCommand = new ExampleCommand();
exampleCommand.setStringListProperty(property); exampleCommand.setStringListProperty(property);
return exampleCommand; 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 static org.junit.jupiter.api.Assertions.assertThrows;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Objects; import java.util.Objects;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
@@ -62,6 +63,8 @@ public class ObjectPropertyValidatorTests {
.notNull(() -> ExampleException.withMessage("The objectProperty cannot be null")); .notNull(() -> ExampleException.withMessage("The objectProperty cannot be null"));
ruleFor(ExampleCommand::getStringListProperty) ruleFor(ExampleCommand::getStringListProperty)
.notNull(d -> ExampleException.withMessage("The stringListProperty cannot be null, but it was %s", d)); .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( ExampleCommand command = new ExampleCommand(
@@ -72,7 +75,8 @@ public class ObjectPropertyValidatorTests {
"StringValue", "StringValue",
LocalDateTime.now().plusDays(1), LocalDateTime.now().plusDays(1),
new Foo(Integer.MAX_VALUE, "StringValue"), new Foo(Integer.MAX_VALUE, "StringValue"),
Lists.newArrayList("ABC", "DEF")); Lists.newArrayList("ABC", "DEF"),
new String[] { "ABC", "DEF" });
assertDoesNotThrow(() -> validator.validate(command)); assertDoesNotThrow(() -> validator.validate(command));
} }
@@ -150,6 +154,8 @@ public class ObjectPropertyValidatorTests {
.isNull(() -> ExampleException.withMessage("The objectProperty should be null")); .isNull(() -> ExampleException.withMessage("The objectProperty should be null"));
ruleFor(ExampleCommand::getStringListProperty) ruleFor(ExampleCommand::getStringListProperty)
.isNull(d -> ExampleException.withMessage("The stringListProperty should be null, but it was %s", d)); .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(); ExampleCommand command = new ExampleCommand();