diff --git a/plusone-validator/src/main/java/xyz/zhouxy/plusone/validator/ArrayPropertyValidator.java b/plusone-validator/src/main/java/xyz/zhouxy/plusone/validator/ArrayPropertyValidator.java index 32eab14..0e2720e 100644 --- a/plusone-validator/src/main/java/xyz/zhouxy/plusone/validator/ArrayPropertyValidator.java +++ b/plusone-validator/src/main/java/xyz/zhouxy/plusone/validator/ArrayPropertyValidator.java @@ -21,6 +21,7 @@ import java.util.function.Predicate; import java.util.function.Supplier; import xyz.zhouxy.plusone.commons.util.ArrayTools; +import xyz.zhouxy.plusone.commons.util.AssertTools; /** * 针对数组类型的属性校验器 @@ -81,8 +82,7 @@ public class ArrayPropertyValidator */ public ArrayPropertyValidator notEmpty( Function e) { - withRule(ArrayTools::isNotEmpty, e); - return this; + return withRule(ArrayTools::isNotEmpty, e); } // ================================ @@ -131,8 +131,7 @@ public class ArrayPropertyValidator */ public ArrayPropertyValidator isEmpty( Function e) { - withRule(ArrayTools::isEmpty, e); - return this; + return withRule(ArrayTools::isEmpty, e); } // ================================ @@ -185,20 +184,114 @@ public class ArrayPropertyValidator */ public ArrayPropertyValidator allMatch( Predicate condition, Function e) { - withRule(c -> { + return withRule(c -> { for (TElement element : c) { if (!condition.test(element)) { throw e.apply(element); } } }); - return this; } // ================================ // #endregion - allMatch // ================================ + // ================================ + // #region - length + // ================================ + + /** + * 添加一条校验属性的规则,校验属性长度是否等于指定长度 + * + * @param length 指定长度 + * @param errMsg 异常信息 + * @return 属性校验器 + */ + public ArrayPropertyValidator length(int length, String errMsg) { + return length(length, convertToExceptionFunction(errMsg)); + } + + /** + * 添加一条校验属性的规则,校验属性长度是否等于指定长度 + * + * @param 异常类型 + * @param length 指定长度 + * @param e 自定义异常 + * @return 属性校验器 + */ + public ArrayPropertyValidator length( + int length, Supplier e) { + return length(length, convertToExceptionFunction(e)); + } + + /** + * 添加一条校验属性的规则,校验属性长度是否等于指定长度 + * + * @param 异常类型 + * @param length 指定长度 + * @param e 自定义异常 + * @return 属性校验器 + */ + public ArrayPropertyValidator length( + int length, Function 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 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 length(int min, int max, String errMsg) { + return length(min, max, convertToExceptionFunction(errMsg)); + } + + /** + * 添加一条校验属性的规则,校验属性的长度范围 + * + * @param min 最小长度 + * @param max 最大长度 + * @param e 自定义异常 + * @return 属性校验器 + */ + public ArrayPropertyValidator length( + int min, int max, Supplier e) { + return length(min, max, convertToExceptionFunction(e)); + } + + /** + * 添加一条校验属性的规则,校验属性的长度范围 + * + * @param min 最小长度 + * @param max 最大长度 + * @param e 自定义异常 + * @return 属性校验器 + */ + public ArrayPropertyValidator length( + int min, int max, Function 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 thisObject() { return this; diff --git a/plusone-validator/src/main/java/xyz/zhouxy/plusone/validator/CollectionPropertyValidator.java b/plusone-validator/src/main/java/xyz/zhouxy/plusone/validator/CollectionPropertyValidator.java index 726afd6..6f5ee05 100644 --- a/plusone-validator/src/main/java/xyz/zhouxy/plusone/validator/CollectionPropertyValidator.java +++ b/plusone-validator/src/main/java/xyz/zhouxy/plusone/validator/CollectionPropertyValidator.java @@ -22,6 +22,7 @@ import java.util.function.Predicate; import java.util.function.Supplier; import xyz.zhouxy.plusone.commons.collection.CollectionTools; +import xyz.zhouxy.plusone.commons.util.AssertTools; /** * 针对集合类型的属性校验器 @@ -82,8 +83,7 @@ public class CollectionPropertyValidator */ public CollectionPropertyValidator notEmpty( Function, E> e) { - withRule(CollectionTools::isNotEmpty, e); - return this; + return withRule(CollectionTools::isNotEmpty, e); } // ================================ @@ -132,8 +132,7 @@ public class CollectionPropertyValidator */ public CollectionPropertyValidator isEmpty( Function, E> e) { - withRule(CollectionTools::isEmpty, e); - return this; + return withRule(CollectionTools::isEmpty, e); } // ================================ @@ -186,18 +185,112 @@ public class CollectionPropertyValidator */ public CollectionPropertyValidator allMatch( Predicate condition, Function e) { - withRule(c -> c.forEach(element -> { + return withRule(c -> c.forEach(element -> { if (!condition.test(element)) { throw e.apply(element); } })); - return this; } // ================================ // #endregion - allMatch // ================================ + // ================================ + // #region - size + // ================================ + + /** + * 添加一条校验属性的规则,校验属性大小是否等于指定大小 + * + * @param size 指定大小 + * @param errMsg 异常信息 + * @return 属性校验器 + */ + public CollectionPropertyValidator size(int size, String errMsg) { + return size(size, convertToExceptionFunction(errMsg)); + } + + /** + * 添加一条校验属性的规则,校验属性大小是否等于指定大小 + * + * @param 异常类型 + * @param size 指定大小 + * @param e 自定义异常 + * @return 属性校验器 + */ + public CollectionPropertyValidator size( + int size, Supplier e) { + return size(size, convertToExceptionFunction(e)); + } + + /** + * 添加一条校验属性的规则,校验属性大小是否等于指定大小 + * + * @param 异常类型 + * @param size 指定大小 + * @param e 自定义异常 + * @return 属性校验器 + */ + public CollectionPropertyValidator size( + int size, Function, 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 boolean checkSize(Collection 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 size(int min, int max, String errMsg) { + return size(min, max, convertToExceptionFunction(errMsg)); + } + + /** + * 添加一条校验属性的规则,校验属性的大小范围 + * + * @param min 最小大小 + * @param max 最大大小 + * @param e 自定义异常 + * @return 属性校验器 + */ + public CollectionPropertyValidator size( + int min, int max, Supplier e) { + return size(min, max, convertToExceptionFunction(e)); + } + + /** + * 添加一条校验属性的规则,校验属性的大小范围 + * + * @param min 最小大小 + * @param max 最大大小 + * @param e 自定义异常 + * @return 属性校验器 + */ + public CollectionPropertyValidator size( + int min, int max, Function, 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 thisObject() { return this; diff --git a/plusone-validator/src/test/java/xyz/zhouxy/plusone/example/validator/ArrayPropertyValidatorTests.java b/plusone-validator/src/test/java/xyz/zhouxy/plusone/example/validator/ArrayPropertyValidatorTests.java index f131b3f..99840fe 100644 --- a/plusone-validator/src/test/java/xyz/zhouxy/plusone/example/validator/ArrayPropertyValidatorTests.java +++ b/plusone-validator/src/test/java/xyz/zhouxy/plusone/example/validator/ArrayPropertyValidatorTests.java @@ -22,6 +22,8 @@ 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; @@ -358,9 +360,157 @@ public class ArrayPropertyValidatorTests { // #endregion - allMatch // ================================ + // ================================ + // #region - length + // ================================ + + private static final int MIN_LENGTH = 6; + private static final int MAX_LENGTH = 8; + + @Test + void length_specifiedLength_validLength() { + IValidator validator = new BaseValidator() { + { + 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 ruleWithMessage = new BaseValidator() { + { + 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 ruleWithExceptionSupplier = new BaseValidator() { + { + 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 ruleWithExceptionFunction = new BaseValidator() { + { + 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 validator = new BaseValidator() { + { + 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 validator = new BaseValidator() { + { + 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 ruleWithMessage = new BaseValidator() { + { + 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 ruleWithExceptionSupplier = new BaseValidator() { + { + 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 ruleWithExceptionFunction = new BaseValidator() { + { + 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; + } } diff --git a/plusone-validator/src/test/java/xyz/zhouxy/plusone/example/validator/CollectionPropertyValidatorTests.java b/plusone-validator/src/test/java/xyz/zhouxy/plusone/example/validator/CollectionPropertyValidatorTests.java index 54584be..01b43e6 100644 --- a/plusone-validator/src/test/java/xyz/zhouxy/plusone/example/validator/CollectionPropertyValidatorTests.java +++ b/plusone-validator/src/test/java/xyz/zhouxy/plusone/example/validator/CollectionPropertyValidatorTests.java @@ -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; @@ -362,9 +365,156 @@ public class CollectionPropertyValidatorTests { // #endregion - allMatch // ================================ + // ================================ + // #region - size + // ================================ + + private static final int MIN_SIZE = 6; + private static final int MAX_SIZE = 8; + + @Test + void size_specifiedSize_validSize() { + IValidator validator = new BaseValidator() { + { + 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 ruleWithMessage = new BaseValidator() { + { + 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 ruleWithExceptionSupplier = new BaseValidator() { + { + 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 ruleWithExceptionFunction = new BaseValidator() { + { + 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 validator = new BaseValidator() { + { + 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 validator = new BaseValidator() { + { + 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 ruleWithMessage = new BaseValidator() { + { + 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 ruleWithExceptionSupplier = new BaseValidator() { + { + 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 ruleWithExceptionFunction = new BaseValidator() { + { + 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 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; + } }