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

garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git


The following commit(s) were added to refs/heads/master by this push:
     new 75d71af80 Include 0x7E (~) in RandomStringUtils nextGraph and 
nextPrint (#1808)
75d71af80 is described below

commit 75d71af80ace2d75dab3f6bb82ac2ef91650634e
Author: alhuda <[email protected]>
AuthorDate: Thu Oct 1 17:51:12 2026 +0530

    Include 0x7E (~) in RandomStringUtils nextGraph and nextPrint (#1808)
    
    * include 0x7e in RandomStringUtils nextGraph and nextPrint
    
    * Update tests for RandomStringUtils to verify character ranges
    
    Co-authored-by: Copilot Autofix powered by AI 
<[email protected]>
    
    * Assert both range ends in the nextGraph and nextPrint tests
    
    The range-only checks passed whether or not nextGraph and nextPrint were
    fixed, so they did not guard the off-by-one. Fold the range check and the
    boundary check into one helper that asserts the lowest and highest
    documented characters are both generated and that nothing outside the
    inclusive range is, and drop the hard-coded probability formula from the
    Javadoc in favour of referencing LOOP_COUNT.
    
    ---------
    
    Co-authored-by: Gary Gregory <[email protected]>
    Co-authored-by: Copilot Autofix powered by AI 
<[email protected]>
---
 .../apache/commons/lang3/RandomStringUtils.java    |  4 +-
 .../commons/lang3/RandomStringUtilsTest.java       | 59 ++++++++++++++++++++++
 2 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/src/main/java/org/apache/commons/lang3/RandomStringUtils.java 
b/src/main/java/org/apache/commons/lang3/RandomStringUtils.java
index 1baa97a0d..97874e7d3 100644
--- a/src/main/java/org/apache/commons/lang3/RandomStringUtils.java
+++ b/src/main/java/org/apache/commons/lang3/RandomStringUtils.java
@@ -969,7 +969,7 @@ public String nextAscii(final int minLengthInclusive, final 
int maxLengthExclusi
      * @since 3.5
      */
     public String nextGraph(final int count) {
-        return next(count, 33, 126, false, false);
+        return next(count, 33, 127, false, false);
     }
 
     /**
@@ -1034,7 +1034,7 @@ public String nextNumeric(final int minLengthInclusive, 
final int maxLengthExclu
      * @since 3.16.0
      */
     public String nextPrint(final int count) {
-        return next(count, 32, 126, false, false);
+        return next(count, 32, 127, false, false);
     }
 
     /**
diff --git a/src/test/java/org/apache/commons/lang3/RandomStringUtilsTest.java 
b/src/test/java/org/apache/commons/lang3/RandomStringUtilsTest.java
index 9d4c1daa5..52507302f 100644
--- a/src/test/java/org/apache/commons/lang3/RandomStringUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/RandomStringUtilsTest.java
@@ -30,6 +30,7 @@
 import java.nio.charset.StandardCharsets;
 import java.time.Duration;
 import java.util.Random;
+import java.util.function.IntFunction;
 import java.util.stream.Stream;
 
 import org.junit.jupiter.api.Test;
@@ -46,10 +47,42 @@ class RandomStringUtilsTest extends AbstractLangTest {
 
     private static final int LOOP_COUNT = 1_000;
 
+    /** Characters generated per iteration when checking that a documented 
range boundary is reachable. */
+    private static final int BOUNDARY_SAMPLE_LENGTH = 100;
+
     /** Maximum safe value for count to avoid overflow: (21x + 3) / 5 + 10 < 
0x0FFF_FFFF */
     private static final int MAX_SAFE_COUNT = 63_913_201;
 
 
+    /**
+     * Asserts that a generator produces both ends of an inclusive character 
range and nothing outside it.
+     * <p>
+     * The random number generator of a {@link RandomStringUtils} instance 
cannot be injected, so reaching a boundary is
+     * sampled rather than forced: {@value #LOOP_COUNT} strings of {@value 
#BOUNDARY_SAMPLE_LENGTH} characters. Over a sample
+     * that size, a correct generator missing a given boundary character is 
not a failure mode that can be observed in
+     * practice.
+     * </p>
+     *
+     * @param generator    Generator under test, called with a character count.
+     * @param minInclusive Lowest character the generator is documented to 
produce.
+     * @param maxInclusive Highest character the generator is documented to 
produce.
+     */
+    private static void assertInclusiveRange(final IntFunction<String> 
generator, final char minInclusive, final char maxInclusive) {
+        boolean minFound = false;
+        boolean maxFound = false;
+        for (int i = 0; i < LOOP_COUNT; i++) {
+            final String randString = generator.apply(BOUNDARY_SAMPLE_LENGTH);
+            for (int j = 0; j < randString.length(); j++) {
+                final char ch = randString.charAt(j);
+                assertTrue(ch >= minInclusive && ch <= maxInclusive, () -> 
"character out of range: " + (int) ch);
+                minFound |= ch == minInclusive;
+                maxFound |= ch == maxInclusive;
+            }
+        }
+        assertTrue(minFound, () -> "character not generated in " + LOOP_COUNT 
+ " attempts: " + (int) minInclusive);
+        assertTrue(maxFound, () -> "character not generated in " + LOOP_COUNT 
+ " attempts: " + (int) maxInclusive);
+    }
+
     static Stream<RandomStringUtils> randomProvider() {
         return Stream.of(RandomStringUtils.secure(), 
RandomStringUtils.secureStrong(), RandomStringUtils.insecure());
     }
@@ -746,6 +779,32 @@ void testRandomAscii(final RandomStringUtils rsu) {
         }
     }
 
+    /**
+     * Verifies that {@link RandomStringUtils#nextGraph(int)} generates both 
ends of the POSIX {@code [:graph:]} class,
+     * {@code '!'} (0x21) and {@code '~'} (0x7E), and nothing outside it.
+     *
+     * @param rsu The instance to test
+     * @see #assertInclusiveRange(IntFunction, char, char)
+     */
+    @ParameterizedTest
+    @MethodSource("randomProvider")
+    void testRandomGraphIncludesTilde(final RandomStringUtils rsu) {
+        assertInclusiveRange(rsu::nextGraph, '!', '~');
+    }
+
+    /**
+     * Verifies that {@link RandomStringUtils#nextPrint(int)} generates both 
ends of the POSIX {@code [:print:]} class,
+     * space (0x20) and {@code '~'} (0x7E), and nothing outside it.
+     *
+     * @param rsu The instance to test
+     * @see #assertInclusiveRange(IntFunction, char, char)
+     */
+    @ParameterizedTest
+    @MethodSource("randomProvider")
+    void testRandomPrintIncludesTilde(final RandomStringUtils rsu) {
+        assertInclusiveRange(rsu::nextPrint, ' ', '~');
+    }
+
     @ParameterizedTest
     @MethodSource("randomProvider")
     void testRandomAsciiRange(final RandomStringUtils rsu) {

Reply via email to