Skip to content

Commit

Permalink
test-utils: RandomUtils is deprecated, TRandom class introduced
Browse files Browse the repository at this point in the history
Signed-off-by: Ketoth Xupack <ketoth.xupack@gmail.com>
  • Loading branch information
KetothXupack committed Jan 10, 2014
1 parent 585a6eb commit 8766443
Show file tree
Hide file tree
Showing 3 changed files with 289 additions and 68 deletions.
78 changes: 10 additions & 68 deletions projects/test-utils/src/main/java/org/nohope/test/RandomUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,90 +3,32 @@
import org.joda.time.DateTime;
import org.joda.time.chrono.ISOChronology;

import java.security.SecureRandom;

/**
* @author <a href="mailto:ketoth.xupack@gmail.com">ketoth xupack</a>
* @since 9/21/12 6:55 PM
* @deprecated use {@link org.nohope.test.TRandom} instead
*/
@Deprecated
public final class RandomUtils {
public static final String LOWER = "abcdefghijklmnopqrstuvwxyz";
public static final String UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String DIGIT = "0123456789";
public static final String SPECIAL = "~`!@#$%^&*()_+-={}[]:\";'<>?,./|\\";
public static final String LOWER = TRandom.LOWER;
public static final String UPPER = TRandom.UPPER;
public static final String DIGIT = TRandom.DIGIT;
public static final String SPECIAL = TRandom.SPECIAL;

private static final SecureRandom RANDOM = new SecureRandom();
private static final TRandom RANDOM = TRandom.threadLocal();

private RandomUtils() {
}

/**
* Generates random string with given length and mask.
* <p />
* Mask is a string which may contain next chars:
* <ul>
* <li>{@code A} for {@link RandomUtils#UPPER upper case} letter</li>
* <li>{@code a} for {@link RandomUtils#LOWER lower case} letter</li>
* <li>{@code #} for {@link RandomUtils#DIGIT digit}</li>
* <li>{@code !} for {@link RandomUtils#SPECIAL special character}</li>
* </ul>
*
* Example:
* <pre>
* RandomUtils.nextString(10, "#A!"); // `XH(^=>70;
* </pre>
*
* @param length target string length
* @param mask mask
* @return randomly generated string
*/
public static String nextString(final int length, final String mask) {
String resultMask = "";
if (mask.indexOf('a') > -1) {
resultMask += LOWER;
}
if (mask.indexOf('A') > -1) {
resultMask += UPPER;
}
if (mask.indexOf('#') > -1) {
resultMask += DIGIT;
}
if (mask.indexOf('!') > -1) {
resultMask += SPECIAL;
}

if ("".equals(mask)) {
throw new IllegalArgumentException("Mask should contain at last one char from 'aA#!' sequence");
}

final StringBuilder result = new StringBuilder();
for (int i = length; i > 0; --i) {
result.append(resultMask.charAt(RANDOM.nextInt(resultMask.length())));
}
return result.toString();
return RANDOM.nextString(length, mask);
}

/**
* Generates random string with varying length from {@code 0} to given upper bound value exclusive.
* <p />
* This version of string generator users {@code "aA#!"} mask.
*
* @param upperBound length
* @return randomly generated string with varying length
* @see RandomUtils#nextString(int, String)
*/
public static String nextString(final int upperBound) {
return nextString(RANDOM.nextInt(upperBound), "aA#!");
return RANDOM.nextString(upperBound);
}

/**
* Generates random string with varying length from {@code 0} to {@code 100} exclusive.
*
* @return randomly generated string with varying length
* @see RandomUtils#nextString(int)
*/
public static String nextString() {
return nextString(100);
return RANDOM.nextString();
}

public static int nextInt() {
Expand Down
181 changes: 181 additions & 0 deletions projects/test-utils/src/main/java/org/nohope/test/TRandom.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package org.nohope.test;

import org.joda.time.DateTime;
import org.joda.time.chrono.ISOChronology;

import javax.annotation.Nonnull;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadLocalRandom;

/**
* @author <a href="mailto:ketoth.xupack@gmail.com">ketoth xupack</a>
* @since 9/21/12 6:55 PM
*/
public final class TRandom {
public static final String LOWER = "abcdefghijklmnopqrstuvwxyz";
public static final String UPPER = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
public static final String DIGIT = "0123456789";
public static final String SPECIAL = "~`!@#$%^&*()_+-={}[]:\";'<>?,./|\\";

private final Callable<Random> randomGetter;

private TRandom(final Callable<Random> randomGetter) {
this.randomGetter = randomGetter;
}

/** @return TRandom instance based on {@link ThreadLocalRandom} class */
public static TRandom threadLocal() {
return new TRandom(new Callable<Random>() {
@Override
public Random call() throws Exception {
return ThreadLocalRandom.current();
}
});
}

/** @return TRandom instance based on {@link Random} class */
public static TRandom standard() {
return new TRandom(new Callable<Random>() {
private final Random rnd = new Random();

@Override
public Random call() throws Exception {
return rnd;
}
});
}

/** @return TRandom instance based on single random instance */
public static TRandom singleton(@Nonnull final Random rnd) {
return new TRandom(new Callable<Random>() {
@Override
public Random call() throws Exception {
return rnd;
}
});
}

/** @return TRandom instance based on thread-local random instance */
public static TRandom threadLocal(@Nonnull final Callable<Random> rnd) {
final ThreadLocal<Random> local = new ThreadLocal<Random>() {
@Override
protected Random initialValue() {
try {
return rnd.call();
} catch (final Exception e) {
throw new IllegalStateException(e);
}
}
};

return new TRandom(new Callable<Random>() {
@Override
public Random call() throws Exception {
return local.get();
}
});
}

private Random get() {
try {
final Random rnd = randomGetter.call();
if (rnd != null) {
return rnd;
}
} catch (final Exception e) {
throw new IllegalStateException(e);
}

throw new IllegalStateException("random instance is null");
}

/**
* Generates random string with given length and mask.
* <p />
* Mask is a string which may contain next chars:
* <ul>
* <li>{@code A} for {@link TRandom#UPPER upper case} letter</li>
* <li>{@code a} for {@link TRandom#LOWER lower case} letter</li>
* <li>{@code #} for {@link TRandom#DIGIT digit}</li>
* <li>{@code !} for {@link TRandom#SPECIAL special character}</li>
* </ul>
*
* Example:
* <pre>
* RandomUtils.nextString(10, "#A!"); // `XH(^=>70;
* </pre>
*
* @param length target string length
* @param mask mask
* @return randomly generated string
*/
public String nextString(final int length, final String mask) {
String resultMask = "";
if (mask.indexOf('a') > -1) {
resultMask += LOWER;
}
if (mask.indexOf('A') > -1) {
resultMask += UPPER;
}
if (mask.indexOf('#') > -1) {
resultMask += DIGIT;
}
if (mask.indexOf('!') > -1) {
resultMask += SPECIAL;
}

if ("".equals(mask)) {
throw new IllegalArgumentException("Mask should contain at last one char from 'aA#!' sequence");
}

final StringBuilder result = new StringBuilder();
for (int i = length; i > 0; --i) {
result.append(resultMask.charAt(get().nextInt(resultMask.length())));
}
return result.toString();
}

/**
* Generates random string with varying length from {@code 0} to given upper bound value exclusive.
* <p />
* This version of string generator users {@code "aA#!"} mask.
*
* @param upperBound length
* @return randomly generated string with varying length
* @see TRandom#nextString(int, String)
*/
public String nextString(final int upperBound) {
return nextString(get().nextInt(upperBound), "aA#!");
}

/**
* Generates random string with varying length from {@code 0} to {@code 100} exclusive.
*
* @return randomly generated string with varying length
* @see TRandom#nextString(int)
*/
public String nextString() {
return nextString(100);
}

public int nextInt() {
return get().nextInt();
}

public DateTime nextUtcDateTime() {
return DateTime.now(ISOChronology.getInstanceUTC());
}

public long nextLong() {
return get().nextLong();
}

public boolean nextBoolean() {
return get().nextBoolean();
}

public double nextDouble() {
return get().nextDouble();
}
}
98 changes: 98 additions & 0 deletions projects/test-utils/src/test/java/org/nohope/test/TRandomTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package org.nohope.test;

import org.junit.Test;

import java.security.SecureRandom;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.regex.Pattern;

import static org.junit.Assert.*;

/**
* @author <a href="mailto:ketoth.xupack@gmail.com">ketoth xupack</a>
* @since 9/30/13 9:02 PM
*/
public class TRandomTest {
private static final Pattern ALL = Pattern.compile(".");

private static final TRandom[] RNDS = {
TRandom.standard(),
TRandom.threadLocal(),
TRandom.singleton(new SecureRandom()),
TRandom.threadLocal(new Callable<Random>() {
@Override
public Random call() throws Exception {
return new SecureRandom();
}
})
};

@Test
public void naive() {
for (final TRandom rnd : RNDS) {
rnd.nextInt();
rnd.nextLong();
rnd.nextDouble();
rnd.nextBoolean();
rnd.nextUtcDateTime();
}
}

@Test
public void randomString() {
for (final TRandom rnd : RNDS) {
assertContainsAll(rnd.nextString(10, "a"), TRandom.LOWER, 10);
assertContainsAll(rnd.nextString(10, "A"), TRandom.UPPER, 10);
assertContainsAll(rnd.nextString(10, "#"), TRandom.DIGIT, 10);
assertContainsAll(rnd.nextString(10, "!"), TRandom.SPECIAL, 10);

assertTrue(rnd.nextString(10).length() <= 10);
assertTrue(rnd.nextString().length() <= 100);

try {
RandomUtils.nextString(10, "");
fail();
} catch (final IllegalArgumentException ignored) {
}
}
}

@Test
public void failure() {
final TRandom rnd = TRandom.threadLocal(new Callable<Random>() {
@Override
public Random call() throws Exception {
return null;
}
});

try {
rnd.nextInt();
fail();
} catch (final IllegalStateException e) {
}

final TRandom rnd2 = TRandom.threadLocal(new Callable<Random>() {
@Override
public Random call() throws Exception {
throw new Exception("test");
}
});

try {
rnd2.nextInt();
fail();
} catch (final IllegalStateException e) {
}
}

private static void assertContainsAll(final String target, final String source, final int length) {
assertEquals(length, target.length());
for (final String s : ALL.split(source)) {
if (!target.contains(s)) {
fail();
}
}
}
}

0 comments on commit 8766443

Please sign in to comment.