This is an automated email from the ASF dual-hosted git repository.

terrymanu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new efd97c03d29 [ISSUE-39362] Fix from-x and to-y rejecting 0 as a valid 
position (#39389)
efd97c03d29 is described below

commit efd97c03d294be02751e479770f852ce281839c2
Author: yali <[email protected]>
AuthorDate: Tue Aug 18 15:14:29 2026 +0800

    [ISSUE-39362] Fix from-x and to-y rejecting 0 as a valid position (#39389)
    
    * [ISSUE-39362] Add checkNotNegativeInteger for 0-based position validation
    
    * [ISSUE-39362] Use checkNotNegativeInteger for from-x and to-y
    
    * [ISSUE-39362] Use checkNotNegativeInteger for from-x and to-y
    
    * [ISSUE-39362] Add zero and negative boundary tests for 
checkNotNegativeInteger
    
    * [ISSUE-39362] Add zero-from-x boundary test cases for MaskFromXToY
    
    * [ISSUE-39362] Add zero-from-x boundary test cases for KeepFromXToY
    
    * [ISSUE-39362] Fix expected values for KeepFromXToY zero-from-x tests
    
    * [ISSUE-39362] Fix expected value for MaskFromXToY zero-from-x short case
---
 .../algorithm/MaskAlgorithmPropertiesChecker.java  | 18 +++++++++++++
 .../algorithm/cover/KeepFromXToYMaskAlgorithm.java |  4 +--
 .../algorithm/cover/MaskFromXToYMaskAlgorithm.java |  4 +--
 .../MaskAlgorithmPropertiesCheckerTest.java        | 30 ++++++++++++++++++++++
 .../cover/KeepFromXToYMaskAlgorithmTest.java       | 21 +++++++++++++++
 .../cover/MaskFromXToYMaskAlgorithmTest.java       | 21 +++++++++++++++
 6 files changed, 94 insertions(+), 4 deletions(-)

diff --git 
a/features/mask/core/src/main/java/org/apache/shardingsphere/mask/algorithm/MaskAlgorithmPropertiesChecker.java
 
b/features/mask/core/src/main/java/org/apache/shardingsphere/mask/algorithm/MaskAlgorithmPropertiesChecker.java
index cd5cc2ac02f..19f9ef53174 100644
--- 
a/features/mask/core/src/main/java/org/apache/shardingsphere/mask/algorithm/MaskAlgorithmPropertiesChecker.java
+++ 
b/features/mask/core/src/main/java/org/apache/shardingsphere/mask/algorithm/MaskAlgorithmPropertiesChecker.java
@@ -73,6 +73,24 @@ public final class MaskAlgorithmPropertiesChecker {
         }
     }
     
+    /**
+     * check not negative integer.
+     *
+     * @param props properties to be checked
+     * @param propKey properties key to be checked
+     * @param algorithm mask algorithm
+     * @throws AlgorithmInitializationException algorithm initialization 
exception
+     */
+    public static void checkNotNegativeInteger(final Properties props, final 
String propKey, final MaskAlgorithm<?, ?> algorithm) {
+        checkRequired(props, propKey, algorithm);
+        try {
+            int integerValue = Integer.parseInt(props.getProperty(propKey));
+            ShardingSpherePreconditions.checkState(integerValue >= 0, () -> 
new AlgorithmInitializationException(algorithm, "%s must be a not negative 
integer.", propKey));
+        } catch (final NumberFormatException ex) {
+            throw new AlgorithmInitializationException(algorithm, "%s must be 
a valid integer number", propKey);
+        }
+    }
+    
     private static void checkRequired(final Properties props, final String 
requiredPropKey, final MaskAlgorithm<?, ?> algorithm) {
         ShardingSpherePreconditions.checkContainsKey(props, requiredPropKey, 
() -> new AlgorithmInitializationException(algorithm, "%s is required", 
requiredPropKey));
     }
diff --git 
a/features/mask/core/src/main/java/org/apache/shardingsphere/mask/algorithm/cover/KeepFromXToYMaskAlgorithm.java
 
b/features/mask/core/src/main/java/org/apache/shardingsphere/mask/algorithm/cover/KeepFromXToYMaskAlgorithm.java
index e96eaebe9b2..e897a104abf 100644
--- 
a/features/mask/core/src/main/java/org/apache/shardingsphere/mask/algorithm/cover/KeepFromXToYMaskAlgorithm.java
+++ 
b/features/mask/core/src/main/java/org/apache/shardingsphere/mask/algorithm/cover/KeepFromXToYMaskAlgorithm.java
@@ -52,12 +52,12 @@ public final class KeepFromXToYMaskAlgorithm implements 
MaskAlgorithm<Object, St
     }
     
     private Integer createFromX(final Properties props) {
-        MaskAlgorithmPropertiesChecker.checkPositiveInteger(props, FROM_X, 
this);
+        MaskAlgorithmPropertiesChecker.checkNotNegativeInteger(props, FROM_X, 
this);
         return Integer.parseInt(props.getProperty(FROM_X));
     }
     
     private Integer createToY(final Properties props) {
-        MaskAlgorithmPropertiesChecker.checkPositiveInteger(props, TO_Y, this);
+        MaskAlgorithmPropertiesChecker.checkNotNegativeInteger(props, TO_Y, 
this);
         return Integer.parseInt(props.getProperty(TO_Y));
     }
     
diff --git 
a/features/mask/core/src/main/java/org/apache/shardingsphere/mask/algorithm/cover/MaskFromXToYMaskAlgorithm.java
 
b/features/mask/core/src/main/java/org/apache/shardingsphere/mask/algorithm/cover/MaskFromXToYMaskAlgorithm.java
index eab93c67504..0b7cdc6ccf7 100644
--- 
a/features/mask/core/src/main/java/org/apache/shardingsphere/mask/algorithm/cover/MaskFromXToYMaskAlgorithm.java
+++ 
b/features/mask/core/src/main/java/org/apache/shardingsphere/mask/algorithm/cover/MaskFromXToYMaskAlgorithm.java
@@ -52,12 +52,12 @@ public final class MaskFromXToYMaskAlgorithm implements 
MaskAlgorithm<Object, St
     }
     
     private Integer createFromX(final Properties props) {
-        MaskAlgorithmPropertiesChecker.checkPositiveInteger(props, FROM_X, 
this);
+        MaskAlgorithmPropertiesChecker.checkNotNegativeInteger(props, FROM_X, 
this);
         return Integer.parseInt(props.getProperty(FROM_X));
     }
     
     private Integer createToY(final Properties props) {
-        MaskAlgorithmPropertiesChecker.checkPositiveInteger(props, TO_Y, this);
+        MaskAlgorithmPropertiesChecker.checkNotNegativeInteger(props, TO_Y, 
this);
         return Integer.parseInt(props.getProperty(TO_Y));
     }
     
diff --git 
a/features/mask/core/src/test/java/org/apache/shardingsphere/mask/algorithm/MaskAlgorithmPropertiesCheckerTest.java
 
b/features/mask/core/src/test/java/org/apache/shardingsphere/mask/algorithm/MaskAlgorithmPropertiesCheckerTest.java
index 4392f4512f5..7710c58e2a9 100644
--- 
a/features/mask/core/src/test/java/org/apache/shardingsphere/mask/algorithm/MaskAlgorithmPropertiesCheckerTest.java
+++ 
b/features/mask/core/src/test/java/org/apache/shardingsphere/mask/algorithm/MaskAlgorithmPropertiesCheckerTest.java
@@ -90,4 +90,34 @@ class MaskAlgorithmPropertiesCheckerTest {
         Properties props = PropertiesBuilder.build(new Property("key", 
"123.0"));
         assertThrows(AlgorithmInitializationException.class, () -> 
MaskAlgorithmPropertiesChecker.checkPositiveInteger(props, "key", 
mock(MaskAlgorithm.class)));
     }
+    
+    @Test
+    void assertCheckNotNegativeIntegerSuccessWithPositive() {
+        Properties props = PropertiesBuilder.build(new Property("key", "123"));
+        assertDoesNotThrow(() -> 
MaskAlgorithmPropertiesChecker.checkNotNegativeInteger(props, "key", 
mock(MaskAlgorithm.class)));
+    }
+    
+    @Test
+    void assertCheckNotNegativeIntegerSuccessWithZero() {
+        Properties props = PropertiesBuilder.build(new Property("key", "0"));
+        assertDoesNotThrow(() -> 
MaskAlgorithmPropertiesChecker.checkNotNegativeInteger(props, "key", 
mock(MaskAlgorithm.class)));
+    }
+    
+    @Test
+    void assertCheckNotNegativeIntegerFailedWithoutKey() {
+        Properties props = new Properties();
+        assertThrows(AlgorithmInitializationException.class, () -> 
MaskAlgorithmPropertiesChecker.checkNotNegativeInteger(props, "key", 
mock(MaskAlgorithm.class)));
+    }
+    
+    @Test
+    void assertCheckNotNegativeIntegerFailedWithNegative() {
+        Properties props = PropertiesBuilder.build(new Property("key", "-1"));
+        assertThrows(AlgorithmInitializationException.class, () -> 
MaskAlgorithmPropertiesChecker.checkNotNegativeInteger(props, "key", 
mock(MaskAlgorithm.class)));
+    }
+    
+    @Test
+    void assertCheckNotNegativeIntegerFailedWithNotInteger() {
+        Properties props = PropertiesBuilder.build(new Property("key", 
"123.0"));
+        assertThrows(AlgorithmInitializationException.class, () -> 
MaskAlgorithmPropertiesChecker.checkNotNegativeInteger(props, "key", 
mock(MaskAlgorithm.class)));
+    }
 }
diff --git 
a/features/mask/core/src/test/java/org/apache/shardingsphere/mask/algorithm/cover/KeepFromXToYMaskAlgorithmTest.java
 
b/features/mask/core/src/test/java/org/apache/shardingsphere/mask/algorithm/cover/KeepFromXToYMaskAlgorithmTest.java
index 08d9f941fcd..ef705faac0d 100644
--- 
a/features/mask/core/src/test/java/org/apache/shardingsphere/mask/algorithm/cover/KeepFromXToYMaskAlgorithmTest.java
+++ 
b/features/mask/core/src/test/java/org/apache/shardingsphere/mask/algorithm/cover/KeepFromXToYMaskAlgorithmTest.java
@@ -51,6 +51,12 @@ class KeepFromXToYMaskAlgorithmTest {
         MaskAlgorithmAssertions.assertMask(type, props, plainValue, 
maskedValue);
     }
     
+    @ParameterizedTest(name = "{0}: {1}")
+    @ArgumentsSource(AlgorithmMaskExecuteWithZeroFromXArgumentsProvider.class)
+    void assertMaskWithZeroFromX(final String type, 
@SuppressWarnings("unused") final String name, final Properties props, final 
Object plainValue, final Object maskedValue) {
+        MaskAlgorithmAssertions.assertMask(type, props, plainValue, 
maskedValue);
+    }
+    
     private static final class AlgorithmInitArgumentsProvider extends 
MaskAlgorithmInitArgumentsProvider {
         
         AlgorithmInitArgumentsProvider() {
@@ -106,4 +112,19 @@ class KeepFromXToYMaskAlgorithmTest {
                     new 
MaskAlgorithmExecuteCaseAssert("plain_value_length_equals_to_Y_plus_one", 
"abc123", "*****3"));
         }
     }
+    
+    private static final class 
AlgorithmMaskExecuteWithZeroFromXArgumentsProvider extends 
MaskAlgorithmExecuteArgumentsProvider {
+        
+        AlgorithmMaskExecuteWithZeroFromXArgumentsProvider() {
+            super("KEEP_FROM_X_TO_Y", PropertiesBuilder.build(new 
Property("from-x", "0"), new Property("to-y", "2"), new 
Property("replace-char", "*")));
+        }
+        
+        @Override
+        protected Collection<MaskAlgorithmExecuteCaseAssert> getCaseAsserts() {
+            return Arrays.asList(
+                    new MaskAlgorithmExecuteCaseAssert("zero_from_x_normal", 
"abc123456", "abc******"),
+                    new MaskAlgorithmExecuteCaseAssert("zero_from_x_short", 
"ab", "ab"),
+                    new MaskAlgorithmExecuteCaseAssert("zero_from_x_empty", 
"", ""));
+        }
+    }
 }
diff --git 
a/features/mask/core/src/test/java/org/apache/shardingsphere/mask/algorithm/cover/MaskFromXToYMaskAlgorithmTest.java
 
b/features/mask/core/src/test/java/org/apache/shardingsphere/mask/algorithm/cover/MaskFromXToYMaskAlgorithmTest.java
index ced2c5aa852..59726f71492 100644
--- 
a/features/mask/core/src/test/java/org/apache/shardingsphere/mask/algorithm/cover/MaskFromXToYMaskAlgorithmTest.java
+++ 
b/features/mask/core/src/test/java/org/apache/shardingsphere/mask/algorithm/cover/MaskFromXToYMaskAlgorithmTest.java
@@ -51,6 +51,12 @@ class MaskFromXToYMaskAlgorithmTest {
         MaskAlgorithmAssertions.assertMask(type, props, plainValue, 
maskedValue);
     }
     
+    @ParameterizedTest(name = "{0}: {1}")
+    @ArgumentsSource(AlgorithmMaskExecuteWithZeroFromXArgumentsProvider.class)
+    void assertMaskWithZeroFromX(final String type, 
@SuppressWarnings("unused") final String name, final Properties props, final 
Object plainValue, final Object maskedValue) {
+        MaskAlgorithmAssertions.assertMask(type, props, plainValue, 
maskedValue);
+    }
+    
     private static final class AlgorithmInitArgumentsProvider extends 
MaskAlgorithmInitArgumentsProvider {
         
         AlgorithmInitArgumentsProvider() {
@@ -104,4 +110,19 @@ class MaskFromXToYMaskAlgorithmTest {
                     new 
MaskAlgorithmExecuteCaseAssert("length_equals_to_Y_plus_one", "abc123", 
"abc12*"));
         }
     }
+    
+    private static final class 
AlgorithmMaskExecuteWithZeroFromXArgumentsProvider extends 
MaskAlgorithmExecuteArgumentsProvider {
+        
+        AlgorithmMaskExecuteWithZeroFromXArgumentsProvider() {
+            super("MASK_FROM_X_TO_Y", PropertiesBuilder.build(new 
Property("from-x", "0"), new Property("to-y", "2"), new 
Property("replace-char", "*")));
+        }
+        
+        @Override
+        protected Collection<MaskAlgorithmExecuteCaseAssert> getCaseAsserts() {
+            return Arrays.asList(
+                    new MaskAlgorithmExecuteCaseAssert("zero_from_x_normal", 
"abc123456", "***123456"),
+                    new MaskAlgorithmExecuteCaseAssert("zero_from_x_short", 
"ab", "**"),
+                    new MaskAlgorithmExecuteCaseAssert("zero_from_x_empty", 
"", ""));
+        }
+    }
 }

Reply via email to