package sqlancer;
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.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.junit.jupiter.api.Test;
public class TestRandomly {
private static final int NR_MIN_RUNS = 100000;
@Test // test that every option is picked
public void testFromOptions() {
Integer[] options = { 1, 2, 3 };
List remainingOptions = new ArrayList<>(Arrays.asList(options));
while (!remainingOptions.isEmpty()) {
Integer pickedOption = Randomly.fromOptions(options);
remainingOptions.remove(pickedOption);
}
assertTrue(remainingOptions.isEmpty());
}
@Test
public void testSubset() {
boolean encounteredEmptySubset = false;
boolean encounteredOriginalSet = false;
boolean encounteredStrictSubsetNonEmpty = false;
Integer[] options = { 1, 2, 3 };
List optionList = new ArrayList<>(Arrays.asList(options));
do {
List subset = Randomly.subset(optionList);
assertEquals(optionList.size(), 3); // check that the original set hasn't been modified
assertTrue(optionList.containsAll(subset));
if (subset.isEmpty()) {
encounteredEmptySubset = true;
} else if (subset.size() == optionList.size()) {
encounteredOriginalSet = true;
} else {
encounteredStrictSubsetNonEmpty = true;
}
} while (!encounteredEmptySubset || !encounteredOriginalSet || !encounteredStrictSubsetNonEmpty);
}
@Test
public void testString() {
boolean encounteredInteger = false;
boolean encounteredAscii = false;
boolean encounteredNonAscii = false;
boolean encounteredSpace = false;
Randomly r = new Randomly();
int i = 0;
do {
String s = r.getString();
for (Character c : s.toCharArray()) {
if (Character.isAlphabetic(c)) {
encounteredAscii = true;
} else if (Character.isDigit(c)) {
encounteredInteger = true;
} else if (Character.isSpaceChar(c)) {
encounteredSpace = true;
} else {
encounteredNonAscii = true;
}
}
} while (!encounteredInteger || !encounteredAscii || !encounteredNonAscii || !encounteredSpace
|| i++ < NR_MIN_RUNS);
}
@Test // TODO: also generate and check for NaN
public void testDouble() {
Randomly r = new Randomly();
boolean encounteredZero = false;
boolean encounteredPositive = false;
boolean encounteredNegative = false;
boolean encounteredInfinity = false;
do {
double doubleVal = r.getDouble();
if (doubleVal == 0) {
encounteredZero = true;
} else if (Double.isInfinite(doubleVal)) {
encounteredInfinity = true;
} else if (doubleVal > 0) {
encounteredPositive = true;
} else if (doubleVal < 0) {
encounteredNegative = true;
} else {
fail(String.valueOf(doubleVal));
}
} while (!encounteredZero || !encounteredPositive || !encounteredNegative || !encounteredInfinity);
}
@Test
public void testFiniteDouble() {
Randomly r = new Randomly();
for (int i = 0; i < NR_MIN_RUNS; i++) {
assertFalse(Double.isInfinite(r.getFiniteDouble()));
}
}
@Test
public void testNonZeroInteger() {
Randomly r = new Randomly();
boolean encounteredPositive = false;
boolean encounteredNegative = false;
int i = 0;
do {
long nonZeroInt = r.getNonZeroInteger();
assertNotEquals(0, nonZeroInt);
if (nonZeroInt > 0) {
encounteredPositive = true;
} else {
encounteredNegative = true;
}
} while (!encounteredPositive || !encounteredNegative || i++ < NR_MIN_RUNS);
}
@Test
public void testPositiveInteger() {
Randomly r = new Randomly();
boolean encounteredZero = false;
boolean encounteredMaxValue = false;
int i = 0;
do {
long positiveInt = r.getPositiveInteger();
assertTrue(positiveInt >= 0);
if (positiveInt == 0) {
encounteredZero = true;
} else if (positiveInt == Long.MAX_VALUE) {
encounteredMaxValue = true;
}
} while (!encounteredZero || !encounteredMaxValue || i++ < NR_MIN_RUNS);
}
@Test
public void testBytes() {
Randomly r = new Randomly();
boolean encounteredAllZeroes = false;
boolean encounteredMax = false;
boolean encounteredZeroLength = false;
int i = 0;
do {
byte[] bytes = r.getBytes();
if (bytes.length == 0) {
encounteredZeroLength = true;
} else if (bytes[0] == 0) {
encounteredAllZeroes = true;
} else if (bytes[0] == Byte.MAX_VALUE) {
encounteredMax = true;
}
} while (!encounteredAllZeroes || !encounteredMax || !encounteredZeroLength || i++ < NR_MIN_RUNS);
}
@Test
public void testNonCachedInteger() {
assertEquals(0, Randomly.getNotCachedInteger(0, 1));
assertEquals(0, Randomly.getNotCachedInteger(0, 0));
assertThrows(Exception.class, () -> Randomly.getNotCachedInteger(5, 0));
}
@Test
public void testInteger() {
Randomly r = new Randomly();
// TODO: we should throw an exception instead
assertEquals(0, r.getInteger(0, 0));
assertEquals(0, r.getInteger(0, 1));
}
@Test
public void testLong() {
Randomly r = new Randomly();
// TODO: we should throw an exception instead
assertEquals(0, r.getLong(0, 0));
assertEquals(0, r.getLong(0, 1));
}
@Test
public void testLong2() {
Randomly r = new Randomly();
for (int i = 0; i < NR_MIN_RUNS; i++) {
long val = r.getLong(-1, Long.MAX_VALUE);
assertTrue(val >= -1);
assertTrue(val < Long.MAX_VALUE);
}
}
@Test // check that when given a seed, each thread computes a consistent result
public void testSeed() {
int seed = 123;
Randomly r = new Randomly(seed);
List values = getRandomValueList(r);
List nonSeedList = getRandomValueList(new Randomly());
List> otherThreadResults = new ArrayList<>();
assertNotEquals(values, nonSeedList);
ExecutorService executor = Executors.newFixedThreadPool(10);
for (int i = 0; i < 1000; i++) {
executor.execute(new Runnable() {
@Override
public void run() {
otherThreadResults.add(getRandomValueList(new Randomly(seed)));
}
});
}
executor.shutdown();
try {
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.HOURS);
} catch (InterruptedException e) {
throw new AssertionError(e);
}
for (List otherThreadResult : otherThreadResults) {
assertEquals(values, otherThreadResult);
}
}
private List getRandomValueList(Randomly r) {
List values = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
values.add(String.valueOf(r.getDouble()));
values.add(String.valueOf(r.getInteger()));
values.add(String.valueOf(r.getString()));
values.add(String.valueOf(Randomly.getBoolean()));
}
return values;
}
}