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));
}