From 8f45918465c1c992d55fe08f2d7e49689b722b38 Mon Sep 17 00:00:00 2001 From: Stephen Colebourne Date: Mon, 9 Jun 2003 21:36:03 +0000 Subject: [PATCH] Ensure that RandomStringUtils returns all expected characters bug 20592, reported/patched by Phil Steitz git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/lang/trunk@137365 13f79535-47bb-0310-9956-ffa450edef68 --- .../commons/lang/RandomStringUtils.java | 12 +-- .../commons/lang/RandomStringUtilsTest.java | 99 ++++++++++++++++++- .../commons/lang/math/RandomUtilsTest.java | 42 ++++---- 3 files changed, 123 insertions(+), 30 deletions(-) diff --git a/src/java/org/apache/commons/lang/RandomStringUtils.java b/src/java/org/apache/commons/lang/RandomStringUtils.java index 63329f42e..63b8c11e2 100644 --- a/src/java/org/apache/commons/lang/RandomStringUtils.java +++ b/src/java/org/apache/commons/lang/RandomStringUtils.java @@ -63,8 +63,9 @@ import java.util.Random; * @author Steven Caswell * @author Stephen Colebourne * @author Gary Gregory + * @author Phil Steitz * @since 1.0 - * @version $Id: RandomStringUtils.java,v 1.12 2003/05/20 21:15:19 ggregory Exp $ + * @version $Id: RandomStringUtils.java,v 1.13 2003/06/09 21:36:02 scolebourne Exp $ */ public class RandomStringUtils { @@ -104,7 +105,7 @@ public class RandomStringUtils { * specified.

* *

Characters will be chosen from the set of characters whose - * ASCII value is between 32 and 127.

+ * ASCII value is between 32 and 126 (inclusive).

* * @param count length of random string to create * @return the random string @@ -199,9 +200,8 @@ public class RandomStringUtils { * * This method has exactly the same semantics as {@link * #random(int,int,int,boolean,boolean,char[],Random)}, but - * instead of depending on internal source of randomness ({@link - * #RANDOM}) it uses externally supplied instance of {@link - * Random} class. + * instead of using an externally supplied source of randomness, it uses + * the internal static {@link Random} instance ({@link #RANDOM}). * * @param count length of random string to create * @param start position in set of chars to start at @@ -256,7 +256,7 @@ public class RandomStringUtils { throw new IllegalArgumentException("Requested random string length " + count + " is less than 0."); } if( (start == 0) && (end == 0) ) { - end = (int)'z'; + end = (int)'z' + 1; start = (int)' '; if(!letters && !numbers) { start = 0; diff --git a/src/test/org/apache/commons/lang/RandomStringUtilsTest.java b/src/test/org/apache/commons/lang/RandomStringUtilsTest.java index f6ff7c729..a9d03c720 100644 --- a/src/test/org/apache/commons/lang/RandomStringUtilsTest.java +++ b/src/test/org/apache/commons/lang/RandomStringUtilsTest.java @@ -57,12 +57,14 @@ import java.util.Random; import junit.framework.*; import junit.textui.TestRunner; + /** * Unit tests {@link org.apache.commons.lang.RandomStringUtils}. * * @author Steven Caswell * @author Ringo De Smet - * @version $Id: RandomStringUtilsTest.java,v 1.6 2003/05/14 02:50:43 bayard Exp $ + * @author Phil Steitz + * @version $Id: RandomStringUtilsTest.java,v 1.7 2003/06/09 21:36:03 scolebourne Exp $ */ public class RandomStringUtilsTest extends junit.framework.TestCase { /** @@ -167,6 +169,99 @@ public class RandomStringUtilsTest extends junit.framework.TestCase { assertNotNull("random(<0) throws exception", e); } + /** + * Make sure boundary alphanumeric characters are generated by randomAlphaNumeric + * This test will fail randomly with probability = 6 * (61/62)**1000 ~ 5.2E-7 + */ + public void testRandomAlphaNumeric() { + char[] testChars = {'a', 'z', 'A', 'Z', '0', '9'}; + boolean[] found = {false, false, false, false, false, false}; + for (int i = 0; i < 100; i++) { + String randString = RandomStringUtils.randomAlphanumeric(10); + for (int j = 0; j < testChars.length; j++) { + if (randString.indexOf(testChars[j]) > 0) { + found[j] = true; + } + } + } + for (int i = 0; i < testChars.length; i++) { + if (!found[i]) { + fail("alphanumeric character not generated in 1000 attempts: " + + testChars[i] +" -- repeated failures indicate a problem "); + } + } + } + + /** + * Make sure '0' and '9' are generated by randomNumeric + * This test will fail randomly with probability = 2 * (9/10)**1000 ~ 3.5E-46 + */ + public void testRandomNumeric() { + char[] testChars = {'0','9'}; + boolean[] found = {false, false}; + for (int i = 0; i < 100; i++) { + String randString = RandomStringUtils.randomNumeric(10); + for (int j = 0; j < testChars.length; j++) { + if (randString.indexOf(testChars[j]) > 0) { + found[j] = true; + } + } + } + for (int i = 0; i < testChars.length; i++) { + if (!found[i]) { + fail("digit not generated in 1000 attempts: " + + testChars[i] +" -- repeated failures indicate a problem "); + } + } + } + + /** + * Make sure boundary alpha characters are generated by randomAlphabetic + * This test will fail randomly with probability = 4 * (51/52)**1000 ~ 1.58E-8 + */ + public void testRandomAlphabetic() { + char[] testChars = {'a', 'z', 'A', 'Z'}; + boolean[] found = {false, false, false, false}; + for (int i = 0; i < 100; i++) { + String randString = RandomStringUtils.randomAlphabetic(10); + for (int j = 0; j < testChars.length; j++) { + if (randString.indexOf(testChars[j]) > 0) { + found[j] = true; + } + } + } + for (int i = 0; i < testChars.length; i++) { + if (!found[i]) { + fail("alphanumeric character not generated in 1000 attempts: " + + testChars[i] +" -- repeated failures indicate a problem "); + } + } + } + + /** + * Make sure 32 and 127 are generated by randomNumeric + * This test will fail randomly with probability = 2*(95/96)**1000 ~ 5.7E-5 + */ + public void testRandomAscii() { + char[] testChars = {(char) 32, (char) 126}; + boolean[] found = {false, false}; + for (int i = 0; i < 100; i++) { + String randString = RandomStringUtils.randomAscii(10); + for (int j = 0; j < testChars.length; j++) { + if (randString.indexOf(testChars[j]) > 0) { + found[j] = true; + } + } + } + for (int i = 0; i < testChars.length; i++) { + if (!found[i]) { + fail("ascii character not generated in 1000 attempts: " + + (int) testChars[i] + + " -- repeated failures indicate a problem"); + } + } + } + /** * Test homogeneity of random strings generated -- * i.e., test that characters show up with expected frequencies @@ -195,8 +290,6 @@ public class RandomStringUtilsTest extends junit.framework.TestCase { chiSquare(expected,counts) < 13.82); } - //FIXME: add similar tests for other functions - /** * Computes Chi-Square statistic given observed and expected counts * @param observed array of observed frequency counts diff --git a/src/test/org/apache/commons/lang/math/RandomUtilsTest.java b/src/test/org/apache/commons/lang/math/RandomUtilsTest.java index dab76bba6..bad8bd670 100644 --- a/src/test/org/apache/commons/lang/math/RandomUtilsTest.java +++ b/src/test/org/apache/commons/lang/math/RandomUtilsTest.java @@ -63,7 +63,7 @@ import junit.framework.TestSuite; * Test cases for the {@link RandomUtils} class. * * @author Phil Steitz - * @version $Revision: 1.2 $ $Date: 2003/06/08 14:19:43 $ + * @version $Revision: 1.3 $ $Date: 2003/06/09 21:36:03 $ */ public final class RandomUtilsTest extends TestCase { @@ -126,12 +126,12 @@ public final class RandomUtilsTest extends TestCase { assertTrue(result >= 0); observed[result]++; } - /* Use ChiSquare dist with df = 4-1 = 3, alpha = .01 - * Change to 16.27 for alpha = .001 + /* Use ChiSquare dist with df = 4-1 = 3, alpha = .001 + * Change to 11.34 for alpha = .01 */ assertTrue( - "chi-square test -- will fail about 1 in 100 times", - chiSquare(expected,observed) < 11.34); + "chi-square test -- will fail about 1 in 1000 times", + chiSquare(expected,observed) < 16.27); } /** test distribution of nextLong() */ @@ -171,12 +171,12 @@ public final class RandomUtilsTest extends TestCase { observed[1]++; } } - /* Use ChiSquare dist with df = 2-1 = 1, alpha = .01 - * Change to 10.83 for alpha = .001 + /* Use ChiSquare dist with df = 2-1 = 1, alpha = .001 + * Change to 6.64 for alpha = .01 */ assertTrue( - "chi-square test -- will fail about 1 in 100 times", - chiSquare(expected,observed) < 6.64); + "chi-square test -- will fail about 1 in 1000 times", + chiSquare(expected,observed) < 10.83); } @@ -214,12 +214,12 @@ public final class RandomUtilsTest extends TestCase { observed[1]++; } } - /* Use ChiSquare dist with df = 2-1 = 1, alpha = .01 - * Change to 10.83 for alpha = .001 + /* Use ChiSquare dist with df = 2-1 = 1, alpha = .001 + * Change to 6.64 for alpha = .01 */ assertTrue( - "chi-square test -- will fail about 1 in 100 times", - chiSquare(expected,observed) < 6.64); + "chi-square test -- will fail about 1 in 1000 times", + chiSquare(expected,observed) < 10.83 ); } /** test distribution of nextFloat() */ @@ -256,12 +256,12 @@ public final class RandomUtilsTest extends TestCase { observed[1]++; } } - /* Use ChiSquare dist with df = 2-1 = 1, alpha = .01 - * Change to 10.83 for alpha = .001 + /* Use ChiSquare dist with df = 2-1 = 1, alpha = .001 + * Change to 6.64 for alpha = .01 */ assertTrue( - "chi-square test -- will fail about 1 in 100 times", - chiSquare(expected,observed) < 6.64); + "chi-square test -- will fail about 1 in 1000 times", + chiSquare(expected,observed) < 10.83); } /** test distribution of nextDouble() */ @@ -298,12 +298,12 @@ public final class RandomUtilsTest extends TestCase { observed[1]++; } } - /* Use ChiSquare dist with df = 2-1 = 1, alpha = .01 - * Change to 10.83 for alpha = .001 + /* Use ChiSquare dist with df = 2-1 = 1, alpha = .001 + * Change to 6.64 for alpha = .01 */ assertTrue( - "chi-square test -- will fail about 1 in 100 times", - chiSquare(expected,observed) < 6.64); + "chi-square test -- will fail about 1 in 1000 times", + chiSquare(expected,observed) < 10.83); } /** make sure that setSeed fails */