You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by pa...@apache.org on 2017/04/28 14:27:14 UTC

[1/4] [text] TEXT-36: RandomStringGenerator: allow users to provide source of randomness (closes #25)

Repository: commons-text
Updated Branches:
  refs/heads/master 66cf58776 -> 1f5171efc


TEXT-36: RandomStringGenerator: allow users to provide source of randomness (closes #25)

Create functional interface to provide randomness for RandomStringGenerator


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/8d14206b
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/8d14206b
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/8d14206b

Branch: refs/heads/master
Commit: 8d14206b94631e5c78a51e1a319c7e7ad06e890a
Parents: edb0676
Author: Ray DeCampo <ra...@decampo.org>
Authored: Fri Jan 6 06:52:15 2017 -0500
Committer: Pascal Schumacher <pa...@gmx.net>
Committed: Fri Apr 28 16:25:34 2017 +0200

----------------------------------------------------------------------
 .../commons/text/RandomStringGenerator.java     | 37 +++++++++++---
 .../apache/commons/text/TextRandomProvider.java | 51 ++++++++++++++++++++
 .../commons/text/RandomStringGeneratorTest.java |  8 ++-
 3 files changed, 83 insertions(+), 13 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/8d14206b/src/main/java/org/apache/commons/text/RandomStringGenerator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/RandomStringGenerator.java b/src/main/java/org/apache/commons/text/RandomStringGenerator.java
index c4411a2..7eb45d9 100644
--- a/src/main/java/org/apache/commons/text/RandomStringGenerator.java
+++ b/src/main/java/org/apache/commons/text/RandomStringGenerator.java
@@ -17,7 +17,6 @@
 package org.apache.commons.text;
 
 import java.util.HashSet;
-import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.ThreadLocalRandom;
 
@@ -30,8 +29,13 @@ import java.util.concurrent.ThreadLocalRandom;
  * </p>
  * 
  * <pre>
+ * // Using Apache Commons RNG for randomness
+ * UniformRandomProvider rng = RandomSource.create(...);
  * // Generates a 20 code point string, using only the letters a-z
- * RandomStringGenerator generator = new RandomStringGenerator.Builder().withinRange('a', 'z').build();
+ * RandomStringGenerator generator = new RandomStringGenerator.Builder()
+ *     .withinRange('a', 'z')
+ *     .usingRandom(rng::nextInt) // uses Java 8 syntax
+ *     .build();
  * String random = generator.generate(20);
  * </pre>
  * 
@@ -46,7 +50,7 @@ public final class RandomStringGenerator {
     private final int minimumCodePoint;
     private final int maximumCodePoint;
     private final Set<CharacterPredicate> inclusivePredicates;
-    private final Random random;
+    private final TextRandomProvider random;
 
 
     /**
@@ -62,7 +66,7 @@ public final class RandomStringGenerator {
      *            source of randomness
      */
     private RandomStringGenerator(int minimumCodePoint, int maximumCodePoint,
-            Set<CharacterPredicate> inclusivePredicates, Random random) {
+            Set<CharacterPredicate> inclusivePredicates, TextRandomProvider random) {
         this.minimumCodePoint = minimumCodePoint;
         this.maximumCodePoint = maximumCodePoint;
         this.inclusivePredicates = inclusivePredicates;
@@ -168,7 +172,7 @@ public final class RandomStringGenerator {
      * <p>The minimum and maximum code point values are defined using {@link #withinRange(int, int)}. The
      * default values are {@code 0} and {@link Character#MAX_CODE_POINT} respectively.</p>
      * 
-     * <p>The source of randomness can be set using {@link #usingRandom(Random)}, otherwise {@link ThreadLocalRandom}
+     * <p>The source of randomness can be set using {@link #usingRandom(TextRandomProvider) }, otherwise {@link ThreadLocalRandom}
      * is used.</p>
      * 
      * <p>The type of code points returned can be filtered using {@link #filteredBy(CharacterPredicate...)}, 
@@ -207,7 +211,7 @@ public final class RandomStringGenerator {
         private int minimumCodePoint = DEFAULT_MINIMUM_CODE_POINT;
         private int maximumCodePoint = DEFAULT_MAXIMUM_CODE_POINT;
         private Set<CharacterPredicate> inclusivePredicates;
-        private Random random;
+        private TextRandomProvider random;
         
         
         /**
@@ -286,8 +290,25 @@ public final class RandomStringGenerator {
         
         /**
          * <p>
-         * Overrides the default source of randomness.
+         * Overrides the default source of randomness.  It is highly
+         * recommended that a random number generator library like
+         * <a href="http://commons.apache.org/proper/commons-rng/">Apache Commons RNG</a>
+         * be used to provide the random number generation.
          * </p>
+         *
+         * <p>
+         * When using Java 8 or later, {@link TextRandomProvider} is a
+         * functional interface and need not be explicitly implemented:
+         * </p>
+         * <pre>
+         * {@code
+         * UniformRandomProvider rng = RandomSource.create(...);
+         * RandomStringGenerator gen = new RandomStringGenerator.Builder()
+         *     .usingRandom(rng::nextInt)
+         *     // additional builder calls as needed
+         *     .build();
+         * }
+         * </pre>
          * 
          * <p>
          * Passing {@code null} to this method will revert to the default source of
@@ -299,7 +320,7 @@ public final class RandomStringGenerator {
          * @return {@code this}, to allow method chaining
          * @since 1.0
          */
-        public Builder usingRandom(final Random random) {
+        public Builder usingRandom(final TextRandomProvider random) {
             this.random = random;
             return this;
         }

http://git-wip-us.apache.org/repos/asf/commons-text/blob/8d14206b/src/main/java/org/apache/commons/text/TextRandomProvider.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/TextRandomProvider.java b/src/main/java/org/apache/commons/text/TextRandomProvider.java
new file mode 100644
index 0000000..4aecd72
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/TextRandomProvider.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+/**
+ * <p>
+ * TextRandomProvider implementations are used by {@link RandomStringGenerator}
+ * as a source of randomness.  It is highly recommended that the
+ * <a href="http://commons.apache.org/proper/commons-rng/">Apache Commons RNG</a>
+ * library be used to provide the random number generation.
+ * </p>
+ *
+ * <p>
+ * When using Java 8 or later, TextRandomProvider is a functional interface and
+ * need not be explicitly implemented.  For example:
+ * </p>
+ * <pre>
+ * {@code
+ * UniformRandomProvider rng = RandomSource.create(...);
+ * RandomStringGenerator gen = new RandomStringGenerator.Builder()
+ *     .usingRandom(rng::nextInt)
+ *     // additional builder calls as needed
+ *     .build();
+ * }
+ * </pre>
+ */
+public interface TextRandomProvider {
+
+    /**
+     * Generates an int value between 0 (inclusive) and the specified value 
+     * (exclusive).
+     * @param max  Bound on the random number to be returned. Must be positive.
+     * @return a random int value between 0 (inclusive) and n (exclusive).
+     * @throws IllegalArgumentException - if max is negative
+     */
+    int nextInt(int max);
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/8d14206b/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java b/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
index 36ce5e0..0da2072 100644
--- a/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
+++ b/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
@@ -16,12 +16,10 @@
  */
 package org.apache.commons.text;
 
-import static org.junit.Assert.*;
-
-import java.util.Random;
-
 import org.junit.Test;
 
+import static org.junit.Assert.*;
+
 /**
  * Tests for {@link RandomStringGenerator}
  */
@@ -115,7 +113,7 @@ public class RandomStringGeneratorTest {
     @Test
     public void testUsingRandom() throws Exception {
         final char testChar = 'a';
-        final Random testRandom = new Random() {
+        final TextRandomProvider testRandom = new TextRandomProvider() {
             private static final long serialVersionUID = 1L;
 
             @Override


[4/4] [text] checkstyle.xml: do not require javadoc for private variables

Posted by pa...@apache.org.
checkstyle.xml: do not require javadoc for private variables


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/1f5171ef
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/1f5171ef
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/1f5171ef

Branch: refs/heads/master
Commit: 1f5171efc40e7a0ce28865ea705f77ebc9d7fd66
Parents: c72a24b
Author: Pascal Schumacher <pa...@gmx.net>
Authored: Mon Apr 24 23:16:44 2017 +0200
Committer: Pascal Schumacher <pa...@gmx.net>
Committed: Fri Apr 28 16:26:59 2017 +0200

----------------------------------------------------------------------
 checkstyle.xml | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/1f5171ef/checkstyle.xml
----------------------------------------------------------------------
diff --git a/checkstyle.xml b/checkstyle.xml
index 6afc1dd..e6cb6b2 100644
--- a/checkstyle.xml
+++ b/checkstyle.xml
@@ -94,7 +94,9 @@
             <property name="allowUndeclaredRTE" value="true"/>
         </module>
         <module name="JavadocType"/>
-        <module name="JavadocVariable"/>
+        <module name="JavadocVariable">
+           <property name="excludeScope" value="private"/>
+        </module>
         <module name="JavadocStyle"/>
 
 


[2/4] [text] TEXT-81: Add RandomStringGenerator

Posted by pa...@apache.org.
TEXT-81: Add RandomStringGenerator

Revert "TEXT-51: remove RandomStringGenerator for 1.0 release add again in 1.1"

This reverts commit ba4e4932f0d864a15c94d32fb8c341e230d928df and restores RandomStringGenerator.


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/edb0676a
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/edb0676a
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/edb0676a

Branch: refs/heads/master
Commit: edb0676a3e40ff414c9c0047e3829b28a219d08f
Parents: 66cf587
Author: Pascal Schumacher <pa...@gmx.net>
Authored: Mon Apr 24 22:09:35 2017 +0200
Committer: Pascal Schumacher <pa...@gmx.net>
Committed: Fri Apr 28 16:25:34 2017 +0200

----------------------------------------------------------------------
 .../commons/text/RandomStringGenerator.java     | 316 +++++++++++++++++++
 .../commons/text/RandomStringGeneratorTest.java | 212 +++++++++++++
 2 files changed, 528 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/edb0676a/src/main/java/org/apache/commons/text/RandomStringGenerator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/RandomStringGenerator.java b/src/main/java/org/apache/commons/text/RandomStringGenerator.java
new file mode 100644
index 0000000..c4411a2
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/RandomStringGenerator.java
@@ -0,0 +1,316 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import java.util.HashSet;
+import java.util.Random;
+import java.util.Set;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * <p>
+ * Generates random Unicode strings containing the specified number of code points.
+ * Instances are created using a builder class, which allows the
+ * callers to define the properties of the generator. See the documentation for the
+ * {@link Builder} class to see available properties.
+ * </p>
+ * 
+ * <pre>
+ * // Generates a 20 code point string, using only the letters a-z
+ * RandomStringGenerator generator = new RandomStringGenerator.Builder().withinRange('a', 'z').build();
+ * String random = generator.generate(20);
+ * </pre>
+ * 
+ * <p>
+ * {@code RandomStringBuilder} instances are immutable and thread-safe.
+ * </p>
+ * 
+ * @since 1.0
+ */
+public final class RandomStringGenerator {
+
+    private final int minimumCodePoint;
+    private final int maximumCodePoint;
+    private final Set<CharacterPredicate> inclusivePredicates;
+    private final Random random;
+
+
+    /**
+     * Constructs the generator.
+     * 
+     * @param minimumCodePoint
+     *            smallest allowed code point (inclusive)
+     * @param maximumCodePoint
+     *            largest allowed code point (inclusive)
+     * @param inclusivePredicates
+     *            filters for code points
+     * @param random
+     *            source of randomness
+     */
+    private RandomStringGenerator(int minimumCodePoint, int maximumCodePoint,
+            Set<CharacterPredicate> inclusivePredicates, Random random) {
+        this.minimumCodePoint = minimumCodePoint;
+        this.maximumCodePoint = maximumCodePoint;
+        this.inclusivePredicates = inclusivePredicates;
+        this.random = random;
+    }
+    
+    /**
+     * Generates a random number within a range, using a
+     * {@link ThreadLocalRandom} instance or the user-supplied source of
+     * randomness.
+     * 
+     * @param minInclusive
+     *            the minimum value allowed
+     * @param maxInclusive
+     *            the maximum value allowed
+     * @return the random number.
+     */
+    private int generateRandomNumber(final int minInclusive, final int maxInclusive) {
+        if (random != null) {
+            return random.nextInt(maxInclusive - minInclusive + 1) + minInclusive;
+        }
+
+        return ThreadLocalRandom.current().nextInt(minInclusive, maxInclusive + 1);
+    }
+
+
+    /**
+     * <p>
+     * Generates a random string, containing the specified number of code points.
+     * </p>
+     * <p>Code points are randomly selected between the minimum and maximum values defined
+     * in the generator.
+     * Surrogate and private use characters are not returned, although the
+     * resulting string may contain pairs of surrogates that together encode a
+     * supplementary character.
+     * </p>
+     * <p>
+     * Note: the number of {@code char} code units generated will exceed
+     * {@code length} if the string contains supplementary characters. See the
+     * {@link Character} documentation to understand how Java stores Unicode
+     * values.
+     * </p>
+     * 
+     * @param length
+     *            the number of code points to generate
+     * @return the generated string
+     * @throws IllegalArgumentException
+     *             if {@code length < 0}
+     * @since 1.0
+     */
+    public String generate(final int length) {
+        if (length == 0) {
+            return "";
+        }
+        
+        if (length < 0) {
+            throw new IllegalArgumentException(String.format("Length %d is smaller than zero.", length));
+        }
+
+        final StringBuilder builder = new StringBuilder(length);
+        long remaining = length;
+
+        do {
+            int codePoint = generateRandomNumber(minimumCodePoint, maximumCodePoint);
+
+            switch (Character.getType(codePoint)) {
+            case Character.UNASSIGNED:
+            case Character.PRIVATE_USE:
+            case Character.SURROGATE:
+                continue;
+            }
+
+            if (inclusivePredicates != null) {
+                boolean matchedFilter = false;
+                for (CharacterPredicate predicate : inclusivePredicates) {
+                    if (predicate.test(codePoint)) {
+                        matchedFilter = true;
+                        break;
+                    }
+                }
+                if (!matchedFilter) {
+                    continue;
+                }
+            }
+
+            builder.appendCodePoint(codePoint);
+            remaining--;
+
+        } while (remaining != 0);
+
+        return builder.toString();
+    }
+    
+    
+    /**
+     * <p>A builder for generating {@code RandomStringGenerator} instances.</p>
+     * <p>The behaviour of a generator is controlled by properties set by this
+     * builder. Each property has a default value, which can be overridden by
+     * calling the methods defined in this class, prior to calling {@link #build()}.</p>
+     * 
+     * <p>All the property setting methods return the {@code Builder} instance to allow for method chaining.</p>
+     * 
+     * <p>The minimum and maximum code point values are defined using {@link #withinRange(int, int)}. The
+     * default values are {@code 0} and {@link Character#MAX_CODE_POINT} respectively.</p>
+     * 
+     * <p>The source of randomness can be set using {@link #usingRandom(Random)}, otherwise {@link ThreadLocalRandom}
+     * is used.</p>
+     * 
+     * <p>The type of code points returned can be filtered using {@link #filteredBy(CharacterPredicate...)}, 
+     * which defines a collection of
+     * tests that are applied to the randomly generated code points. The code points
+     * will only be included in the result if they pass at least one of the tests.
+     * Some commonly used predicates are provided by the {@link CharacterPredicates} enum.</p>
+     * 
+     * <p>This class is not thread safe.</p>
+     * @since 1.0
+     */
+    public static class Builder implements org.apache.commons.text.Builder<RandomStringGenerator> {
+        
+        /**
+         * The default maximum code point allowed: {@link Character#MAX_CODE_POINT}
+         * ({@value})
+         * 
+         * @since 1.0
+         */
+        public static final int DEFAULT_MAXIMUM_CODE_POINT = Character.MAX_CODE_POINT;
+        
+        /**
+         * The default string length produced by this builder: {@value}
+         * 
+         * @since 1.0
+         */
+        public static final int DEFAULT_LENGTH = 0;
+
+        /**
+         * The default minimum code point allowed: {@value}
+         * 
+         * @since 1.0
+         */
+        public static final int DEFAULT_MINIMUM_CODE_POINT = 0;
+
+        private int minimumCodePoint = DEFAULT_MINIMUM_CODE_POINT;
+        private int maximumCodePoint = DEFAULT_MAXIMUM_CODE_POINT;
+        private Set<CharacterPredicate> inclusivePredicates;
+        private Random random;
+        
+        
+        /**
+         * <p>
+         * Specifies the minimum and maximum code points allowed in the generated
+         * string.
+         * </p>
+         * 
+         * @param minimumCodePoint
+         *            the smallest code point allowed (inclusive)
+         * @param maximumCodePoint
+         *            the largest code point allowed (inclusive)
+         * @return {@code this}, to allow method chaining
+         * @throws IllegalArgumentException
+         *             if {@code maximumCodePoint >}
+         *             {@link Character#MAX_CODE_POINT}
+         * @throws IllegalArgumentException
+         *             if {@code minimumCodePoint < 0}
+         * @throws IllegalArgumentException
+         *             if {@code minimumCodePoint > maximumCodePoint}
+         * @since 1.0
+         */
+        public Builder withinRange(final int minimumCodePoint, final int maximumCodePoint) {
+            if (minimumCodePoint > maximumCodePoint) {
+                throw new IllegalArgumentException(String.format(
+                        "Minimum code point %d is larger than maximum code point %d", minimumCodePoint, maximumCodePoint));
+            }
+            if (minimumCodePoint < 0) {
+                throw new IllegalArgumentException(String.format("Minimum code point %d is negative", minimumCodePoint));
+            }
+            if (maximumCodePoint > Character.MAX_CODE_POINT) {
+                throw new IllegalArgumentException(
+                        String.format("Value %d is larger than Character.MAX_CODE_POINT.", maximumCodePoint));
+            }
+
+            this.minimumCodePoint = minimumCodePoint;
+            this.maximumCodePoint = maximumCodePoint;
+            return this;
+        }
+        
+        /**
+         * <p>
+         * Limits the characters in the generated string to those that match at
+         * least one of the predicates supplied.
+         * </p>
+         * 
+         * <p>
+         * Passing {@code null} or an empty array to this method will revert to the
+         * default behaviour of allowing any character. Multiple calls to this
+         * method will replace the previously stored predicates.
+         * </p>
+         * 
+         * @param predicates
+         *            the predicates, may be {@code null} or empty
+         * @return {@code this}, to allow method chaining
+         * @since 1.0
+         */
+        public Builder filteredBy(final CharacterPredicate... predicates) {
+            if (predicates == null || predicates.length == 0) {
+                inclusivePredicates = null;
+                return this;
+            }
+
+            if (inclusivePredicates == null) {
+                inclusivePredicates = new HashSet<>();
+            } else {
+                inclusivePredicates.clear();
+            }
+
+            for (CharacterPredicate predicate : predicates) {
+                inclusivePredicates.add(predicate);
+            }
+
+            return this;
+        }
+        
+        /**
+         * <p>
+         * Overrides the default source of randomness.
+         * </p>
+         * 
+         * <p>
+         * Passing {@code null} to this method will revert to the default source of
+         * randomness.
+         * </p>
+         * 
+         * @param random
+         *            the source of randomness, may be {@code null}
+         * @return {@code this}, to allow method chaining
+         * @since 1.0
+         */
+        public Builder usingRandom(final Random random) {
+            this.random = random;
+            return this;
+        }
+
+        /**
+         * <p>Builds the {@code RandomStringGenerator} using the properties specified.</p>
+         */
+        @Override
+        public RandomStringGenerator build() {
+            return new RandomStringGenerator(minimumCodePoint, maximumCodePoint, inclusivePredicates, random);
+        }
+        
+    }
+}

http://git-wip-us.apache.org/repos/asf/commons-text/blob/edb0676a/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java b/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
new file mode 100644
index 0000000..36ce5e0
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.commons.text;
+
+import static org.junit.Assert.*;
+
+import java.util.Random;
+
+import org.junit.Test;
+
+/**
+ * Tests for {@link RandomStringGenerator}
+ */
+public class RandomStringGeneratorTest {
+
+    private static int codePointLength(String s) {
+        return s.codePointCount(0, s.length());
+    }
+
+    private static final CharacterPredicate A_FILTER = new CharacterPredicate() {
+        @Override
+        public boolean test(int codePoint) {
+            return codePoint == 'a';
+        }
+    };
+
+    private static final CharacterPredicate B_FILTER = new CharacterPredicate() {
+        @Override
+        public boolean test(int codePoint) {
+            return codePoint == 'b';
+        }
+    };
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testInvalidLength() throws Exception {
+        RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
+        generator.generate(-1);
+    }
+
+    @Test
+    public void testSetLength() throws Exception {
+        final int length = 99;
+        RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
+        String str = generator.generate(length);
+        assertEquals(length, codePointLength(str));
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testBadMinimumCodePoint() throws Exception {
+        new RandomStringGenerator.Builder().withinRange(-1, 1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testBadMaximumCodePoint() throws Exception {
+        new RandomStringGenerator.Builder().withinRange(0, Character.MAX_CODE_POINT + 1);
+    }
+
+    @Test
+        public void testWithinRange() throws Exception {
+            final int length = 5000;
+            final int minimumCodePoint = 'a';
+            final int maximumCodePoint = 'z';
+            RandomStringGenerator generator = new RandomStringGenerator.Builder().withinRange(minimumCodePoint,maximumCodePoint).build();
+            String str = generator.generate(length);
+    
+            int i = 0;
+            do {
+                int codePoint = str.codePointAt(i);
+                assertTrue(codePoint >= minimumCodePoint && codePoint <= maximumCodePoint);
+                i += Character.charCount(codePoint);
+            } while (i < str.length());
+    
+        }
+
+    @Test
+    public void testNoLoneSurrogates() throws Exception {
+        final int length = 5000;
+        String str = new RandomStringGenerator.Builder().build().generate(length);
+
+        char lastChar = str.charAt(0);
+        for (int i = 1; i < str.length(); i++) {
+            char c = str.charAt(i);
+
+            if (Character.isLowSurrogate(c)) {
+                assertTrue(Character.isHighSurrogate(lastChar));
+            }
+
+            if (Character.isHighSurrogate(lastChar)) {
+                assertTrue(Character.isLowSurrogate(c));
+            }
+
+            if (Character.isHighSurrogate(c)) {
+                // test this isn't the last character in the string
+                assertTrue(i + 1 < str.length());
+            }
+
+            lastChar = c;
+        }
+    }
+
+    @Test
+    public void testUsingRandom() throws Exception {
+        final char testChar = 'a';
+        final Random testRandom = new Random() {
+            private static final long serialVersionUID = 1L;
+
+            @Override
+            public int nextInt(int n) {
+                return testChar;
+            }
+        };
+
+        String str = new RandomStringGenerator.Builder().usingRandom(testRandom).build().generate(10);
+        for (char c : str.toCharArray()) {
+            assertEquals(testChar, c);
+        }
+    }
+
+    @Test
+    public void testMultipleFilters() throws Exception {
+        String str = new RandomStringGenerator.Builder().withinRange('a','d')
+                .filteredBy(A_FILTER, B_FILTER).build().generate(5000);
+
+        boolean aFound = false;
+        boolean bFound = false;
+
+        for (char c : str.toCharArray()) {
+            if (c == 'a') {
+                aFound = true;
+            } else if (c == 'b') {
+                bFound = true;
+            } else {
+                fail("Invalid character");
+            }
+        }
+
+        assertTrue(aFound && bFound);
+    }
+
+    @Test
+    public void testNoPrivateCharacters() throws Exception {
+        final int startOfPrivateBMPChars = 0xE000;
+
+        // Request a string in an area of the Basic Multilingual Plane that is
+        // largely
+        // occupied by private characters
+        String str = new RandomStringGenerator.Builder().withinRange(startOfPrivateBMPChars, 
+                Character.MIN_SUPPLEMENTARY_CODE_POINT - 1).build().generate(5000);
+
+        int i = 0;
+        do {
+            int codePoint = str.codePointAt(i);
+            assertFalse(Character.getType(codePoint) == Character.PRIVATE_USE);
+            i += Character.charCount(codePoint);
+        } while (i < str.length());
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testBadMinAndMax() throws Exception {
+        new RandomStringGenerator.Builder().withinRange(2, 1);
+    }
+
+    @Test
+    public void testRemoveFilters() throws Exception {
+
+        RandomStringGenerator.Builder builder = new RandomStringGenerator.Builder().withinRange('a', 'z')
+                .filteredBy(A_FILTER);
+
+        builder.filteredBy();
+
+        String str = builder.build().generate(100);
+        for (char c : str.toCharArray()) {
+            if (c != 'a') {
+                // filter was successfully removed
+                return;
+            }
+        }
+
+        fail("Filter appears to have remained in place");
+    }
+
+    @Test
+    public void testChangeOfFilter() throws Exception {
+        RandomStringGenerator.Builder builder = new RandomStringGenerator.Builder().withinRange('a', 'z')
+                .filteredBy(A_FILTER);
+        String str = builder.filteredBy(B_FILTER).build().generate(100);
+
+        for (char c : str.toCharArray()) {
+            assertTrue(c == 'b');
+        }
+    }
+    
+    @Test
+    public void testZeroLength() throws Exception {
+        RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
+        assertEquals("", generator.generate(0));
+    }
+}


[3/4] [text] TEXT-81: Add RandomStringGenerator (closes #36)

Posted by pa...@apache.org.
TEXT-81: Add RandomStringGenerator (closes #36)

add changes.xml entries for TEXT-81 and TEXT-36

fix checkstyle violations

other minimal clean-up

fix checkstyle


Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/c72a24bc
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/c72a24bc
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/c72a24bc

Branch: refs/heads/master
Commit: c72a24bc24f2650a71bee0418b2ee3609f297cdc
Parents: 8d14206
Author: Pascal Schumacher <pa...@gmx.net>
Authored: Mon Apr 24 22:28:09 2017 +0200
Committer: Pascal Schumacher <pa...@gmx.net>
Committed: Fri Apr 28 16:26:36 2017 +0200

----------------------------------------------------------------------
 src/changes/changes.xml                         |   2 +
 .../commons/text/RandomStringGenerator.java     | 106 ++++++++-----------
 .../apache/commons/text/TextRandomProvider.java |   4 +-
 .../commons/text/RandomStringGeneratorTest.java |  66 ++++++------
 4 files changed, 82 insertions(+), 96 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/commons-text/blob/c72a24bc/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index cd59174..91067bb 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -46,6 +46,8 @@ The <action> type attribute can be add,update,fix,remove.
   <body>
 
   <release version="1.1" date="tbd" description="tbd">
+    <action issue="TEXT-81" type="add" dev="pschumacher" dev="djones">Add RandomStringGenerator</action>
+    <action issue="TEXT-36" type="add" dev="pschumacher" due-to="Raymond DeCampo">RandomStringGenerator: allow users to provide source of randomness</action>
     <action issue="TEXT-76" type="fix" dev="kinow">Correct round issue in Jaro Winkler implementation</action>
     <action issue="TEXT-72" type="fix" dev="chtompki">Similar to LANG-1025, clirr fails site build.</action>
   </release>

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c72a24bc/src/main/java/org/apache/commons/text/RandomStringGenerator.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/RandomStringGenerator.java b/src/main/java/org/apache/commons/text/RandomStringGenerator.java
index 7eb45d9..ab7fd9d 100644
--- a/src/main/java/org/apache/commons/text/RandomStringGenerator.java
+++ b/src/main/java/org/apache/commons/text/RandomStringGenerator.java
@@ -27,7 +27,12 @@ import java.util.concurrent.ThreadLocalRandom;
  * callers to define the properties of the generator. See the documentation for the
  * {@link Builder} class to see available properties.
  * </p>
- * 
+ * <pre>
+ * // Generates a 20 code point string, using only the letters a-z
+ * RandomStringGenerator generator = new RandomStringGenerator.Builder()
+ *     .withinRange('a', 'z').build();
+ * String randomLetters = generator.generate(20);
+ * </pre>
  * <pre>
  * // Using Apache Commons RNG for randomness
  * UniformRandomProvider rng = RandomSource.create(...);
@@ -36,14 +41,12 @@ import java.util.concurrent.ThreadLocalRandom;
  *     .withinRange('a', 'z')
  *     .usingRandom(rng::nextInt) // uses Java 8 syntax
  *     .build();
- * String random = generator.generate(20);
+ * String randomLetters = generator.generate(20);
  * </pre>
- * 
  * <p>
  * {@code RandomStringBuilder} instances are immutable and thread-safe.
  * </p>
- * 
- * @since 1.0
+ * @since 1.1
  */
 public final class RandomStringGenerator {
 
@@ -52,10 +55,9 @@ public final class RandomStringGenerator {
     private final Set<CharacterPredicate> inclusivePredicates;
     private final TextRandomProvider random;
 
-
     /**
      * Constructs the generator.
-     * 
+     *
      * @param minimumCodePoint
      *            smallest allowed code point (inclusive)
      * @param maximumCodePoint
@@ -72,12 +74,11 @@ public final class RandomStringGenerator {
         this.inclusivePredicates = inclusivePredicates;
         this.random = random;
     }
-    
+
     /**
-     * Generates a random number within a range, using a
-     * {@link ThreadLocalRandom} instance or the user-supplied source of
-     * randomness.
-     * 
+     * Generates a random number within a range, using a {@link ThreadLocalRandom} instance
+     * or the user-supplied source of randomness.
+     *
      * @param minInclusive
      *            the minimum value allowed
      * @param maxInclusive
@@ -88,11 +89,9 @@ public final class RandomStringGenerator {
         if (random != null) {
             return random.nextInt(maxInclusive - minInclusive + 1) + minInclusive;
         }
-
         return ThreadLocalRandom.current().nextInt(minInclusive, maxInclusive + 1);
     }
 
-
     /**
      * <p>
      * Generates a random string, containing the specified number of code points.
@@ -109,19 +108,17 @@ public final class RandomStringGenerator {
      * {@link Character} documentation to understand how Java stores Unicode
      * values.
      * </p>
-     * 
+     *
      * @param length
      *            the number of code points to generate
      * @return the generated string
      * @throws IllegalArgumentException
      *             if {@code length < 0}
-     * @since 1.0
      */
     public String generate(final int length) {
         if (length == 0) {
             return "";
         }
-        
         if (length < 0) {
             throw new IllegalArgumentException(String.format("Length %d is smaller than zero.", length));
         }
@@ -137,6 +134,7 @@ public final class RandomStringGenerator {
             case Character.PRIVATE_USE:
             case Character.SURROGATE:
                 continue;
+            default:
             }
 
             if (inclusivePredicates != null) {
@@ -159,52 +157,44 @@ public final class RandomStringGenerator {
 
         return builder.toString();
     }
-    
-    
+
     /**
      * <p>A builder for generating {@code RandomStringGenerator} instances.</p>
      * <p>The behaviour of a generator is controlled by properties set by this
      * builder. Each property has a default value, which can be overridden by
      * calling the methods defined in this class, prior to calling {@link #build()}.</p>
-     * 
+     *
      * <p>All the property setting methods return the {@code Builder} instance to allow for method chaining.</p>
-     * 
+     *
      * <p>The minimum and maximum code point values are defined using {@link #withinRange(int, int)}. The
      * default values are {@code 0} and {@link Character#MAX_CODE_POINT} respectively.</p>
-     * 
-     * <p>The source of randomness can be set using {@link #usingRandom(TextRandomProvider) }, otherwise {@link ThreadLocalRandom}
-     * is used.</p>
-     * 
-     * <p>The type of code points returned can be filtered using {@link #filteredBy(CharacterPredicate...)}, 
-     * which defines a collection of
-     * tests that are applied to the randomly generated code points. The code points
-     * will only be included in the result if they pass at least one of the tests.
+     *
+     * <p>The source of randomness can be set using {@link #usingRandom(TextRandomProvider)},
+     * otherwise {@link ThreadLocalRandom} is used.</p>
+     *
+     * <p>The type of code points returned can be filtered using {@link #filteredBy(CharacterPredicate...)},
+     * which defines a collection of tests that are applied to the randomly generated code points.
+     * The code points will only be included in the result if they pass at least one of the tests.
      * Some commonly used predicates are provided by the {@link CharacterPredicates} enum.</p>
-     * 
+     *
      * <p>This class is not thread safe.</p>
-     * @since 1.0
+     * @since 1.1
      */
     public static class Builder implements org.apache.commons.text.Builder<RandomStringGenerator> {
-        
+
         /**
          * The default maximum code point allowed: {@link Character#MAX_CODE_POINT}
-         * ({@value})
-         * 
-         * @since 1.0
+         * ({@value}).
          */
         public static final int DEFAULT_MAXIMUM_CODE_POINT = Character.MAX_CODE_POINT;
-        
+
         /**
-         * The default string length produced by this builder: {@value}
-         * 
-         * @since 1.0
+         * The default string length produced by this builder: {@value}.
          */
         public static final int DEFAULT_LENGTH = 0;
 
         /**
-         * The default minimum code point allowed: {@value}
-         * 
-         * @since 1.0
+         * The default minimum code point allowed: {@value}.
          */
         public static final int DEFAULT_MINIMUM_CODE_POINT = 0;
 
@@ -212,14 +202,13 @@ public final class RandomStringGenerator {
         private int maximumCodePoint = DEFAULT_MAXIMUM_CODE_POINT;
         private Set<CharacterPredicate> inclusivePredicates;
         private TextRandomProvider random;
-        
-        
+
         /**
          * <p>
-         * Specifies the minimum and maximum code points allowed in the generated
-         * string.
+         * Specifies the minimum and maximum code points allowed in the
+         * generated string.
          * </p>
-         * 
+         *
          * @param minimumCodePoint
          *            the smallest code point allowed (inclusive)
          * @param maximumCodePoint
@@ -232,15 +221,16 @@ public final class RandomStringGenerator {
          *             if {@code minimumCodePoint < 0}
          * @throws IllegalArgumentException
          *             if {@code minimumCodePoint > maximumCodePoint}
-         * @since 1.0
          */
         public Builder withinRange(final int minimumCodePoint, final int maximumCodePoint) {
             if (minimumCodePoint > maximumCodePoint) {
                 throw new IllegalArgumentException(String.format(
-                        "Minimum code point %d is larger than maximum code point %d", minimumCodePoint, maximumCodePoint));
+                        "Minimum code point %d is larger than maximum code point %d",
+                        minimumCodePoint, maximumCodePoint));
             }
             if (minimumCodePoint < 0) {
-                throw new IllegalArgumentException(String.format("Minimum code point %d is negative", minimumCodePoint));
+                throw new IllegalArgumentException(
+                        String.format("Minimum code point %d is negative", minimumCodePoint));
             }
             if (maximumCodePoint > Character.MAX_CODE_POINT) {
                 throw new IllegalArgumentException(
@@ -251,23 +241,22 @@ public final class RandomStringGenerator {
             this.maximumCodePoint = maximumCodePoint;
             return this;
         }
-        
+
         /**
          * <p>
          * Limits the characters in the generated string to those that match at
          * least one of the predicates supplied.
          * </p>
-         * 
+         *
          * <p>
          * Passing {@code null} or an empty array to this method will revert to the
          * default behaviour of allowing any character. Multiple calls to this
          * method will replace the previously stored predicates.
          * </p>
-         * 
+         *
          * @param predicates
          *            the predicates, may be {@code null} or empty
          * @return {@code this}, to allow method chaining
-         * @since 1.0
          */
         public Builder filteredBy(final CharacterPredicate... predicates) {
             if (predicates == null || predicates.length == 0) {
@@ -287,7 +276,7 @@ public final class RandomStringGenerator {
 
             return this;
         }
-        
+
         /**
          * <p>
          * Overrides the default source of randomness.  It is highly
@@ -309,16 +298,15 @@ public final class RandomStringGenerator {
          *     .build();
          * }
          * </pre>
-         * 
+         *
          * <p>
          * Passing {@code null} to this method will revert to the default source of
          * randomness.
          * </p>
-         * 
+         *
          * @param random
          *            the source of randomness, may be {@code null}
          * @return {@code this}, to allow method chaining
-         * @since 1.0
          */
         public Builder usingRandom(final TextRandomProvider random) {
             this.random = random;
@@ -327,11 +315,11 @@ public final class RandomStringGenerator {
 
         /**
          * <p>Builds the {@code RandomStringGenerator} using the properties specified.</p>
+         * @return the configured {@code RandomStringGenerator}
          */
         @Override
         public RandomStringGenerator build() {
             return new RandomStringGenerator(minimumCodePoint, maximumCodePoint, inclusivePredicates, random);
         }
-        
     }
 }

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c72a24bc/src/main/java/org/apache/commons/text/TextRandomProvider.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/TextRandomProvider.java b/src/main/java/org/apache/commons/text/TextRandomProvider.java
index 4aecd72..98c5f2d 100644
--- a/src/main/java/org/apache/commons/text/TextRandomProvider.java
+++ b/src/main/java/org/apache/commons/text/TextRandomProvider.java
@@ -37,15 +37,15 @@ package org.apache.commons.text;
  *     .build();
  * }
  * </pre>
+ * @since 1.1
  */
 public interface TextRandomProvider {
 
     /**
-     * Generates an int value between 0 (inclusive) and the specified value 
+     * Generates an int value between 0 (inclusive) and the specified value
      * (exclusive).
      * @param max  Bound on the random number to be returned. Must be positive.
      * @return a random int value between 0 (inclusive) and n (exclusive).
-     * @throws IllegalArgumentException - if max is negative
      */
     int nextInt(int max);
 }

http://git-wip-us.apache.org/repos/asf/commons-text/blob/c72a24bc/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java b/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
index 0da2072..86537fa 100644
--- a/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
+++ b/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
@@ -25,10 +25,6 @@ import static org.junit.Assert.*;
  */
 public class RandomStringGeneratorTest {
 
-    private static int codePointLength(String s) {
-        return s.codePointCount(0, s.length());
-    }
-
     private static final CharacterPredicate A_FILTER = new CharacterPredicate() {
         @Override
         public boolean test(int codePoint) {
@@ -44,13 +40,17 @@ public class RandomStringGeneratorTest {
     };
 
     @Test(expected = IllegalArgumentException.class)
-    public void testInvalidLength() throws Exception {
+    public void testInvalidLength() {
         RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
         generator.generate(-1);
     }
 
+    private static int codePointLength(String s) {
+        return s.codePointCount(0, s.length());
+    }
+
     @Test
-    public void testSetLength() throws Exception {
+    public void testSetLength() {
         final int length = 99;
         RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
         String str = generator.generate(length);
@@ -58,34 +58,33 @@ public class RandomStringGeneratorTest {
     }
 
     @Test(expected = IllegalArgumentException.class)
-    public void testBadMinimumCodePoint() throws Exception {
+    public void testBadMinimumCodePoint() {
         new RandomStringGenerator.Builder().withinRange(-1, 1);
     }
 
     @Test(expected = IllegalArgumentException.class)
-    public void testBadMaximumCodePoint() throws Exception {
+    public void testBadMaximumCodePoint() {
         new RandomStringGenerator.Builder().withinRange(0, Character.MAX_CODE_POINT + 1);
     }
 
     @Test
-        public void testWithinRange() throws Exception {
-            final int length = 5000;
-            final int minimumCodePoint = 'a';
-            final int maximumCodePoint = 'z';
-            RandomStringGenerator generator = new RandomStringGenerator.Builder().withinRange(minimumCodePoint,maximumCodePoint).build();
-            String str = generator.generate(length);
-    
-            int i = 0;
-            do {
-                int codePoint = str.codePointAt(i);
-                assertTrue(codePoint >= minimumCodePoint && codePoint <= maximumCodePoint);
-                i += Character.charCount(codePoint);
-            } while (i < str.length());
-    
-        }
+    public void testWithinRange() {
+        final int length = 5000;
+        final int minimumCodePoint = 'a';
+        final int maximumCodePoint = 'z';
+        RandomStringGenerator generator = new RandomStringGenerator.Builder().withinRange(minimumCodePoint,maximumCodePoint).build();
+        String str = generator.generate(length);
+
+        int i = 0;
+        do {
+            int codePoint = str.codePointAt(i);
+            assertTrue(codePoint >= minimumCodePoint && codePoint <= maximumCodePoint);
+            i += Character.charCount(codePoint);
+        } while (i < str.length());
+    }
 
     @Test
-    public void testNoLoneSurrogates() throws Exception {
+    public void testNoLoneSurrogates() {
         final int length = 5000;
         String str = new RandomStringGenerator.Builder().build().generate(length);
 
@@ -111,10 +110,9 @@ public class RandomStringGeneratorTest {
     }
 
     @Test
-    public void testUsingRandom() throws Exception {
+    public void testUsingRandom() {
         final char testChar = 'a';
         final TextRandomProvider testRandom = new TextRandomProvider() {
-            private static final long serialVersionUID = 1L;
 
             @Override
             public int nextInt(int n) {
@@ -129,7 +127,7 @@ public class RandomStringGeneratorTest {
     }
 
     @Test
-    public void testMultipleFilters() throws Exception {
+    public void testMultipleFilters() {
         String str = new RandomStringGenerator.Builder().withinRange('a','d')
                 .filteredBy(A_FILTER, B_FILTER).build().generate(5000);
 
@@ -150,12 +148,11 @@ public class RandomStringGeneratorTest {
     }
 
     @Test
-    public void testNoPrivateCharacters() throws Exception {
+    public void testNoPrivateCharacters() {
         final int startOfPrivateBMPChars = 0xE000;
 
         // Request a string in an area of the Basic Multilingual Plane that is
-        // largely
-        // occupied by private characters
+        // largely occupied by private characters
         String str = new RandomStringGenerator.Builder().withinRange(startOfPrivateBMPChars, 
                 Character.MIN_SUPPLEMENTARY_CODE_POINT - 1).build().generate(5000);
 
@@ -173,8 +170,7 @@ public class RandomStringGeneratorTest {
     }
 
     @Test
-    public void testRemoveFilters() throws Exception {
-
+    public void testRemoveFilters() {
         RandomStringGenerator.Builder builder = new RandomStringGenerator.Builder().withinRange('a', 'z')
                 .filteredBy(A_FILTER);
 
@@ -192,7 +188,7 @@ public class RandomStringGeneratorTest {
     }
 
     @Test
-    public void testChangeOfFilter() throws Exception {
+    public void testChangeOfFilter() {
         RandomStringGenerator.Builder builder = new RandomStringGenerator.Builder().withinRange('a', 'z')
                 .filteredBy(A_FILTER);
         String str = builder.filteredBy(B_FILTER).build().generate(100);
@@ -201,9 +197,9 @@ public class RandomStringGeneratorTest {
             assertTrue(c == 'b');
         }
     }
-    
+
     @Test
-    public void testZeroLength() throws Exception {
+    public void testZeroLength() {
         RandomStringGenerator generator = new RandomStringGenerator.Builder().build();
         assertEquals("", generator.generate(0));
     }