diff --git a/hutool-core/src/main/java/cn/hutool/v7/core/lang/Validator.java b/hutool-core/src/main/java/cn/hutool/v7/core/lang/Validator.java index 17e0828cc..198e61f1e 100644 --- a/hutool-core/src/main/java/cn/hutool/v7/core/lang/Validator.java +++ b/hutool-core/src/main/java/cn/hutool/v7/core/lang/Validator.java @@ -28,6 +28,7 @@ import cn.hutool.v7.core.text.StrUtil; import cn.hutool.v7.core.util.CharsetUtil; import cn.hutool.v7.core.util.ObjUtil; +import java.math.BigDecimal; import java.net.MalformedURLException; import java.nio.charset.Charset; import java.util.Date; @@ -1052,8 +1053,13 @@ public class Validator { Assert.notNull(value); Assert.notNull(min); Assert.notNull(max); - final double doubleValue = value.doubleValue(); - return (doubleValue >= min.doubleValue()) && (doubleValue <= max.doubleValue()); +// final double doubleValue = value.doubleValue(); +// return (doubleValue >= min.doubleValue()) && (doubleValue <= max.doubleValue()); + // 通过 NumberUtil 转换为 BigDecimal,使用 BigDecimal 进行比较以保留精度 + BigDecimal valBd = NumberUtil.toBigDecimal(value); + BigDecimal minBd = NumberUtil.toBigDecimal(min); + BigDecimal maxBd = NumberUtil.toBigDecimal(max); + return valBd.compareTo(minBd) >= 0 && valBd.compareTo(maxBd) <= 0; } /** diff --git a/hutool-core/src/test/java/cn/hutool/v7/core/lang/ValidatorTest.java b/hutool-core/src/test/java/cn/hutool/v7/core/lang/ValidatorTest.java index 16017f90a..ecb4b0ac7 100644 --- a/hutool-core/src/test/java/cn/hutool/v7/core/lang/ValidatorTest.java +++ b/hutool-core/src/test/java/cn/hutool/v7/core/lang/ValidatorTest.java @@ -27,6 +27,9 @@ import org.junit.jupiter.api.Test; import java.util.Date; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + /** * 验证器单元测试 * @@ -36,10 +39,10 @@ public class ValidatorTest { @Test public void isNumberTest() { - Assertions.assertTrue(Validator.isNumber("45345365465")); - Assertions.assertTrue(Validator.isNumber("0004545435")); - Assertions.assertTrue(Validator.isNumber("5.222")); - Assertions.assertTrue(Validator.isNumber("0.33323")); + assertTrue(Validator.isNumber("45345365465")); + assertTrue(Validator.isNumber("0004545435")); + assertTrue(Validator.isNumber("5.222")); + assertTrue(Validator.isNumber("0.33323")); } @Test @@ -48,74 +51,74 @@ public class ValidatorTest { final String var2 = "str"; final String var3 = "180"; final String var4 = "身高180体重180"; - Assertions.assertFalse(Validator.hasNumber(var1)); - Assertions.assertFalse(Validator.hasNumber(var2)); - Assertions.assertTrue(Validator.hasNumber(var3)); - Assertions.assertTrue(Validator.hasNumber(var4)); + assertFalse(Validator.hasNumber(var1)); + assertFalse(Validator.hasNumber(var2)); + assertTrue(Validator.hasNumber(var3)); + assertTrue(Validator.hasNumber(var4)); } @Test public void isLetterTest() { - Assertions.assertTrue(Validator.isLetter("asfdsdsfds")); - Assertions.assertTrue(Validator.isLetter("asfdsdfdsfVCDFDFGdsfds")); - Assertions.assertTrue(Validator.isLetter("asfdsdf你好dsfVCDFDFGdsfds")); + assertTrue(Validator.isLetter("asfdsdsfds")); + assertTrue(Validator.isLetter("asfdsdfdsfVCDFDFGdsfds")); + assertTrue(Validator.isLetter("asfdsdf你好dsfVCDFDFGdsfds")); } @Test public void isUperCaseTest() { - Assertions.assertTrue(Validator.isUpperCase("VCDFDFG")); - Assertions.assertTrue(Validator.isUpperCase("ASSFD")); + assertTrue(Validator.isUpperCase("VCDFDFG")); + assertTrue(Validator.isUpperCase("ASSFD")); - Assertions.assertFalse(Validator.isUpperCase("asfdsdsfds")); - Assertions.assertFalse(Validator.isUpperCase("ASSFD你好")); + assertFalse(Validator.isUpperCase("asfdsdsfds")); + assertFalse(Validator.isUpperCase("ASSFD你好")); } @Test public void isLowerCaseTest() { - Assertions.assertTrue(Validator.isLowerCase("asfdsdsfds")); + assertTrue(Validator.isLowerCase("asfdsdsfds")); - Assertions.assertFalse(Validator.isLowerCase("aaaa你好")); - Assertions.assertFalse(Validator.isLowerCase("VCDFDFG")); - Assertions.assertFalse(Validator.isLowerCase("ASSFD")); - Assertions.assertFalse(Validator.isLowerCase("ASSFD你好")); + assertFalse(Validator.isLowerCase("aaaa你好")); + assertFalse(Validator.isLowerCase("VCDFDFG")); + assertFalse(Validator.isLowerCase("ASSFD")); + assertFalse(Validator.isLowerCase("ASSFD你好")); } @Test public void isBirthdayTest() { final boolean b = Validator.isBirthday("20150101"); - Assertions.assertTrue(b); + assertTrue(b); final boolean b2 = Validator.isBirthday("2015-01-01"); - Assertions.assertTrue(b2); + assertTrue(b2); final boolean b3 = Validator.isBirthday("2015.01.01"); - Assertions.assertTrue(b3); + assertTrue(b3); final boolean b4 = Validator.isBirthday("2015年01月01日"); - Assertions.assertTrue(b4); + assertTrue(b4); final boolean b5 = Validator.isBirthday("2015.01.01"); - Assertions.assertTrue(b5); + assertTrue(b5); final boolean b6 = Validator.isBirthday("2018-08-15"); - Assertions.assertTrue(b6); + assertTrue(b6); //验证年非法 - Assertions.assertFalse(Validator.isBirthday("2095.05.01")); + assertFalse(Validator.isBirthday("2095.05.01")); //验证月非法 - Assertions.assertFalse(Validator.isBirthday("2015.13.01")); + assertFalse(Validator.isBirthday("2015.13.01")); //验证日非法 - Assertions.assertFalse(Validator.isBirthday("2015.02.29")); + assertFalse(Validator.isBirthday("2015.02.29")); } @Test public void isCitizenIdTest() { // 18为身份证号码验证 final boolean b = Validator.isCitizenId("110101199003074477"); - Assertions.assertTrue(b); + assertTrue(b); // 15位身份证号码验证 final boolean b1 = Validator.isCitizenId("410001910101123"); - Assertions.assertTrue(b1); + assertTrue(b1); // 10位身份证号码验证 final boolean b2 = Validator.isCitizenId("U193683453"); - Assertions.assertTrue(b2); + assertTrue(b2); } @Test @@ -126,145 +129,157 @@ public class ValidatorTest { @Test public void isEmailTest() { final boolean email = Validator.isEmail("abc_cde@163.com"); - Assertions.assertTrue(email); + assertTrue(email); final boolean email1 = Validator.isEmail("abc_%cde@163.com"); - Assertions.assertTrue(email1); + assertTrue(email1); final boolean email2 = Validator.isEmail("abc_%cde@aaa.c"); - Assertions.assertTrue(email2); + assertTrue(email2); final boolean email3 = Validator.isEmail("xiaolei.lu@aaa.b"); - Assertions.assertTrue(email3); + assertTrue(email3); final boolean email4 = Validator.isEmail("xiaolei.Lu@aaa.b"); - Assertions.assertTrue(email4); + assertTrue(email4); final boolean email5 = Validator.isEmail("luxiaolei_小磊@小磊.com"); - Assertions.assertTrue(email5); + assertTrue(email5); } @Test void issueI94YYUTest() { final boolean ret = PatternPool.EMAIL.matcher(StrUtil.repeat("hutool\\\"", 1000)).matches(); - Assertions.assertFalse(ret); + assertFalse(ret); } @Test public void isMobileTest() { final boolean m1 = Validator.isMobile("13900221432"); - Assertions.assertTrue(m1); + assertTrue(m1); final boolean m2 = Validator.isMobile("015100221432"); - Assertions.assertTrue(m2); + assertTrue(m2); final boolean m3 = Validator.isMobile("+8618600221432"); - Assertions.assertTrue(m3); + assertTrue(m3); final boolean m4 = Validator.isMobile("19312341234"); - Assertions.assertTrue(m4); + assertTrue(m4); } @Test public void isMatchTest() { String url = "http://aaa-bbb.somthing.com/a.php?a=b&c=2"; - Assertions.assertTrue(Validator.isMatchRegex(PatternPool.URL_HTTP, url)); + assertTrue(Validator.isMatchRegex(PatternPool.URL_HTTP, url)); url = "https://aaa-bbb.somthing.com/a.php?a=b&c=2"; - Assertions.assertTrue(Validator.isMatchRegex(PatternPool.URL_HTTP, url)); + assertTrue(Validator.isMatchRegex(PatternPool.URL_HTTP, url)); url = "https://aaa-bbb.somthing.com:8080/a.php?a=b&c=2"; - Assertions.assertTrue(Validator.isMatchRegex(PatternPool.URL_HTTP, url)); + assertTrue(Validator.isMatchRegex(PatternPool.URL_HTTP, url)); } @Test public void isGeneralTest() { String str = ""; boolean general = Validator.isGeneral(str, -1, 5); - Assertions.assertTrue(general); + assertTrue(general); str = "123_abc_ccc"; general = Validator.isGeneral(str, -1, 100); - Assertions.assertTrue(general); + assertTrue(general); // 不允许中文 str = "123_abc_ccc中文"; general = Validator.isGeneral(str, -1, 100); - Assertions.assertFalse(general); + assertFalse(general); } @Test public void isPlateNumberTest(){ - Assertions.assertTrue(Validator.isPlateNumber("粤BA03205")); - Assertions.assertTrue(Validator.isPlateNumber("闽20401领")); + assertTrue(Validator.isPlateNumber("粤BA03205")); + assertTrue(Validator.isPlateNumber("闽20401领")); } @Test public void isChineseTest(){ - Assertions.assertTrue(Validator.isChinese("全都是中文")); - Assertions.assertTrue(Validator.isChinese("㐓㐘")); - Assertions.assertFalse(Validator.isChinese("not全都是中文")); + assertTrue(Validator.isChinese("全都是中文")); + assertTrue(Validator.isChinese("㐓㐘")); + assertFalse(Validator.isChinese("not全都是中文")); } @Test public void hasChineseTest() { - Assertions.assertTrue(Validator.hasChinese("黄单桑米")); - Assertions.assertTrue(Validator.hasChinese("Kn 四兄弟")); - Assertions.assertTrue(Validator.hasChinese("\uD840\uDDA3")); - Assertions.assertFalse(Validator.hasChinese("Abc")); + assertTrue(Validator.hasChinese("黄单桑米")); + assertTrue(Validator.hasChinese("Kn 四兄弟")); + assertTrue(Validator.hasChinese("\uD840\uDDA3")); + assertFalse(Validator.hasChinese("Abc")); } @Test public void isUUIDTest(){ - Assertions.assertTrue(Validator.isUUID(IdUtil.randomUUID())); - Assertions.assertTrue(Validator.isUUID(IdUtil.fastSimpleUUID())); + assertTrue(Validator.isUUID(IdUtil.randomUUID())); + assertTrue(Validator.isUUID(IdUtil.fastSimpleUUID())); - Assertions.assertTrue(Validator.isUUID(IdUtil.randomUUID().toUpperCase())); - Assertions.assertTrue(Validator.isUUID(IdUtil.fastSimpleUUID().toUpperCase())); + assertTrue(Validator.isUUID(IdUtil.randomUUID().toUpperCase())); + assertTrue(Validator.isUUID(IdUtil.fastSimpleUUID().toUpperCase())); } @Test public void isZipCodeTest(){ // 港 boolean zipCode = Validator.isZipCode("999077"); - Assertions.assertTrue(zipCode); + assertTrue(zipCode); // 澳 zipCode = Validator.isZipCode("999078"); - Assertions.assertTrue(zipCode); + assertTrue(zipCode); // 台(2020年3月起改用6位邮编,3+3) zipCode = Validator.isZipCode("822001"); - Assertions.assertTrue(zipCode); + assertTrue(zipCode); // 内蒙 zipCode = Validator.isZipCode("016063"); - Assertions.assertTrue(zipCode); + assertTrue(zipCode); // 山西 zipCode = Validator.isZipCode("045246"); - Assertions.assertTrue(zipCode); + assertTrue(zipCode); // 河北 zipCode = Validator.isZipCode("066502"); - Assertions.assertTrue(zipCode); + assertTrue(zipCode); // 北京 zipCode = Validator.isZipCode("102629"); - Assertions.assertTrue(zipCode); + assertTrue(zipCode); } @Test public void isBetweenTest() { - Assertions.assertTrue(Validator.isBetween(0, 0, 1)); - Assertions.assertTrue(Validator.isBetween(1L, 0L, 1L)); - Assertions.assertTrue(Validator.isBetween(0.19f, 0.1f, 0.2f)); - Assertions.assertTrue(Validator.isBetween(0.19, 0.1, 0.2)); + assertTrue(Validator.isBetween(0, 0, 1)); + assertTrue(Validator.isBetween(1L, 0L, 1L)); + assertTrue(Validator.isBetween(0.19f, 0.1f, 0.2f)); + assertTrue(Validator.isBetween(0.19, 0.1, 0.2)); + } + + @Test + public void isBetweenPrecisionLossTest() { + // 使用超过 double 精度的值 + long base = 10000000000000000L; + long min = base + 1; + long max = base + 2; + + // 在 double 转换下,base、min 和 max 是完全相等的,因为 double 精度不够 + // 预期结果为false,但是因为double 精度不够,导致输出为true + assertFalse(Validator.isBetween(base, min, max)); } @Test public void isCarVinTest(){ - Assertions.assertTrue(Validator.isCarVin("LSJA24U62JG269225")); - Assertions.assertTrue(Validator.isCarVin("LDC613P23A1305189")); - Assertions.assertFalse(Validator.isCarVin("LOC613P23A1305189")); + assertTrue(Validator.isCarVin("LSJA24U62JG269225")); + assertTrue(Validator.isCarVin("LDC613P23A1305189")); + assertFalse(Validator.isCarVin("LOC613P23A1305189")); - Assertions.assertTrue(Validator.isCarVin("LSJA24U62JG269225")); //标准分类1 - Assertions.assertTrue(Validator.isCarVin("LDC613P23A1305189")); //标准分类1 - Assertions.assertTrue(Validator.isCarVin("LBV5S3102ESJ25655")); //标准分类1 - Assertions.assertTrue(Validator.isCarVin("LBV5S3102ESJPE655")); //标准分类2 - Assertions.assertFalse(Validator.isCarVin("LOC613P23A1305189")); //错误示例 + assertTrue(Validator.isCarVin("LSJA24U62JG269225")); //标准分类1 + assertTrue(Validator.isCarVin("LDC613P23A1305189")); //标准分类1 + assertTrue(Validator.isCarVin("LBV5S3102ESJ25655")); //标准分类1 + assertTrue(Validator.isCarVin("LBV5S3102ESJPE655")); //标准分类2 + assertFalse(Validator.isCarVin("LOC613P23A1305189")); //错误示例 } @Test public void isCarDrivingLicenceTest(){ - Assertions.assertTrue(Validator.isCarDrivingLicence("430101758218")); + assertTrue(Validator.isCarDrivingLicence("430101758218")); } @Test @@ -281,8 +296,8 @@ public class ValidatorTest { final String content = "https://detail.tmall.com/item.htm?" + "id=639428931841&ali_refid=a3_430582_1006:1152464078:N:Sk5vwkMVsn5O6DcnvicELrFucL21A32m:0af8611e23c1d07697e"; - Assertions.assertTrue(Validator.isMatchRegex(PatternPool.URL, content)); - Assertions.assertTrue(Validator.isMatchRegex(PatternPool.URL_HTTP, content)); + assertTrue(Validator.isMatchRegex(PatternPool.URL, content)); + assertTrue(Validator.isMatchRegex(PatternPool.URL_HTTP, content)); } @Test @@ -292,7 +307,7 @@ public class ValidatorTest { final Date end = DateUtil.parse("2022-09-09 21:22:00"); Validator.validateBetween(value, start, end, "您选择的日期超出规定范围!"); - Assertions.assertTrue(true); + assertTrue(true); final Date value2 = DateUtil.parse("2023-08-09 21:22:00"); Assertions.assertThrows(ValidateException.class, ()-> @@ -325,18 +340,18 @@ public class ValidatorTest { @Test public void isChineseNameTest(){ - Assertions.assertTrue(Validator.isChineseName("阿卜杜尼亚孜·毛力尼亚孜")); - Assertions.assertFalse(Validator.isChineseName("阿卜杜尼亚孜./毛力尼亚孜")); - Assertions.assertTrue(Validator.isChineseName("段正淳")); - Assertions.assertTrue(Validator.isChineseName("刘欣䶮")); + assertTrue(Validator.isChineseName("阿卜杜尼亚孜·毛力尼亚孜")); + assertFalse(Validator.isChineseName("阿卜杜尼亚孜./毛力尼亚孜")); + assertTrue(Validator.isChineseName("段正淳")); + assertTrue(Validator.isChineseName("刘欣䶮")); - Assertions.assertFalse(Validator.isChineseName("孟 伟")); - Assertions.assertFalse(Validator.isChineseName("李")); - Assertions.assertFalse(Validator.isChineseName("连逍遥0")); - Assertions.assertFalse(Validator.isChineseName("SHE")); + assertFalse(Validator.isChineseName("孟 伟")); + assertFalse(Validator.isChineseName("李")); + assertFalse(Validator.isChineseName("连逍遥0")); + assertFalse(Validator.isChineseName("SHE")); // issue#IAOGDR - Assertions.assertFalse(Validator.isChineseName("张三。")); + assertFalse(Validator.isChineseName("张三。")); } @Test