You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by dj...@apache.org on 2016/12/27 08:45:33 UTC
[text] Rename RandomStringBuilder and make it immutable and
thread-safe.
Repository: commons-text
Updated Branches:
refs/heads/master 6f6da3467 -> 08ac56a50
Rename RandomStringBuilder and make it immutable and thread-safe.
The RandomStringBuilder class was renamed to RandomStringGenerator. The
class is now constructed using an inner Builder class, resulting in an
immutable and thread-safe generator. The default random generator is now
ThreadLocalRandom rather than Random.
The inner CodePointPredicate class was extracted into a separate class
and renamed to CharacterPredicate. The commonly used predicates are now
in a separate enum, CharacterPredicates.
Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/08ac56a5
Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/08ac56a5
Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/08ac56a5
Branch: refs/heads/master
Commit: 08ac56a502adb0d274d02f9d97f394e4a5c5966e
Parents: 6f6da34
Author: duncan <du...@wortharead.com>
Authored: Tue Dec 27 08:18:52 2016 +0000
Committer: duncan <du...@wortharead.com>
Committed: Tue Dec 27 08:42:48 2016 +0000
----------------------------------------------------------------------
.../apache/commons/text/CharacterPredicate.java | 37 ++
.../commons/text/CharacterPredicates.java | 52 +++
.../commons/text/RandomStringBuilder.java | 354 -------------------
.../commons/text/RandomStringGenerator.java | 316 +++++++++++++++++
.../commons/text/CharacterPredicatesTest.java | 50 +++
.../commons/text/RandomStringBuilderTest.java | 235 ------------
.../commons/text/RandomStringGeneratorTest.java | 206 +++++++++++
7 files changed, 661 insertions(+), 589 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/commons-text/blob/08ac56a5/src/main/java/org/apache/commons/text/CharacterPredicate.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/CharacterPredicate.java b/src/main/java/org/apache/commons/text/CharacterPredicate.java
new file mode 100644
index 0000000..fb23ac4
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/CharacterPredicate.java
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+/**
+ * A predicate for selecting code points. Implementations of this interface must
+ * be thread safe.
+ *
+ * @since 1.0
+ */
+public interface CharacterPredicate {
+
+ /**
+ * Tests the code point with this predicate.
+ *
+ * @param codePoint
+ * the code point to test
+ * @return {@code true} if the code point matches the predicate,
+ * {@code false} otherwise
+ * @since 1.0
+ */
+ boolean test(int codePoint);
+}
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/commons-text/blob/08ac56a5/src/main/java/org/apache/commons/text/CharacterPredicates.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/CharacterPredicates.java b/src/main/java/org/apache/commons/text/CharacterPredicates.java
new file mode 100644
index 0000000..7f38552
--- /dev/null
+++ b/src/main/java/org/apache/commons/text/CharacterPredicates.java
@@ -0,0 +1,52 @@
+/*
+ * 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>
+ * Commonly used implementations of {@link CharacterPredicate}. Per the interface
+ * requirements, all implementations are thread safe.
+ * </p>
+ *
+ * @since 1.0
+ */
+public enum CharacterPredicates implements CharacterPredicate {
+
+ /**
+ * Tests code points against {@link Character#isLetter(int)}
+ *
+ * @since 1.0
+ */
+ LETTERS {
+ @Override
+ public boolean test(int codePoint) {
+ return Character.isLetter(codePoint);
+ }
+ },
+
+ /**
+ * Tests code points against {@link Character#isDigit(int)}.
+ *
+ * @since 1.0
+ */
+ DIGITS {
+ @Override
+ public boolean test(int codePoint) {
+ return Character.isDigit(codePoint);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-text/blob/08ac56a5/src/main/java/org/apache/commons/text/RandomStringBuilder.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/apache/commons/text/RandomStringBuilder.java b/src/main/java/org/apache/commons/text/RandomStringBuilder.java
deleted file mode 100644
index 38ba974..0000000
--- a/src/main/java/org/apache/commons/text/RandomStringBuilder.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * 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;
-
-/**
- * <p>
- * Generates a random Unicode string based on properties defined using a builder
- * pattern.
- * </p>
- * <p>
- * Overriding the default properties is optional, however callers will need to
- * define the length of the output string using {@link #ofLength(int)} to avoid
- * generating an empty string.
- * </p>
- * <p>
- * All the property setting methods return the {@code RandomStringBuilder}
- * instance to allow for method chaining:
- * </p>
- *
- * <pre>
- * // Generates a 20 code point string, using only the letters a-z
- * String random = new RandomStringBuilder().ofLength(20).withinRange('a','z').build();
- * </pre>
- *
- * <p>
- * The type of code point returned can be filtered using
- * {@link #filteredBy(CodePointPredicate...)}, 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 (e.g. {@link #LETTERS} or
- * {@link #DIGITS}) and others can be created by implementing
- * {@link CodePointPredicate}.
- * </p>
- *
- * <pre>
- * // Generates a 10 code point string containing only letters
- *
- * import static org.apache.commons.text.RandomStringBuilder.LETTERS;
- * ...
- * String random = new RandomStringBuilder().ofLength(10).filteredBy(LETTERS).build();
- * </pre>
- *
- * <p>
- * A {@code RandomStringBuilder} instance can be used multiple times to generate
- * different random strings, however it cannot safely be shared between threads.
- * </p>
- *
- * @since 1.0
- */
-public class RandomStringBuilder implements Builder<String> {
-
- /**
- * Default source of randomness
- */
- private static final Random DEFAULT_RANDOM = new Random();
-
- /**
- * 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;
-
- /**
- * 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;
-
- private int length = 0;
- private int minimumCodePoint = 0;
- private int maximumCodePoint = Character.MAX_CODE_POINT;
- private Set<CodePointPredicate> inclusivePredicates = null;
- private Random random = null;
-
- /**
- * <p>
- * Constructs a builder with default properties:
- * </p>
- *
- * <ul>
- * <li>Length: {@value #DEFAULT_LENGTH}</li>
- * <li>Minimum code point: {@value #DEFAULT_MINIMUM_CODE_POINT}</li>
- * <li>Maximum code point: {@link Character#MAX_CODE_POINT}</li>
- * <li>Default source of randomness</li>
- * <li>No character filters</li>
- * </ul>
- *
- * @since 1.0
- */
- public RandomStringBuilder() {
- }
-
- /**
- * <p>
- * Specifies how many code points to generate in the random string.
- * </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 {@code this}, to allow method chaining
- * @throws IllegalArgumentException
- * if {@code length < 0}
- * @since 1.0
- */
- public RandomStringBuilder ofLength(final int length) {
- if (length < 0) {
- throw new IllegalArgumentException(String.format("Length %d is smaller than zero.", length));
- }
-
- this.length = length;
- return this;
- }
-
- /**
- * <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 RandomStringBuilder 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>
- * 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 RandomStringBuilder usingRandom(final Random random) {
- this.random = random;
- 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 RandomStringBuilder filteredBy(final CodePointPredicate... predicates) {
- if (predicates == null || predicates.length == 0) {
- inclusivePredicates = null;
- return this;
- }
-
- if (inclusivePredicates == null) {
- inclusivePredicates = new HashSet<>();
- } else {
- inclusivePredicates.clear();
- }
-
- for (CodePointPredicate predicate : predicates) {
- inclusivePredicates.add(predicate);
- }
-
- return this;
- }
-
- /**
- * <p>
- * Generates a random string using the settings defined in this builder.
- * Code points are randomly selected between the minimum and maximum values.
- * 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>
- * A static {@code Random} instance is used if an alternative wasn't
- * provided via {@link #usingRandom(Random)}.
- * </p>
- *
- * @return the randomly generated string
- * @since 1.0
- */
- @Override
- public String build() {
- if (length == 0) {
- return "";
- }
-
- if (random == null) {
- random = DEFAULT_RANDOM;
- }
-
- final StringBuilder builder = new StringBuilder(length);
- long remaining = length;
-
- do {
- int codePoint = random.nextInt(maximumCodePoint - minimumCodePoint + 1) + minimumCodePoint;
-
- switch (Character.getType(codePoint)) {
- case Character.UNASSIGNED:
- case Character.PRIVATE_USE:
- case Character.SURROGATE:
- continue;
- }
-
- if (inclusivePredicates != null) {
- boolean matchedFilter = false;
- for (CodePointPredicate predicate : inclusivePredicates) {
- if (predicate.test(codePoint)) {
- matchedFilter = true;
- break;
- }
- }
- if (!matchedFilter) {
- continue;
- }
- }
-
- builder.appendCodePoint(codePoint);
- remaining--;
-
- } while (remaining != 0);
-
- return builder.toString();
- }
-
- /**
- * A predicate for selecting code points.
- *
- * @since 1.0
- */
- public static interface CodePointPredicate {
- /**
- * Tests the code point with this predicate.
- *
- * @param codePoint
- * the code point to test
- * @return {@code true} if the code point matches the predicate,
- * {@code false} otherwise
- * @since 1.0
- */
- boolean test(int codePoint);
- }
-
- /**
- * Tests code points against {@link Character#isLetter(int)}.
- *
- * @since 1.0
- */
- public static final CodePointPredicate LETTERS = new LetterPredicate();
-
- /**
- * Tests code points against {@link Character#isDigit(int)}.
- *
- * @since 1.0
- */
- public static final CodePointPredicate DIGITS = new DigitPredicate();
-
- /**
- * Tests whether code points are letters.
- */
- private static final class LetterPredicate implements CodePointPredicate {
- @Override
- public boolean test(int codePoint) {
- return Character.isLetter(codePoint);
- }
- }
-
- /**
- * Tests whether code points are digits.
- */
- private static final class DigitPredicate implements CodePointPredicate {
- @Override
- public boolean test(int codePoint) {
- return Character.isDigit(codePoint);
- }
- };
-}
http://git-wip-us.apache.org/repos/asf/commons-text/blob/08ac56a5/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/08ac56a5/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java b/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
new file mode 100644
index 0000000..3ff8b74
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
@@ -0,0 +1,50 @@
+/*
+ * 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.assertTrue;
+
+import org.junit.Test;
+
+/**
+ * Tests for implementations in the {@link CharacterPredicates} enum.
+ */
+public class CharacterPredicatesTest {
+ @Test
+ public void testDigitPredicate() throws Exception {
+ String str = new RandomStringGenerator.Builder().filteredBy(CharacterPredicates.DIGITS).build().generate(5000);
+
+ int i = 0;
+ do {
+ int codePoint = str.codePointAt(i);
+ assertTrue(Character.isDigit(codePoint));
+ i += Character.charCount(codePoint);
+ } while (i < str.length());
+ }
+
+ @Test
+ public void testLetterPredicate() throws Exception {
+ String str = new RandomStringGenerator.Builder().filteredBy(CharacterPredicates.LETTERS).build().generate(5000);
+
+ int i = 0;
+ do {
+ int codePoint = str.codePointAt(i);
+ assertTrue(Character.isLetter(codePoint));
+ i += Character.charCount(codePoint);
+ } while (i < str.length());
+ }
+}
http://git-wip-us.apache.org/repos/asf/commons-text/blob/08ac56a5/src/test/java/org/apache/commons/text/RandomStringBuilderTest.java
----------------------------------------------------------------------
diff --git a/src/test/java/org/apache/commons/text/RandomStringBuilderTest.java b/src/test/java/org/apache/commons/text/RandomStringBuilderTest.java
deleted file mode 100644
index e6f9f81..0000000
--- a/src/test/java/org/apache/commons/text/RandomStringBuilderTest.java
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * 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.apache.commons.text.RandomStringBuilder.LETTERS;
-import static org.junit.Assert.*;
-
-import java.util.Random;
-
-import org.apache.commons.text.RandomStringBuilder.CodePointPredicate;
-import org.junit.Test;
-
-/**
- * Tests for {@link RandomStringBuilder}
- */
-public class RandomStringBuilderTest {
-
- private static int codePointLength(String s) {
- return s.codePointCount(0, s.length());
- }
-
- private static final CodePointPredicate A_FILTER = new CodePointPredicate() {
- @Override
- public boolean test(int codePoint) {
- return codePoint == 'a';
- }
- };
-
- private static final CodePointPredicate B_FILTER = new CodePointPredicate() {
- @Override
- public boolean test(int codePoint) {
- return codePoint == 'b';
- }
- };
-
- @Test
- public void testDefaultLength() throws Exception {
- String str = new RandomStringBuilder().build();
- assertEquals(RandomStringBuilder.DEFAULT_LENGTH, codePointLength(str));
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testInvalidLength() throws Exception {
- new RandomStringBuilder().ofLength(-1);
- }
-
- @Test
- public void testSetLength() throws Exception {
- final int length = 99;
- String str = new RandomStringBuilder().ofLength(length).build();
- assertEquals(length, codePointLength(str));
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testBadMinimumCodePoint() throws Exception {
- new RandomStringBuilder().withinRange(-1, 1);
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void testBadMaximumCodePoint() throws Exception {
- new RandomStringBuilder().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';
- String str = new RandomStringBuilder().ofLength(length).withinRange(minimumCodePoint,maximumCodePoint).build();
-
- 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 RandomStringBuilder().ofLength(length).build();
-
- 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 RandomStringBuilder().ofLength(100).usingRandom(testRandom).build();
- for (char c : str.toCharArray()) {
- assertEquals(testChar, c);
- }
- }
-
- @Test
- public void testLetterPredicate() throws Exception {
- String str = new RandomStringBuilder().ofLength(5000).filteredBy(LETTERS).build();
-
- int i = 0;
- do {
- int codePoint = str.codePointAt(i);
- assertTrue(Character.isLetter(codePoint));
- i += Character.charCount(codePoint);
- } while (i < str.length());
- }
-
- @Test
- public void testDigitPredicate() throws Exception {
- String str = new RandomStringBuilder().ofLength(5000).filteredBy(RandomStringBuilder.DIGITS).build();
-
- int i = 0;
- do {
- int codePoint = str.codePointAt(i);
- assertTrue(Character.isDigit(codePoint));
- i += Character.charCount(codePoint);
- } while (i < str.length());
- }
-
- @Test
- public void testMultipleFilters() throws Exception {
- String str = new RandomStringBuilder().ofLength(5000).withinRange('a','d')
- .filteredBy(A_FILTER, B_FILTER).build();
-
- 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 RandomStringBuilder().ofLength(5000).withinRange(startOfPrivateBMPChars,
- Character.MIN_SUPPLEMENTARY_CODE_POINT - 1).build();
-
- 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 RandomStringBuilder().withinRange(2, 1);
- }
-
- @Test
- public void testRemoveFilters() throws Exception {
-
- RandomStringBuilder builder = new RandomStringBuilder().ofLength(100).withinRange('a', 'z')
- .filteredBy(A_FILTER);
-
- builder.filteredBy();
-
- String str = builder.build();
- 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 {
- RandomStringBuilder builder = new RandomStringBuilder().ofLength(100).withinRange('a', 'z')
- .filteredBy(A_FILTER);
- String str = builder.filteredBy(B_FILTER).build();
-
- for (char c : str.toCharArray()) {
- assertTrue(c == 'b');
- }
- }
-}
http://git-wip-us.apache.org/repos/asf/commons-text/blob/08ac56a5/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..2ff7a67
--- /dev/null
+++ b/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
@@ -0,0 +1,206 @@
+/*
+ * 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');
+ }
+ }
+}
Re: [text] Rename RandomStringBuilder and make it immutable and
thread-safe.
Posted by Duncan Jones <du...@wortharead.com>.
> On 27 Dec 2016, at 08:45, djones@apache.org wrote:
>
> Repository: commons-text
> Updated Branches:
> refs/heads/master 6f6da3467 -> 08ac56a50
>
>
> Rename RandomStringBuilder and make it immutable and thread-safe.
>
> The RandomStringBuilder class was renamed to RandomStringGenerator. The
> class is now constructed using an inner Builder class, resulting in an
> immutable and thread-safe generator. The default random generator is now
> ThreadLocalRandom rather than Random.
>
> The inner CodePointPredicate class was extracted into a separate class
> and renamed to CharacterPredicate. The commonly used predicates are now
> in a separate enum, CharacterPredicates.
>
> Project: http://git-wip-us.apache.org/repos/asf/commons-text/repo
> Commit: http://git-wip-us.apache.org/repos/asf/commons-text/commit/08ac56a5
> Tree: http://git-wip-us.apache.org/repos/asf/commons-text/tree/08ac56a5
> Diff: http://git-wip-us.apache.org/repos/asf/commons-text/diff/08ac56a5
>
> Branch: refs/heads/master
> Commit: 08ac56a502adb0d274d02f9d97f394e4a5c5966e
> Parents: 6f6da34
> Author: duncan <du...@wortharead.com>
> Authored: Tue Dec 27 08:18:52 2016 +0000
> Committer: duncan <du...@wortharead.com>
> Committed: Tue Dec 27 08:42:48 2016 +0000
>
> ----------------------------------------------------------------------
> .../apache/commons/text/CharacterPredicate.java | 37 ++
> .../commons/text/CharacterPredicates.java | 52 +++
> .../commons/text/RandomStringBuilder.java | 354 -------------------
> .../commons/text/RandomStringGenerator.java | 316 +++++++++++++++++
> .../commons/text/CharacterPredicatesTest.java | 50 +++
> .../commons/text/RandomStringBuilderTest.java | 235 ------------
> .../commons/text/RandomStringGeneratorTest.java | 206 +++++++++++
> 7 files changed, 661 insertions(+), 589 deletions(-)
> ———————————————————————————————————
Apologies, should have split this into multiple commits but I got too far into it before I reached that conclusion!
>
>
> http://git-wip-us.apache.org/repos/asf/commons-text/blob/08ac56a5/src/main/java/org/apache/commons/text/CharacterPredicate.java
> ----------------------------------------------------------------------
> diff --git a/src/main/java/org/apache/commons/text/CharacterPredicate.java b/src/main/java/org/apache/commons/text/CharacterPredicate.java
> new file mode 100644
> index 0000000..fb23ac4
> --- /dev/null
> +++ b/src/main/java/org/apache/commons/text/CharacterPredicate.java
> @@ -0,0 +1,37 @@
> +/*
> + * 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;
> +
> +/**
> + * A predicate for selecting code points. Implementations of this interface must
> + * be thread safe.
> + *
> + * @since 1.0
> + */
> +public interface CharacterPredicate {
> +
> + /**
> + * Tests the code point with this predicate.
> + *
> + * @param codePoint
> + * the code point to test
> + * @return {@code true} if the code point matches the predicate,
> + * {@code false} otherwise
> + * @since 1.0
> + */
> + boolean test(int codePoint);
> +}
> \ No newline at end of file
>
> http://git-wip-us.apache.org/repos/asf/commons-text/blob/08ac56a5/src/main/java/org/apache/commons/text/CharacterPredicates.java
> ----------------------------------------------------------------------
> diff --git a/src/main/java/org/apache/commons/text/CharacterPredicates.java b/src/main/java/org/apache/commons/text/CharacterPredicates.java
> new file mode 100644
> index 0000000..7f38552
> --- /dev/null
> +++ b/src/main/java/org/apache/commons/text/CharacterPredicates.java
> @@ -0,0 +1,52 @@
> +/*
> + * 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>
> + * Commonly used implementations of {@link CharacterPredicate}. Per the interface
> + * requirements, all implementations are thread safe.
> + * </p>
> + *
> + * @since 1.0
> + */
> +public enum CharacterPredicates implements CharacterPredicate {
> +
> + /**
> + * Tests code points against {@link Character#isLetter(int)}
> + *
> + * @since 1.0
> + */
> + LETTERS {
> + @Override
> + public boolean test(int codePoint) {
> + return Character.isLetter(codePoint);
> + }
> + },
> +
> + /**
> + * Tests code points against {@link Character#isDigit(int)}.
> + *
> + * @since 1.0
> + */
> + DIGITS {
> + @Override
> + public boolean test(int codePoint) {
> + return Character.isDigit(codePoint);
> + }
> + }
> +}
>
> http://git-wip-us.apache.org/repos/asf/commons-text/blob/08ac56a5/src/main/java/org/apache/commons/text/RandomStringBuilder.java
> ----------------------------------------------------------------------
> diff --git a/src/main/java/org/apache/commons/text/RandomStringBuilder.java b/src/main/java/org/apache/commons/text/RandomStringBuilder.java
> deleted file mode 100644
> index 38ba974..0000000
> --- a/src/main/java/org/apache/commons/text/RandomStringBuilder.java
> +++ /dev/null
> @@ -1,354 +0,0 @@
> -/*
> - * 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;
> -
> -/**
> - * <p>
> - * Generates a random Unicode string based on properties defined using a builder
> - * pattern.
> - * </p>
> - * <p>
> - * Overriding the default properties is optional, however callers will need to
> - * define the length of the output string using {@link #ofLength(int)} to avoid
> - * generating an empty string.
> - * </p>
> - * <p>
> - * All the property setting methods return the {@code RandomStringBuilder}
> - * instance to allow for method chaining:
> - * </p>
> - *
> - * <pre>
> - * // Generates a 20 code point string, using only the letters a-z
> - * String random = new RandomStringBuilder().ofLength(20).withinRange('a','z').build();
> - * </pre>
> - *
> - * <p>
> - * The type of code point returned can be filtered using
> - * {@link #filteredBy(CodePointPredicate...)}, 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 (e.g. {@link #LETTERS} or
> - * {@link #DIGITS}) and others can be created by implementing
> - * {@link CodePointPredicate}.
> - * </p>
> - *
> - * <pre>
> - * // Generates a 10 code point string containing only letters
> - *
> - * import static org.apache.commons.text.RandomStringBuilder.LETTERS;
> - * ...
> - * String random = new RandomStringBuilder().ofLength(10).filteredBy(LETTERS).build();
> - * </pre>
> - *
> - * <p>
> - * A {@code RandomStringBuilder} instance can be used multiple times to generate
> - * different random strings, however it cannot safely be shared between threads.
> - * </p>
> - *
> - * @since 1.0
> - */
> -public class RandomStringBuilder implements Builder<String> {
> -
> - /**
> - * Default source of randomness
> - */
> - private static final Random DEFAULT_RANDOM = new Random();
> -
> - /**
> - * 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;
> -
> - /**
> - * 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;
> -
> - private int length = 0;
> - private int minimumCodePoint = 0;
> - private int maximumCodePoint = Character.MAX_CODE_POINT;
> - private Set<CodePointPredicate> inclusivePredicates = null;
> - private Random random = null;
> -
> - /**
> - * <p>
> - * Constructs a builder with default properties:
> - * </p>
> - *
> - * <ul>
> - * <li>Length: {@value #DEFAULT_LENGTH}</li>
> - * <li>Minimum code point: {@value #DEFAULT_MINIMUM_CODE_POINT}</li>
> - * <li>Maximum code point: {@link Character#MAX_CODE_POINT}</li>
> - * <li>Default source of randomness</li>
> - * <li>No character filters</li>
> - * </ul>
> - *
> - * @since 1.0
> - */
> - public RandomStringBuilder() {
> - }
> -
> - /**
> - * <p>
> - * Specifies how many code points to generate in the random string.
> - * </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 {@code this}, to allow method chaining
> - * @throws IllegalArgumentException
> - * if {@code length < 0}
> - * @since 1.0
> - */
> - public RandomStringBuilder ofLength(final int length) {
> - if (length < 0) {
> - throw new IllegalArgumentException(String.format("Length %d is smaller than zero.", length));
> - }
> -
> - this.length = length;
> - return this;
> - }
> -
> - /**
> - * <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 RandomStringBuilder 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>
> - * 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 RandomStringBuilder usingRandom(final Random random) {
> - this.random = random;
> - 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 RandomStringBuilder filteredBy(final CodePointPredicate... predicates) {
> - if (predicates == null || predicates.length == 0) {
> - inclusivePredicates = null;
> - return this;
> - }
> -
> - if (inclusivePredicates == null) {
> - inclusivePredicates = new HashSet<>();
> - } else {
> - inclusivePredicates.clear();
> - }
> -
> - for (CodePointPredicate predicate : predicates) {
> - inclusivePredicates.add(predicate);
> - }
> -
> - return this;
> - }
> -
> - /**
> - * <p>
> - * Generates a random string using the settings defined in this builder.
> - * Code points are randomly selected between the minimum and maximum values.
> - * 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>
> - * A static {@code Random} instance is used if an alternative wasn't
> - * provided via {@link #usingRandom(Random)}.
> - * </p>
> - *
> - * @return the randomly generated string
> - * @since 1.0
> - */
> - @Override
> - public String build() {
> - if (length == 0) {
> - return "";
> - }
> -
> - if (random == null) {
> - random = DEFAULT_RANDOM;
> - }
> -
> - final StringBuilder builder = new StringBuilder(length);
> - long remaining = length;
> -
> - do {
> - int codePoint = random.nextInt(maximumCodePoint - minimumCodePoint + 1) + minimumCodePoint;
> -
> - switch (Character.getType(codePoint)) {
> - case Character.UNASSIGNED:
> - case Character.PRIVATE_USE:
> - case Character.SURROGATE:
> - continue;
> - }
> -
> - if (inclusivePredicates != null) {
> - boolean matchedFilter = false;
> - for (CodePointPredicate predicate : inclusivePredicates) {
> - if (predicate.test(codePoint)) {
> - matchedFilter = true;
> - break;
> - }
> - }
> - if (!matchedFilter) {
> - continue;
> - }
> - }
> -
> - builder.appendCodePoint(codePoint);
> - remaining--;
> -
> - } while (remaining != 0);
> -
> - return builder.toString();
> - }
> -
> - /**
> - * A predicate for selecting code points.
> - *
> - * @since 1.0
> - */
> - public static interface CodePointPredicate {
> - /**
> - * Tests the code point with this predicate.
> - *
> - * @param codePoint
> - * the code point to test
> - * @return {@code true} if the code point matches the predicate,
> - * {@code false} otherwise
> - * @since 1.0
> - */
> - boolean test(int codePoint);
> - }
> -
> - /**
> - * Tests code points against {@link Character#isLetter(int)}.
> - *
> - * @since 1.0
> - */
> - public static final CodePointPredicate LETTERS = new LetterPredicate();
> -
> - /**
> - * Tests code points against {@link Character#isDigit(int)}.
> - *
> - * @since 1.0
> - */
> - public static final CodePointPredicate DIGITS = new DigitPredicate();
> -
> - /**
> - * Tests whether code points are letters.
> - */
> - private static final class LetterPredicate implements CodePointPredicate {
> - @Override
> - public boolean test(int codePoint) {
> - return Character.isLetter(codePoint);
> - }
> - }
> -
> - /**
> - * Tests whether code points are digits.
> - */
> - private static final class DigitPredicate implements CodePointPredicate {
> - @Override
> - public boolean test(int codePoint) {
> - return Character.isDigit(codePoint);
> - }
> - };
> -}
>
> http://git-wip-us.apache.org/repos/asf/commons-text/blob/08ac56a5/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/08ac56a5/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
> ----------------------------------------------------------------------
> diff --git a/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java b/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
> new file mode 100644
> index 0000000..3ff8b74
> --- /dev/null
> +++ b/src/test/java/org/apache/commons/text/CharacterPredicatesTest.java
> @@ -0,0 +1,50 @@
> +/*
> + * 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.assertTrue;
> +
> +import org.junit.Test;
> +
> +/**
> + * Tests for implementations in the {@link CharacterPredicates} enum.
> + */
> +public class CharacterPredicatesTest {
> + @Test
> + public void testDigitPredicate() throws Exception {
> + String str = new RandomStringGenerator.Builder().filteredBy(CharacterPredicates.DIGITS).build().generate(5000);
> +
> + int i = 0;
> + do {
> + int codePoint = str.codePointAt(i);
> + assertTrue(Character.isDigit(codePoint));
> + i += Character.charCount(codePoint);
> + } while (i < str.length());
> + }
> +
> + @Test
> + public void testLetterPredicate() throws Exception {
> + String str = new RandomStringGenerator.Builder().filteredBy(CharacterPredicates.LETTERS).build().generate(5000);
> +
> + int i = 0;
> + do {
> + int codePoint = str.codePointAt(i);
> + assertTrue(Character.isLetter(codePoint));
> + i += Character.charCount(codePoint);
> + } while (i < str.length());
> + }
> +}
>
> http://git-wip-us.apache.org/repos/asf/commons-text/blob/08ac56a5/src/test/java/org/apache/commons/text/RandomStringBuilderTest.java
> ----------------------------------------------------------------------
> diff --git a/src/test/java/org/apache/commons/text/RandomStringBuilderTest.java b/src/test/java/org/apache/commons/text/RandomStringBuilderTest.java
> deleted file mode 100644
> index e6f9f81..0000000
> --- a/src/test/java/org/apache/commons/text/RandomStringBuilderTest.java
> +++ /dev/null
> @@ -1,235 +0,0 @@
> -/*
> - * 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.apache.commons.text.RandomStringBuilder.LETTERS;
> -import static org.junit.Assert.*;
> -
> -import java.util.Random;
> -
> -import org.apache.commons.text.RandomStringBuilder.CodePointPredicate;
> -import org.junit.Test;
> -
> -/**
> - * Tests for {@link RandomStringBuilder}
> - */
> -public class RandomStringBuilderTest {
> -
> - private static int codePointLength(String s) {
> - return s.codePointCount(0, s.length());
> - }
> -
> - private static final CodePointPredicate A_FILTER = new CodePointPredicate() {
> - @Override
> - public boolean test(int codePoint) {
> - return codePoint == 'a';
> - }
> - };
> -
> - private static final CodePointPredicate B_FILTER = new CodePointPredicate() {
> - @Override
> - public boolean test(int codePoint) {
> - return codePoint == 'b';
> - }
> - };
> -
> - @Test
> - public void testDefaultLength() throws Exception {
> - String str = new RandomStringBuilder().build();
> - assertEquals(RandomStringBuilder.DEFAULT_LENGTH, codePointLength(str));
> - }
> -
> - @Test(expected = IllegalArgumentException.class)
> - public void testInvalidLength() throws Exception {
> - new RandomStringBuilder().ofLength(-1);
> - }
> -
> - @Test
> - public void testSetLength() throws Exception {
> - final int length = 99;
> - String str = new RandomStringBuilder().ofLength(length).build();
> - assertEquals(length, codePointLength(str));
> - }
> -
> - @Test(expected = IllegalArgumentException.class)
> - public void testBadMinimumCodePoint() throws Exception {
> - new RandomStringBuilder().withinRange(-1, 1);
> - }
> -
> - @Test(expected = IllegalArgumentException.class)
> - public void testBadMaximumCodePoint() throws Exception {
> - new RandomStringBuilder().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';
> - String str = new RandomStringBuilder().ofLength(length).withinRange(minimumCodePoint,maximumCodePoint).build();
> -
> - 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 RandomStringBuilder().ofLength(length).build();
> -
> - 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 RandomStringBuilder().ofLength(100).usingRandom(testRandom).build();
> - for (char c : str.toCharArray()) {
> - assertEquals(testChar, c);
> - }
> - }
> -
> - @Test
> - public void testLetterPredicate() throws Exception {
> - String str = new RandomStringBuilder().ofLength(5000).filteredBy(LETTERS).build();
> -
> - int i = 0;
> - do {
> - int codePoint = str.codePointAt(i);
> - assertTrue(Character.isLetter(codePoint));
> - i += Character.charCount(codePoint);
> - } while (i < str.length());
> - }
> -
> - @Test
> - public void testDigitPredicate() throws Exception {
> - String str = new RandomStringBuilder().ofLength(5000).filteredBy(RandomStringBuilder.DIGITS).build();
> -
> - int i = 0;
> - do {
> - int codePoint = str.codePointAt(i);
> - assertTrue(Character.isDigit(codePoint));
> - i += Character.charCount(codePoint);
> - } while (i < str.length());
> - }
> -
> - @Test
> - public void testMultipleFilters() throws Exception {
> - String str = new RandomStringBuilder().ofLength(5000).withinRange('a','d')
> - .filteredBy(A_FILTER, B_FILTER).build();
> -
> - 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 RandomStringBuilder().ofLength(5000).withinRange(startOfPrivateBMPChars,
> - Character.MIN_SUPPLEMENTARY_CODE_POINT - 1).build();
> -
> - 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 RandomStringBuilder().withinRange(2, 1);
> - }
> -
> - @Test
> - public void testRemoveFilters() throws Exception {
> -
> - RandomStringBuilder builder = new RandomStringBuilder().ofLength(100).withinRange('a', 'z')
> - .filteredBy(A_FILTER);
> -
> - builder.filteredBy();
> -
> - String str = builder.build();
> - 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 {
> - RandomStringBuilder builder = new RandomStringBuilder().ofLength(100).withinRange('a', 'z')
> - .filteredBy(A_FILTER);
> - String str = builder.filteredBy(B_FILTER).build();
> -
> - for (char c : str.toCharArray()) {
> - assertTrue(c == 'b');
> - }
> - }
> -}
>
> http://git-wip-us.apache.org/repos/asf/commons-text/blob/08ac56a5/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..2ff7a67
> --- /dev/null
> +++ b/src/test/java/org/apache/commons/text/RandomStringGeneratorTest.java
> @@ -0,0 +1,206 @@
> +/*
> + * 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');
> + }
> + }
> +}
>
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org