diff --git a/src/main/java/org/apache/commons/lang3/RandomStringUtils.java b/src/main/java/org/apache/commons/lang3/RandomStringUtils.java index eb6615e75..d64ec5ebf 100644 --- a/src/main/java/org/apache/commons/lang3/RandomStringUtils.java +++ b/src/main/java/org/apache/commons/lang3/RandomStringUtils.java @@ -16,201 +16,212 @@ */ package org.apache.commons.lang3; -import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; +import java.security.Security; import java.util.Random; import java.util.concurrent.ThreadLocalRandom; - -import org.apache.commons.lang3.exception.UncheckedException; +import java.util.function.Supplier; /** * Generates random {@link String}s. *
- * Starting in version 3.15.0, this classes uses {@link SecureRandom#getInstanceStrong()}. + * Starting in version 3.16.0, this class uses {@link #secure()} for static methods and adds {@link #insecure()}. *
*- * Before version 3.15.0, this classes used {@link ThreadLocalRandom#current()}, which was NOT cryptographically secure. + * Starting in version 3.15.0, this class uses {@link SecureRandom#getInstanceStrong()} for static methods. + *
+ *+ * Before version 3.15.0, this class used {@link ThreadLocalRandom#current()} for static methods, which is not + * cryptographically secure. + *
+ *+ * Use {@link #secure()} to get the singleton instance based on {@link SecureRandom#getInstanceStrong()} which uses an + * algorithms/providers specified in the {@code securerandom.strongAlgorithms} {@link Security} property. + *
+ *+ * Use {@link #insecure()} to get the singleton instance based on {@link ThreadLocalRandom#current()}; which is not + * cryptographically secure. *
** RandomStringUtils is intended for simple use cases. For more advanced use cases consider using Apache Commons Text's - * RandomStringGenerator - * instead. + * + * RandomStringGenerator instead. *
*- * The Apache Commons project provides Commons RNG dedicated to pseudo-random number generation, - * that may be a better choice for applications with more stringent requirements (performance and/or correctness). + * The Apache Commons project provides Commons RNG + * dedicated to pseudo-random number generation, that may be a better choice for applications with more stringent + * requirements (performance and/or correctness). *
*- * Note that private high surrogate characters are ignored. These are Unicode characters that fall between the values 56192 (db80) and 56319 (dbff) as - * we don't know how to handle them. High and low surrogates are correctly dealt with - that is if a high surrogate is randomly chosen, 55296 (d800) to 56191 - * (db7f) then it is followed by a low surrogate. If a low surrogate is chosen, 56320 (dc00) to 57343 (dfff) then it is placed after a randomly chosen high + * Note that private high surrogate characters are ignored. These are Unicode characters that fall between the + * values 56192 (db80) and 56319 (dbff) as we don't know how to handle them. High and low surrogates are correctly dealt + * with - that is if a high surrogate is randomly chosen, 55296 (d800) to 56191 (db7f) then it is followed by a low + * surrogate. If a low surrogate is chosen, 56320 (dc00) to 57343 (dfff) then it is placed after a randomly chosen high * surrogate. *
** #ThreadSafe# *
* + * @see RandomUtils * @since 1.0 */ public class RandomStringUtils { - private static final ThreadLocal+ * The method {@link ThreadLocalRandom#current()} is called on-demand. + *
* - *Characters will be chosen from the set of all characters.
+ * @return the singleton instance based on {@link ThreadLocalRandom#current()}. + * @see ThreadLocalRandom#current() + * @see #secure() + * @since 3.16.0 + */ + public static RandomStringUtils insecure() { + return INSECURE; + } + + /** + * Creates a random string whose length is the number of characters specified. * - * @param count the length of random string to create + *+ * Characters will be chosen from the set of all characters. + *
+ * + * @param count the length of random string to create * @return the random string * @throws IllegalArgumentException if {@code count} < 0. */ public static String random(final int count) { - return random(count, false, false); + return secure().next(count); } /** - * Creates a random string whose length is the number of characters - * specified. + * Creates a random string whose length is the number of characters specified. * - *Characters will be chosen from the set of alpha-numeric - * characters as indicated by the arguments.
+ *+ * Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments. + *
* - * @param count the length of random string to create - * @param letters if {@code true}, generated string may include - * alphabetic characters - * @param numbers if {@code true}, generated string may include - * numeric characters + * @param count the length of random string to create + * @param letters if {@code true}, generated string may include alphabetic characters + * @param numbers if {@code true}, generated string may include numeric characters * @return the random string * @throws IllegalArgumentException if {@code count} < 0. */ public static String random(final int count, final boolean letters, final boolean numbers) { - return random(count, 0, 0, letters, numbers); + return secure().next(count, letters, numbers); } /** - * Creates a random string whose length is the number of characters - * specified. + * Creates a random string whose length is the number of characters specified. * - *Characters will be chosen from the set of characters specified.
+ *+ * Characters will be chosen from the set of characters specified. + *
* - * @param count the length of random string to create - * @param chars the character array containing the set of characters to use, - * may be null + * @param count the length of random string to create + * @param chars the character array containing the set of characters to use, may be null * @return the random string * @throws IllegalArgumentException if {@code count} < 0. */ public static String random(final int count, final char... chars) { - if (chars == null) { - return random(count, 0, 0, false, false, null, random()); - } - return random(count, 0, chars.length, false, false, chars, random()); + return secure().next(count, chars); } /** - * Creates a random string whose length is the number of characters - * specified. + * Creates a random string whose length is the number of characters specified. * - *Characters will be chosen from the set of alpha-numeric - * characters as indicated by the arguments.
+ *+ * Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments. + *
* - * @param count the length of random string to create - * @param start the position in set of chars to start at - * @param end the position in set of chars to end before - * @param letters if {@code true}, generated string may include - * alphabetic characters - * @param numbers if {@code true}, generated string may include - * numeric characters + * @param count the length of random string to create + * @param start the position in set of chars to start at + * @param end the position in set of chars to end before + * @param letters if {@code true}, generated string may include alphabetic characters + * @param numbers if {@code true}, generated string may include numeric characters * @return the random string * @throws IllegalArgumentException if {@code count} < 0. */ - public static String random(final int count, final int start, final int end, final boolean letters, final boolean numbers) { - return random(count, start, end, letters, numbers, null, random()); + public static String random(final int count, final int start, final int end, final boolean letters, + final boolean numbers) { + return secure().next(count, start, end, letters, numbers); } /** - * Creates a random string based on a variety of options, using - * default source of randomness. + * Creates a random string based on a variety of options, using default source of randomness. * - *This method has exactly the same semantics as - * {@link #random(int,int,int,boolean,boolean,char[],Random)}, but - * instead of using an externally supplied source of randomness, it uses - * the internal static {@link Random} instance.
+ *+ * This method has exactly the same semantics as {@link #random(int,int,int,boolean,boolean,char[],Random)}, but + * instead of using an externally supplied source of randomness, it uses the internal static {@link Random} + * instance. + *
* - * @param count the length of random string to create - * @param start the position in set of chars to start at - * @param end the position in set of chars to end before - * @param letters if {@code true}, generated string may include - * alphabetic characters - * @param numbers if {@code true}, generated string may include - * numeric characters - * @param chars the set of chars to choose randoms from. - * If {@code null}, then it will use the set of all chars. + * @param count the length of random string to create + * @param start the position in set of chars to start at + * @param end the position in set of chars to end before + * @param letters if {@code true}, generated string may include alphabetic characters + * @param numbers if {@code true}, generated string may include numeric characters + * @param chars the set of chars to choose randoms from. If {@code null}, then it will use the set of all chars. * @return the random string - * @throws ArrayIndexOutOfBoundsException if there are not - * {@code (end - start) + 1} characters in the set array. - * @throws IllegalArgumentException if {@code count} < 0. + * @throws ArrayIndexOutOfBoundsException if there are not {@code (end - start) + 1} characters in the set array. + * @throws IllegalArgumentException if {@code count} < 0. */ - public static String random(final int count, final int start, final int end, final boolean letters, final boolean numbers, final char... chars) { - return random(count, start, end, letters, numbers, chars, random()); + public static String random(final int count, final int start, final int end, final boolean letters, + final boolean numbers, final char... chars) { + return secure().next(count, start, end, letters, numbers, chars); } /** - * Creates a random string based on a variety of options, using - * supplied source of randomness. + * Creates a random string based on a variety of options, using supplied source of randomness. * - *If start and end are both {@code 0}, start and end are set - * to {@code ' '} and {@code 'z'}, the ASCII printable - * characters, will be used, unless letters and numbers are both - * {@code false}, in which case, start and end are set to - * {@code 0} and {@link Character#MAX_CODE_POINT}. + *
+ * If start and end are both {@code 0}, start and end are set to {@code ' '} and {@code 'z'}, the ASCII printable + * characters, will be used, unless letters and numbers are both {@code false}, in which case, start and end are set + * to {@code 0} and {@link Character#MAX_CODE_POINT}. * - *
If set is not {@code null}, characters between start and - * end are chosen.
+ *+ * If set is not {@code null}, characters between start and end are chosen. + *
* - *This method accepts a user-supplied {@link Random} - * instance to use as a source of randomness. By seeding a single - * {@link Random} instance with a fixed seed and using it for each call, - * the same random sequence of strings can be generated repeatedly - * and predictably.
+ *+ * This method accepts a user-supplied {@link Random} instance to use as a source of randomness. By seeding a single + * {@link Random} instance with a fixed seed and using it for each call, the same random sequence of strings can be + * generated repeatedly and predictably. + *
* - * @param count the length of random string to create - * @param start the position in set of chars to start at (inclusive) - * @param end the position in set of chars to end before (exclusive) - * @param letters if {@code true}, generated string may include - * alphabetic characters - * @param numbers if {@code true}, generated string may include - * numeric characters - * @param chars the set of chars to choose randoms from, must not be empty. - * If {@code null}, then it will use the set of all chars. + * @param count the length of random string to create + * @param start the position in set of chars to start at (inclusive) + * @param end the position in set of chars to end before (exclusive) + * @param letters if {@code true}, generated string may include alphabetic characters + * @param numbers if {@code true}, generated string may include numeric characters + * @param chars the set of chars to choose randoms from, must not be empty. If {@code null}, then it will use the + * set of all chars. * @param random a source of randomness. * @return the random string - * @throws ArrayIndexOutOfBoundsException if there are not - * {@code (end - start) + 1} characters in the set array. - * @throws IllegalArgumentException if {@code count} < 0 or the provided chars array is empty. + * @throws ArrayIndexOutOfBoundsException if there are not {@code (end - start) + 1} characters in the set array. + * @throws IllegalArgumentException if {@code count} < 0 or the provided chars array is empty. * @since 2.0 */ public static String random(int count, int start, int end, final boolean letters, final boolean numbers, - final char[] chars, final Random random) { + final char[] chars, final Random random) { if (count == 0) { return StringUtils.EMPTY; } @@ -231,7 +242,8 @@ public class RandomStringUtils { start = ' '; } } else if (end <= start) { - throw new IllegalArgumentException("Parameter end (" + end + ") must be greater than start (" + start + ")"); + throw new IllegalArgumentException( + "Parameter end (" + end + ") must be greater than start (" + start + ")"); } else if (start < 0 || end < 0) { throw new IllegalArgumentException("Character positions MUST be >= 0"); } @@ -275,10 +287,10 @@ public class RandomStringUtils { final int zeroDigitAscii = 48; final int firstLetterAscii = 65; - if (chars == null && (numbers && end <= zeroDigitAscii - || letters && end <= firstLetterAscii)) { - throw new IllegalArgumentException("Parameter end (" + end + ") must be greater then (" + zeroDigitAscii + ") for generating digits " + - "or greater then (" + firstLetterAscii + ") for generating letters."); + if (chars == null && (numbers && end <= zeroDigitAscii || letters && end <= firstLetterAscii)) { + throw new IllegalArgumentException( + "Parameter end (" + end + ") must be greater then (" + zeroDigitAscii + ") for generating digits " + + "or greater then (" + firstLetterAscii + ") for generating letters."); } final StringBuilder builder = new StringBuilder(count); @@ -322,8 +334,7 @@ public class RandomStringUtils { continue; } - if (letters && Character.isLetter(codePoint) - || numbers && Character.isDigit(codePoint) + if (letters && Character.isLetter(codePoint) || numbers && Character.isDigit(codePoint) || !letters && !numbers) { builder.appendCodePoint(codePoint); @@ -339,46 +350,43 @@ public class RandomStringUtils { } /** - * Creates a random string whose length is the number of characters - * specified. + * Creates a random string whose length is the number of characters specified. * - *Characters will be chosen from the set of characters - * specified by the string, must not be empty. - * If null, the set of all characters is used.
+ *+ * Characters will be chosen from the set of characters specified by the string, must not be empty. If null, the set + * of all characters is used. + *
* - * @param count the length of random string to create - * @param chars the String containing the set of characters to use, - * may be null, but must not be empty + * @param count the length of random string to create + * @param chars the String containing the set of characters to use, may be null, but must not be empty * @return the random string * @throws IllegalArgumentException if {@code count} < 0 or the string is empty. */ public static String random(final int count, final String chars) { - if (chars == null) { - return random(count, 0, 0, false, false, null, random()); - } - return random(count, chars.toCharArray()); + return secure().next(count, chars); } /** - * Creates a random string whose length is the number of characters - * specified. + * Creates a random string whose length is the number of characters specified. * - *Characters will be chosen from the set of Latin alphabetic - * characters (a-z, A-Z).
+ *+ * Characters will be chosen from the set of Latin alphabetic characters (a-z, A-Z). + *
* - * @param count the length of random string to create + * @param count the length of random string to create * @return the random string * @throws IllegalArgumentException if {@code count} < 0. */ public static String randomAlphabetic(final int count) { - return random(count, true, false); + return secure().nextAlphabetic(count); } /** - * Creates a random string whose length is between the inclusive minimum and - * the exclusive maximum. + * Creates a random string whose length is between the inclusive minimum and the exclusive maximum. * - *Characters will be chosen from the set of Latin alphabetic characters (a-z, A-Z).
+ *+ * Characters will be chosen from the set of Latin alphabetic characters (a-z, A-Z). + *
* * @param minLengthInclusive the inclusive minimum length of the string to generate * @param maxLengthExclusive the exclusive maximum length of the string to generate @@ -386,30 +394,30 @@ public class RandomStringUtils { * @since 3.5 */ public static String randomAlphabetic(final int minLengthInclusive, final int maxLengthExclusive) { - return randomAlphabetic(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); + return secure().nextAlphabetic(minLengthInclusive, maxLengthExclusive); } /** - * Creates a random string whose length is the number of characters - * specified. + * Creates a random string whose length is the number of characters specified. * - *Characters will be chosen from the set of Latin alphabetic - * characters (a-z, A-Z) and the digits 0-9.
+ *+ * Characters will be chosen from the set of Latin alphabetic characters (a-z, A-Z) and the digits 0-9. + *
* - * @param count the length of random string to create + * @param count the length of random string to create * @return the random string * @throws IllegalArgumentException if {@code count} < 0. */ public static String randomAlphanumeric(final int count) { - return random(count, true, true); + return secure().nextAlphanumeric(count); } /** - * Creates a random string whose length is between the inclusive minimum and - * the exclusive maximum. + * Creates a random string whose length is between the inclusive minimum and the exclusive maximum. * - *Characters will be chosen from the set of Latin alphabetic - * characters (a-z, A-Z) and the digits 0-9.
+ *+ * Characters will be chosen from the set of Latin alphabetic characters (a-z, A-Z) and the digits 0-9. + *
* * @param minLengthInclusive the inclusive minimum length of the string to generate * @param maxLengthExclusive the exclusive maximum length of the string to generate @@ -417,30 +425,32 @@ public class RandomStringUtils { * @since 3.5 */ public static String randomAlphanumeric(final int minLengthInclusive, final int maxLengthExclusive) { - return randomAlphanumeric(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); + return secure().nextAlphanumeric(minLengthInclusive, maxLengthExclusive); } /** - * Creates a random string whose length is the number of characters - * specified. + * Creates a random string whose length is the number of characters specified. * - *Characters will be chosen from the set of characters whose - * ASCII value is between {@code 32} and {@code 126} (inclusive).
+ *+ * Characters will be chosen from the set of characters whose ASCII value is between {@code 32} and {@code 126} + * (inclusive). + *
* - * @param count the length of random string to create + * @param count the length of random string to create * @return the random string * @throws IllegalArgumentException if {@code count} < 0. */ public static String randomAscii(final int count) { - return random(count, 32, 127, false, false); + return secure().nextAscii(count); } /** - * Creates a random string whose length is between the inclusive minimum and - * the exclusive maximum. + * Creates a random string whose length is between the inclusive minimum and the exclusive maximum. * - *Characters will be chosen from the set of characters whose - * ASCII value is between {@code 32} and {@code 126} (inclusive).
+ *+ * Characters will be chosen from the set of characters whose ASCII value is between {@code 32} and {@code 126} + * (inclusive). + *
* * @param minLengthInclusive the inclusive minimum length of the string to generate * @param maxLengthExclusive the exclusive maximum length of the string to generate @@ -448,30 +458,32 @@ public class RandomStringUtils { * @since 3.5 */ public static String randomAscii(final int minLengthInclusive, final int maxLengthExclusive) { - return randomAscii(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); + return secure().nextAscii(minLengthInclusive, maxLengthExclusive); } /** * Creates a random string whose length is the number of characters specified. * - *Characters will be chosen from the set of characters which match the POSIX [:graph:] - * regular expression character class. This class contains all visible ASCII characters - * (i.e. anything except spaces and control characters).
+ *+ * Characters will be chosen from the set of characters which match the POSIX [:graph:] regular expression character + * class. This class contains all visible ASCII characters (i.e. anything except spaces and control characters). + *
* - * @param count the length of random string to create + * @param count the length of random string to create * @return the random string * @throws IllegalArgumentException if {@code count} < 0. * @since 3.5 */ public static String randomGraph(final int count) { - return random(count, 33, 126, false, false); + return secure().nextGraph(count); } /** - * Creates a random string whose length is between the inclusive minimum and - * the exclusive maximum. + * Creates a random string whose length is between the inclusive minimum and the exclusive maximum. * - *Characters will be chosen from the set of \p{Graph} characters.
+ *+ * Characters will be chosen from the set of \p{Graph} characters. + *
* * @param minLengthInclusive the inclusive minimum length of the string to generate * @param maxLengthExclusive the exclusive maximum length of the string to generate @@ -479,29 +491,30 @@ public class RandomStringUtils { * @since 3.5 */ public static String randomGraph(final int minLengthInclusive, final int maxLengthExclusive) { - return randomGraph(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); + return secure().nextGraph(minLengthInclusive, maxLengthExclusive); } /** - * Creates a random string whose length is the number of characters - * specified. + * Creates a random string whose length is the number of characters specified. * - *Characters will be chosen from the set of numeric - * characters.
+ *+ * Characters will be chosen from the set of numeric characters. + *
* - * @param count the length of random string to create + * @param count the length of random string to create * @return the random string * @throws IllegalArgumentException if {@code count} < 0. */ public static String randomNumeric(final int count) { - return random(count, false, true); + return secure().nextNumeric(count); } /** - * Creates a random string whose length is between the inclusive minimum and - * the exclusive maximum. + * Creates a random string whose length is between the inclusive minimum and the exclusive maximum. * - *Characters will be chosen from the set of \p{Digit} characters.
+ *+ * Characters will be chosen from the set of \p{Digit} characters. + *
* * @param minLengthInclusive the inclusive minimum length of the string to generate * @param maxLengthExclusive the exclusive maximum length of the string to generate @@ -509,30 +522,32 @@ public class RandomStringUtils { * @since 3.5 */ public static String randomNumeric(final int minLengthInclusive, final int maxLengthExclusive) { - return randomNumeric(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); + return secure().nextNumeric(minLengthInclusive, maxLengthExclusive); } /** * Creates a random string whose length is the number of characters specified. * - *Characters will be chosen from the set of characters which match the POSIX [:print:] - * regular expression character class. This class includes all visible ASCII characters and spaces - * (i.e. anything except control characters).
+ *+ * Characters will be chosen from the set of characters which match the POSIX [:print:] regular expression character + * class. This class includes all visible ASCII characters and spaces (i.e. anything except control characters). + *
* - * @param count the length of random string to create + * @param count the length of random string to create * @return the random string * @throws IllegalArgumentException if {@code count} < 0. * @since 3.5 */ public static String randomPrint(final int count) { - return random(count, 32, 126, false, false); + return secure().nextPrint(count); } /** - * Creates a random string whose length is between the inclusive minimum and - * the exclusive maximum. + * Creates a random string whose length is between the inclusive minimum and the exclusive maximum. * - *Characters will be chosen from the set of \p{Print} characters.
+ *+ * Characters will be chosen from the set of \p{Print} characters. + *
* * @param minLengthInclusive the inclusive minimum length of the string to generate * @param maxLengthExclusive the exclusive maximum length of the string to generate @@ -540,22 +555,378 @@ public class RandomStringUtils { * @since 3.5 */ public static String randomPrint(final int minLengthInclusive, final int maxLengthExclusive) { - return randomPrint(RandomUtils.nextInt(minLengthInclusive, maxLengthExclusive)); + return secure().nextPrint(minLengthInclusive, maxLengthExclusive); } /** - * {@link RandomStringUtils} instances should NOT be constructed in - * standard programming. Instead, the class should be used as - * {@code RandomStringUtils.random(5);}. + * Gets the singleton instance based on {@link SecureRandom#getInstanceStrong()} which uses an algorithms/providers + * specified in the {@code securerandom.strongAlgorithms} {@link Security} property. + *+ * The method {@link SecureRandom#getInstanceStrong()} is called on-demand. + *
* - *This constructor is public to permit tools that require a JavaBean instance - * to operate.
+ * @return the singleton instance based on {@link SecureRandom#getInstanceStrong()}. + * @see SecureRandom#getInstanceStrong() + * @since 3.16.0 + */ + public static RandomStringUtils secure() { + return SECURE; + } + + private final Supplier+ * This constructor is public to permit tools that require a JavaBean instance to operate. + *
* * @deprecated TODO Make private in 4.0. */ @Deprecated public RandomStringUtils() { - // empty + this(SECURE_SUPPLIER); + } + + private RandomStringUtils(final Supplier+ * Characters will be chosen from the set of all characters. + *
+ * + * @param count the length of random string to create + * @return the random string + * @throws IllegalArgumentException if {@code count} < 0. + * @since 3.16.0 + */ + public String next(final int count) { + return random(count, false, false); + } + + /** + * Creates a random string whose length is the number of characters specified. + * + *+ * Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments. + *
+ * + * @param count the length of random string to create + * @param letters if {@code true}, generated string may include alphabetic characters + * @param numbers if {@code true}, generated string may include numeric characters + * @return the random string + * @throws IllegalArgumentException if {@code count} < 0. + * @since 3.16.0 + */ + public String next(final int count, final boolean letters, final boolean numbers) { + return random(count, 0, 0, letters, numbers); + } + + /** + * Creates a random string whose length is the number of characters specified. + * + *+ * Characters will be chosen from the set of characters specified. + *
+ * + * @param count the length of random string to create + * @param chars the character array containing the set of characters to use, may be null + * @return the random string + * @throws IllegalArgumentException if {@code count} < 0. + * @since 3.16.0 + */ + public String next(final int count, final char... chars) { + if (chars == null) { + return random(count, 0, 0, false, false, null, random()); + } + return random(count, 0, chars.length, false, false, chars, random()); + } + + /** + * Creates a random string whose length is the number of characters specified. + * + *+ * Characters will be chosen from the set of alpha-numeric characters as indicated by the arguments. + *
+ * + * @param count the length of random string to create + * @param start the position in set of chars to start at + * @param end the position in set of chars to end before + * @param letters if {@code true}, generated string may include alphabetic characters + * @param numbers if {@code true}, generated string may include numeric characters + * @return the random string + * @throws IllegalArgumentException if {@code count} < 0. + * @since 3.16.0 + */ + public String next(final int count, final int start, final int end, final boolean letters, final boolean numbers) { + return random(count, start, end, letters, numbers, null, random()); + } + + /** + * Creates a random string based on a variety of options, using default source of randomness. + * + *+ * This method has exactly the same semantics as {@link #random(int,int,int,boolean,boolean,char[],Random)}, but + * instead of using an externally supplied source of randomness, it uses the internal static {@link Random} + * instance. + *
+ * + * @param count the length of random string to create + * @param start the position in set of chars to start at + * @param end the position in set of chars to end before + * @param letters if {@code true}, generated string may include alphabetic characters + * @param numbers if {@code true}, generated string may include numeric characters + * @param chars the set of chars to choose randoms from. If {@code null}, then it will use the set of all chars. + * @return the random string + * @throws ArrayIndexOutOfBoundsException if there are not {@code (end - start) + 1} characters in the set array. + * @throws IllegalArgumentException if {@code count} < 0. + */ + public String next(final int count, final int start, final int end, final boolean letters, final boolean numbers, + final char... chars) { + return random(count, start, end, letters, numbers, chars, random()); + } + + /** + * Creates a random string whose length is the number of characters specified. + * + *+ * Characters will be chosen from the set of characters specified by the string, must not be empty. If null, the set + * of all characters is used. + *
+ * + * @param count the length of random string to create + * @param chars the String containing the set of characters to use, may be null, but must not be empty + * @return the random string + * @throws IllegalArgumentException if {@code count} < 0 or the string is empty. + * @since 3.16.0 + */ + public String next(final int count, final String chars) { + if (chars == null) { + return random(count, 0, 0, false, false, null, random()); + } + return random(count, chars.toCharArray()); + } + + /** + * Creates a random string whose length is the number of characters specified. + * + *+ * Characters will be chosen from the set of Latin alphabetic characters (a-z, A-Z). + *
+ * + * @param count the length of random string to create + * @return the random string + * @throws IllegalArgumentException if {@code count} < 0. + */ + public String nextAlphabetic(final int count) { + return random(count, true, false); + } + + /** + * Creates a random string whose length is between the inclusive minimum and the exclusive maximum. + * + *+ * Characters will be chosen from the set of Latin alphabetic characters (a-z, A-Z). + *
+ * + * @param minLengthInclusive the inclusive minimum length of the string to generate + * @param maxLengthExclusive the exclusive maximum length of the string to generate + * @return the random string + * @since 3.5 + */ + public String nextAlphabetic(final int minLengthInclusive, final int maxLengthExclusive) { + return randomAlphabetic(randomUtils().randomInt(minLengthInclusive, maxLengthExclusive)); + } + + /** + * Creates a random string whose length is the number of characters specified. + * + *+ * Characters will be chosen from the set of Latin alphabetic characters (a-z, A-Z) and the digits 0-9. + *
+ * + * @param count the length of random string to create + * @return the random string + * @throws IllegalArgumentException if {@code count} < 0. + */ + public String nextAlphanumeric(final int count) { + return random(count, true, true); + } + + /** + * Creates a random string whose length is between the inclusive minimum and the exclusive maximum. + * + *+ * Characters will be chosen from the set of Latin alphabetic characters (a-z, A-Z) and the digits 0-9. + *
+ * + * @param minLengthInclusive the inclusive minimum length of the string to generate + * @param maxLengthExclusive the exclusive maximum length of the string to generate + * @return the random string + * @since 3.5 + */ + public String nextAlphanumeric(final int minLengthInclusive, final int maxLengthExclusive) { + return randomAlphanumeric(randomUtils().randomInt(minLengthInclusive, maxLengthExclusive)); + } + + /** + * Creates a random string whose length is the number of characters specified. + * + *+ * Characters will be chosen from the set of characters whose ASCII value is between {@code 32} and {@code 126} + * (inclusive). + *
+ * + * @param count the length of random string to create + * @return the random string + * @throws IllegalArgumentException if {@code count} < 0. + */ + public String nextAscii(final int count) { + return random(count, 32, 127, false, false); + } + + /** + * Creates a random string whose length is between the inclusive minimum and the exclusive maximum. + * + *+ * Characters will be chosen from the set of characters whose ASCII value is between {@code 32} and {@code 126} + * (inclusive). + *
+ * + * @param minLengthInclusive the inclusive minimum length of the string to generate + * @param maxLengthExclusive the exclusive maximum length of the string to generate + * @return the random string + * @since 3.5 + */ + public String nextAscii(final int minLengthInclusive, final int maxLengthExclusive) { + return randomAscii(randomUtils().randomInt(minLengthInclusive, maxLengthExclusive)); + } + + /** + * Creates a random string whose length is the number of characters specified. + * + *+ * Characters will be chosen from the set of characters which match the POSIX [:graph:] regular expression character + * class. This class contains all visible ASCII characters (i.e. anything except spaces and control characters). + *
+ * + * @param count the length of random string to create + * @return the random string + * @throws IllegalArgumentException if {@code count} < 0. + * @since 3.5 + */ + public String nextGraph(final int count) { + return random(count, 33, 126, false, false); + } + + /** + * Creates a random string whose length is between the inclusive minimum and the exclusive maximum. + * + *+ * Characters will be chosen from the set of \p{Graph} characters. + *
+ * + * @param minLengthInclusive the inclusive minimum length of the string to generate + * @param maxLengthExclusive the exclusive maximum length of the string to generate + * @return the random string + * @since 3.5 + */ + public String nextGraph(final int minLengthInclusive, final int maxLengthExclusive) { + return randomGraph(randomUtils().randomInt(minLengthInclusive, maxLengthExclusive)); + } + + /** + * Creates a random string whose length is the number of characters specified. + * + *+ * Characters will be chosen from the set of numeric characters. + *
+ * + * @param count the length of random string to create + * @return the random string + * @throws IllegalArgumentException if {@code count} < 0. + */ + public String nextNumeric(final int count) { + return random(count, false, true); + } + + /** + * Creates a random string whose length is between the inclusive minimum and the exclusive maximum. + * + *+ * Characters will be chosen from the set of \p{Digit} characters. + *
+ * + * @param minLengthInclusive the inclusive minimum length of the string to generate + * @param maxLengthExclusive the exclusive maximum length of the string to generate + * @return the random string + * @since 3.5 + */ + public String nextNumeric(final int minLengthInclusive, final int maxLengthExclusive) { + return randomNumeric(randomUtils().randomInt(minLengthInclusive, maxLengthExclusive)); + } + + /** + * Creates a random string whose length is the number of characters specified. + * + *+ * Characters will be chosen from the set of characters which match the POSIX [:print:] regular expression character + * class. This class includes all visible ASCII characters and spaces (i.e. anything except control characters). + *
+ * + * @param count the length of random string to create + * @return the random string + * @throws IllegalArgumentException if {@code count} < 0. + * @since 3.5 + * @since 3.16.0 + */ + public String nextPrint(final int count) { + return random(count, 32, 126, false, false); + } + + /** + * Creates a random string whose length is between the inclusive minimum and the exclusive maximum. + * + *+ * Characters will be chosen from the set of \p{Print} characters. + *
+ * + * @param minLengthInclusive the inclusive minimum length of the string to generate + * @param maxLengthExclusive the exclusive maximum length of the string to generate + * @return the random string + * @since 3.16.0 + */ + public String nextPrint(final int minLengthInclusive, final int maxLengthExclusive) { + return randomPrint(randomUtils().randomInt(minLengthInclusive, maxLengthExclusive)); + } + + /** + * Gets the Random. + * + * @return the Random. + */ + private Random random() { + return randomUtils().random(); + } + + /** + * Gets the RandomUtils. + * + * @return the RandomUtils. + */ + private RandomUtils randomUtils() { + return random.get(); + } + + @Override + public String toString() { + return "RandomStringUtils [random=" + random() + "]"; } } diff --git a/src/main/java/org/apache/commons/lang3/RandomUtils.java b/src/main/java/org/apache/commons/lang3/RandomUtils.java index b3c652445..5a5851419 100644 --- a/src/main/java/org/apache/commons/lang3/RandomUtils.java +++ b/src/main/java/org/apache/commons/lang3/RandomUtils.java @@ -16,23 +16,78 @@ */ package org.apache.commons.lang3; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.security.Security; import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Supplier; + +import org.apache.commons.lang3.exception.UncheckedException; /** - * Utility library that supplements the standard {@link Random} class. + * Supplements the standard {@link Random} class. + *+ * Use {@link #secure()} to get the singleton instance based on {@link SecureRandom#getInstanceStrong()} which uses an + * algorithms/providers specified in the {@code securerandom.strongAlgorithms} {@link Security} property. + *
+ *+ * Use {@link #insecure()} to get the singleton instance based on {@link ThreadLocalRandom#current()}; which is not + * cryptographically secure. + *
+ *+ * Starting in version 3.15.0, this class uses {@link SecureRandom#getInstanceStrong()} for static methods. + *
+ *+ * Starting in version 3.16.0, this class uses {@link #secure()} for static methods and adds {@link #insecure()}. + *
+ *+ * Before version 3.15.0, this class used {@link ThreadLocalRandom#current()} for static methods, which is not + * cryptographically secure. + *
+ *+ * Please note that the Apache Commons project provides a component dedicated to pseudo-random number generation, namely + * Commons RNG, that may be a better choice for + * applications with more stringent requirements (performance and/or correctness). + *
* - *Please note that the Apache Commons project provides a component - * dedicated to pseudo-random number generation, namely - * Commons RNG, that may be - * a better choice for applications with more stringent requirements - * (performance and/or correctness).
- * - * @deprecated Use Apache Commons RNG's optimized UniformRandomProvider + * @see RandomStringUtils * @since 3.3 */ -@Deprecated public class RandomUtils { + private static RandomUtils INSECURE = new RandomUtils(ThreadLocalRandom::current); + + private static final Supplier+ * The method {@link ThreadLocalRandom#current()} is called on-demand. + *
+ * + * @return the singleton instance based on {@link ThreadLocalRandom#current()}. + * @see ThreadLocalRandom#current() + * @see #secure() + * @since 3.16.0 + */ + static RandomUtils insecure() { + return INSECURE; + } + /** * Generates a random boolean value. * @@ -40,22 +95,18 @@ public class RandomUtils { * @since 3.5 */ public static boolean nextBoolean() { - return RandomStringUtils.random().nextBoolean(); + return secure().randomBoolean(); } /** * Generates an array of random bytes. * - * @param count - * the size of the returned array + * @param count the size of the returned array * @return the random byte array * @throws IllegalArgumentException if {@code count} is negative */ public static byte[] nextBytes(final int count) { - Validate.isTrue(count >= 0, "Count cannot be negative."); - final byte[] result = new byte[count]; - RandomStringUtils.random().nextBytes(result); - return result; + return secure().randomBytes(count); } /** @@ -66,29 +117,20 @@ public class RandomUtils { * @since 3.5 */ public static double nextDouble() { - return nextDouble(0, Double.MAX_VALUE); + return secure().randomDouble(); } /** * Generates a random double within the specified range. * - * @param startInclusive - * the smallest value that can be returned, must be non-negative - * @param endExclusive - * the upper bound (not included) - * @throws IllegalArgumentException - * if {@code startInclusive > endExclusive} or if - * {@code startInclusive} is negative + * @param startInclusive the smallest value that can be returned, must be non-negative + * @param endExclusive the upper bound (not included) + * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is + * negative * @return the random double */ public static double nextDouble(final double startInclusive, final double endExclusive) { - Validate.isTrue(endExclusive >= startInclusive, - "Start value must be smaller or equal to end value."); - Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); - if (startInclusive == endExclusive) { - return startInclusive; - } - return startInclusive + (endExclusive - startInclusive) * RandomStringUtils.random().nextDouble(); + return secure().randomDouble(startInclusive, endExclusive); } /** @@ -99,29 +141,20 @@ public class RandomUtils { * @since 3.5 */ public static float nextFloat() { - return nextFloat(0, Float.MAX_VALUE); + return secure().randomFloat(); } /** * Generates a random float within the specified range. * - * @param startInclusive - * the smallest value that can be returned, must be non-negative - * @param endExclusive - * the upper bound (not included) - * @throws IllegalArgumentException - * if {@code startInclusive > endExclusive} or if - * {@code startInclusive} is negative + * @param startInclusive the smallest value that can be returned, must be non-negative + * @param endExclusive the upper bound (not included) + * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is + * negative * @return the random float */ public static float nextFloat(final float startInclusive, final float endExclusive) { - Validate.isTrue(endExclusive >= startInclusive, - "Start value must be smaller or equal to end value."); - Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); - if (startInclusive == endExclusive) { - return startInclusive; - } - return startInclusive + (endExclusive - startInclusive) * RandomStringUtils.random().nextFloat(); + return secure().randomFloat(startInclusive, endExclusive); } /** @@ -132,29 +165,20 @@ public class RandomUtils { * @since 3.5 */ public static int nextInt() { - return nextInt(0, Integer.MAX_VALUE); + return secure().randomInt(); } /** * Generates a random integer within the specified range. * - * @param startInclusive - * the smallest value that can be returned, must be non-negative - * @param endExclusive - * the upper bound (not included) - * @throws IllegalArgumentException - * if {@code startInclusive > endExclusive} or if - * {@code startInclusive} is negative + * @param startInclusive the smallest value that can be returned, must be non-negative + * @param endExclusive the upper bound (not included) + * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is + * negative * @return the random integer */ public static int nextInt(final int startInclusive, final int endExclusive) { - Validate.isTrue(endExclusive >= startInclusive, - "Start value must be smaller or equal to end value."); - Validate.isTrue(startInclusive >= 0, "Both range values must be non-negative."); - if (startInclusive == endExclusive) { - return startInclusive; - } - return startInclusive + RandomStringUtils.random().nextInt(endExclusive - startInclusive); + return secure().randomInt(startInclusive, endExclusive); } /** @@ -165,24 +189,213 @@ public class RandomUtils { * @since 3.5 */ public static long nextLong() { + return secure().randomLong(); + } + + /** + * Generates a {@code long} value between 0 (inclusive) and the specified value (exclusive). + * + * @param n Bound on the random number to be returned. Must be positive. + * @return a random {@code long} value between 0 (inclusive) and {@code n} (exclusive). + */ + private static long nextLong(final long n) { + return secure().randomLong(n); + } + + /** + * Generates a random long within the specified range. + * + * @param startInclusive the smallest value that can be returned, must be non-negative + * @param endExclusive the upper bound (not included) + * @throws IllegalArgumentException if {@code startInclusive > endExclusive} or if {@code startInclusive} is + * negative + * @return the random long + */ + public static long nextLong(final long startInclusive, final long endExclusive) { + return secure().randomLong(startInclusive, endExclusive); + } + + /** + * Gets the singleton instance based on {@link SecureRandom#getInstanceStrong()} which uses an algorithms/providers + * specified in the {@code securerandom.strongAlgorithms} {@link Security} property. + *+ * The method {@link SecureRandom#getInstanceStrong()} is called on-demand. + *
+ * + * @return the singleton instance based on {@link SecureRandom#getInstanceStrong()}. + * @see SecureRandom#getInstanceStrong() + * @since 3.16.0 + */ + public static RandomUtils secure() { + return SECURE; + } + + static SecureRandom secureRandom() { + return SECURE_RANDOM.get(); + } + + private final Supplier+ * This constructor is public to permit tools that require a JavaBean instance to operate. + *
+ * + * @deprecated TODO Make private in 4.0. + */ + @Deprecated + public RandomUtils() { + this(SECURE_SUPPLIER); + } + + private RandomUtils(final Supplier- * This constructor is public to permit tools that require a JavaBean - * instance to operate. - *
- * - * @deprecated TODO Make private in 4.0. - */ - @Deprecated - public RandomUtils() { - // empty + @Override + public String toString() { + return "RandomUtils [random=" + random() + "]"; } + } diff --git a/src/test/java/org/apache/commons/lang3/RandomStringUtilsTest.java b/src/test/java/org/apache/commons/lang3/RandomStringUtilsTest.java index 2999d8ebc..d5c543ef5 100644 --- a/src/test/java/org/apache/commons/lang3/RandomStringUtilsTest.java +++ b/src/test/java/org/apache/commons/lang3/RandomStringUtilsTest.java @@ -24,19 +24,20 @@ import static org.hamcrest.Matchers.lessThan; import static org.hamcrest.Matchers.lessThanOrEqualTo; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.fail; -import java.lang.reflect.Constructor; -import java.lang.reflect.Modifier; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Random; +import java.util.stream.Stream; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.MethodSource; /** * Tests {@link RandomStringUtils}. @@ -45,6 +46,10 @@ public class RandomStringUtilsTest extends AbstractLangTest { private static final int LOOP_COUNT = 1_000; + static Stream+ * return (long) nextDouble(startInclusive, endExclusive); + *+ * + *
See LANG-1592.
+ */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testLargeValueRangeLong(final RandomUtils ru) { + final long startInclusive = 12900000000001L; + final long endExclusive = 12900000000016L; + // Note: The method using 'return (long) nextDouble(startInclusive, endExclusive)' + // takes thousands of calls to generate an error. This size loop fails most + // of the time with the previous method. + final int n = (int) (endExclusive - startInclusive) * 1000; + for (int i = 0; i < n; i++) { + assertNotEquals(endExclusive, ru.randomLong(startInclusive, endExclusive)); + } + } + /** * Tests random byte array. */ @@ -131,11 +199,27 @@ public class RandomUtilsTest extends AbstractLangTest { assertEquals(20, result.length); } + /** + * Tests random byte array. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextBytes(final RandomUtils ru) { + final byte[] result = ru.randomBytes(20); + assertEquals(20, result.length); + } + @Test public void testNextBytesNegative() { assertThrows(IllegalArgumentException.class, () -> RandomUtils.nextBytes(-1)); } + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextBytesNegative(final RandomUtils ru) { + assertThrows(IllegalArgumentException.class, () -> ru.randomBytes(-1)); + } + /** * Tests next double range. */ @@ -145,11 +229,27 @@ public class RandomUtilsTest extends AbstractLangTest { assertThat("result >= 33d && result < 42d", result, allOf(greaterThanOrEqualTo(33d), lessThan(42d))); } + /** + * Tests next double range. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextDouble(final RandomUtils ru) { + final double result = ru.randomDouble(33d, 42d); + assertThat("result >= 33d && result < 42d", result, allOf(greaterThanOrEqualTo(33d), lessThan(42d))); + } + @Test public void testNextDoubleLowerGreaterUpper() { assertThrows(IllegalArgumentException.class, () -> RandomUtils.nextDouble(2, 1)); } + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextDoubleLowerGreaterUpper(final RandomUtils ru) { + assertThrows(IllegalArgumentException.class, () -> ru.randomDouble(2, 1)); + } + /** * Test next double range with minimal range. */ @@ -158,11 +258,26 @@ public class RandomUtilsTest extends AbstractLangTest { assertEquals(42.1, RandomUtils.nextDouble(42.1, 42.1), DELTA); } + /** + * Test next double range with minimal range. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextDoubleMinimalRange(final RandomUtils ru) { + assertEquals(42.1, ru.randomDouble(42.1, 42.1), DELTA); + } + @Test public void testNextDoubleNegative() { assertThrows(IllegalArgumentException.class, () -> RandomUtils.nextDouble(-1, 1)); } + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextDoubleNegative(final RandomUtils ru) { + assertThrows(IllegalArgumentException.class, () -> ru.randomDouble(-1, 1)); + } + /** * Tests next double range, random result. */ @@ -172,6 +287,16 @@ public class RandomUtilsTest extends AbstractLangTest { assertThat("randomResult >= 0 0 && randomResult < Double.MAX_VALUE", randomResult, allOf(greaterThanOrEqualTo(0d), lessThan(Double.MAX_VALUE))); } + /** + * Tests next double range, random result. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextDoubleRandomResult(final RandomUtils ru) { + final double randomResult = ru.randomDouble(); + assertThat("randomResult >= 0 0 && randomResult < Double.MAX_VALUE", randomResult, allOf(greaterThanOrEqualTo(0d), lessThan(Double.MAX_VALUE))); + } + /** * Tests next float range. */ @@ -181,11 +306,27 @@ public class RandomUtilsTest extends AbstractLangTest { assertThat("result >= 33f && result < 42f", result, allOf(greaterThanOrEqualTo(33f), lessThan(42f))); } + /** + * Tests next float range. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextFloat(final RandomUtils ru) { + final float result = ru.randomFloat(33f, 42f); + assertThat("result >= 33f && result < 42f", result, allOf(greaterThanOrEqualTo(33f), lessThan(42f))); + } + @Test public void testNextFloatLowerGreaterUpper() { assertThrows(IllegalArgumentException.class, () -> RandomUtils.nextFloat(2, 1)); } + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextFloatLowerGreaterUpper(final RandomUtils ru) { + assertThrows(IllegalArgumentException.class, () -> ru.randomFloat(2, 1)); + } + /** * Test next float range with minimal range. */ @@ -194,11 +335,26 @@ public class RandomUtilsTest extends AbstractLangTest { assertEquals(42.1f, RandomUtils.nextFloat(42.1f, 42.1f), DELTA); } + /** + * Test next float range with minimal range. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextFloatMinimalRange(final RandomUtils ru) { + assertEquals(42.1f, ru.randomFloat(42.1f, 42.1f), DELTA); + } + @Test public void testNextFloatNegative() { assertThrows(IllegalArgumentException.class, () -> RandomUtils.nextFloat(-1, 1)); } + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextFloatNegative(final RandomUtils ru) { + assertThrows(IllegalArgumentException.class, () -> ru.randomFloat(-1, 1)); + } + /** * Tests next float range, random result. */ @@ -208,6 +364,16 @@ public class RandomUtilsTest extends AbstractLangTest { assertThat("randomResult >= 0 && randomResult < Double.MAX_VALUE", randomResult, allOf(greaterThanOrEqualTo(0f), lessThan(Float.MAX_VALUE))); } + /** + * Tests next float range, random result. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextFloatRandomResult(final RandomUtils ru) { + final float randomResult = ru.randomFloat(); + assertThat("randomResult >= 0 && randomResult < Double.MAX_VALUE", randomResult, allOf(greaterThanOrEqualTo(0f), lessThan(Float.MAX_VALUE))); + } + /** * Tests next int range. */ @@ -217,11 +383,27 @@ public class RandomUtilsTest extends AbstractLangTest { assertThat("result >= 33 && result < 42", result, allOf(greaterThanOrEqualTo(33), lessThan(42))); } + /** + * Tests next int range. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextInt(final RandomUtils ru) { + final int result = ru.randomInt(33, 42); + assertThat("result >= 33 && result < 42", result, allOf(greaterThanOrEqualTo(33), lessThan(42))); + } + @Test public void testNextIntLowerGreaterUpper() { assertThrows(IllegalArgumentException.class, () -> RandomUtils.nextInt(2, 1)); } + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextIntLowerGreaterUpper(final RandomUtils ru) { + assertThrows(IllegalArgumentException.class, () -> ru.randomInt(2, 1)); + } + /** * Test next int range with minimal range. */ @@ -230,11 +412,26 @@ public class RandomUtilsTest extends AbstractLangTest { assertEquals(42, RandomUtils.nextInt(42, 42)); } + /** + * Test next int range with minimal range. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextIntMinimalRange(final RandomUtils ru) { + assertEquals(42, ru.randomInt(42, 42)); + } + @Test public void testNextIntNegative() { assertThrows(IllegalArgumentException.class, () -> RandomUtils.nextInt(-1, 1)); } + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextIntNegative(final RandomUtils ru) { + assertThrows(IllegalArgumentException.class, () -> ru.randomInt(-1, 1)); + } + /** * Tests next int range, random result. */ @@ -245,6 +442,17 @@ public class RandomUtilsTest extends AbstractLangTest { assertTrue(randomResult < Integer.MAX_VALUE); } + /** + * Tests next int range, random result. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextIntRandomResult(final RandomUtils ru) { + final int randomResult = ru.randomInt(); + assertTrue(randomResult > 0); + assertTrue(randomResult < Integer.MAX_VALUE); + } + /** * Tests next long range. */ @@ -254,11 +462,27 @@ public class RandomUtilsTest extends AbstractLangTest { assertThat("result >= 33L && result < 42L", result, allOf(greaterThanOrEqualTo(33L), lessThan(42L))); } + /** + * Tests next long range. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextLong(final RandomUtils ru) { + final long result = ru.randomLong(33L, 42L); + assertThat("result >= 33L && result < 42L", result, allOf(greaterThanOrEqualTo(33L), lessThan(42L))); + } + @Test public void testNextLongLowerGreaterUpper() { assertThrows(IllegalArgumentException.class, () -> RandomUtils.nextLong(2, 1)); } + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextLongLowerGreaterUpper(final RandomUtils ru) { + assertThrows(IllegalArgumentException.class, () -> ru.randomLong(2, 1)); + } + /** * Test next long range with minimal range. */ @@ -267,11 +491,26 @@ public class RandomUtilsTest extends AbstractLangTest { assertEquals(42L, RandomUtils.nextLong(42L, 42L)); } + /** + * Test next long range with minimal range. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextLongMinimalRange(final RandomUtils ru) { + assertEquals(42L, ru.randomLong(42L, 42L)); + } + @Test public void testNextLongNegative() { assertThrows(IllegalArgumentException.class, () -> RandomUtils.nextLong(-1, 1)); } + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextLongNegative(final RandomUtils ru) { + assertThrows(IllegalArgumentException.class, () -> ru.randomLong(-1, 1)); + } + /** * Tests next long range, random result. */ @@ -281,6 +520,16 @@ public class RandomUtilsTest extends AbstractLangTest { assertThat("randomResult >= 0 && randomResult < Long.MAX_VALUE", randomResult, allOf(greaterThanOrEqualTo(0L), lessThan(Long.MAX_VALUE))); } + /** + * Tests next long range, random result. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testNextLongRandomResult(final RandomUtils ru) { + final long randomResult = ru.randomLong(); + assertThat("randomResult >= 0 && randomResult < Long.MAX_VALUE", randomResult, allOf(greaterThanOrEqualTo(0L), lessThan(Long.MAX_VALUE))); + } + /** * Tests a zero byte array length. */ @@ -288,4 +537,13 @@ public class RandomUtilsTest extends AbstractLangTest { public void testZeroLengthNextBytes() { assertArrayEquals(new byte[0], RandomUtils.nextBytes(0)); } + + /** + * Tests a zero byte array length. + */ + @ParameterizedTest + @MethodSource("randomProvider") + public void testZeroLengthNextBytes(final RandomUtils ru) { + assertArrayEquals(new byte[0], ru.randomBytes(0)); + } }