package org.rascalmpl.library.cobra.util;
import java.util.Random;
public class RandomUtil {
private interface StringGen {
public void generate(Random rand, int length, StringBuilder result);
}
private static class CharRanges implements StringGen {
private int[] start;
private int[] stop;
public CharRanges(int[] start, int[] stop) {
assert start.length == stop.length;
this.start = start;
this.stop = stop;
}
public void generate(Random rand, int length, StringBuilder result) {
for (int c = 0; c < length; c++) {
int r = rand.nextInt(start.length);
result.appendCodePoint(generateCodePoint(rand, start[r], stop[r]));
}
}
private int generateCodePoint(Random rand, int start, int stop) {
int range = stop - start;
int result = 0;
do
result = start + rand.nextInt(range + 1);
while (!validCodePoint(result));
return result;
}
}
private static class CharSets implements StringGen {
private int[] chars;
public CharSets(int... chars) {
this.chars = chars;
}
@Override
public void generate(Random rand, int length, StringBuilder result) {
for (int c = 0; c < length; c++)
result.appendCodePoint(chars[rand.nextInt(chars.length)]);
}
}
private static class MixGenerators implements StringGen {
private StringGen[] generators;
public MixGenerators(StringGen... generators) {
this.generators = generators;
}
@Override
public void generate(Random rand, int length, StringBuilder result) {
int left = length;
while (left > 0) {
int chunk = 1 + rand.nextInt(left);
generators[rand.nextInt(generators.length)].generate(rand, chunk, result);
left -= chunk;
}
}
}
private static boolean validCodePoint(int cp) {
return Character.isDefined(cp)
&& Character.isValidCodePoint(cp)
&& Character.getType(cp) != Character.UNASSIGNED
;
}
private static String sanitize(String unclean) {
// let's avoid testing with invalid codepoints
int i = 0;
char [] chars = unclean.toCharArray();
while (i < chars.length) {
char c = chars[i];
if (Character.isHighSurrogate(c)) {
i++;
if (i < chars.length) {
int cp = Character.toCodePoint(c, chars[i]);
if (!validCodePoint(cp) || !Character.isSurrogatePair(c, chars[i])) {
chars[i-1] = '_';
chars[i] = '_';
}
}
else {
chars[i-1] = '_';
}
}
else if (Character.isLowSurrogate(c)) {
// this means the previous was not high
chars[i] = '_';
}
else if (!validCodePoint(c)) {
chars[i] = '_';
}
i++;
}
return new String(chars);
}
private final static StringGen alphaOnly = new CharRanges(new int[]{'a','A'}, new int[]{'z','Z'});
private final static StringGen normalStrings = new CharRanges(new int[]{'a','A','0'}, new int[]{'z','Z','9'});
private final static StringGen generalStrangeChars = new CharRanges(new int[]{0x00, 0x21,0xA1}, new int[]{0x09,0x2F,0xAC});
private final static StringGen normalUnicode = new CharRanges(new int[]{0x0100,0x3400,0xD000}, new int[]{0x0200,0x4D00,0xD700});
private final static StringGen strangeUnicode = new CharRanges(new int[]{0x12000, 0x20000}, new int[]{0x1247F, 0x215FF});
private final static StringGen whiteSpace = new CharSets(' ','\t','\n','\t');
private final static StringGen strangeWhiteSpace = new CharSets(0x85, 0xA0, 0x1680, 0x2000, 0x2028, 0x2029,0x205F,0x3000);
private final static StringGen rascalEscapes = new CharSets('\"','\'','>','\\','<','@','`');
private final static StringGen[] generators = new StringGen[] {
normalStrings,
normalStrings,
normalUnicode,
new MixGenerators(normalStrings, generalStrangeChars),
new MixGenerators(normalStrings, whiteSpace),
new MixGenerators(strangeWhiteSpace, whiteSpace),
new MixGenerators(normalUnicode, strangeUnicode),
new MixGenerators(normalStrings, rascalEscapes),
new MixGenerators(normalStrings, generalStrangeChars, normalUnicode, whiteSpace, rascalEscapes)
};
public static String string(Random rand, int depth) {
StringGen randomGenerator = generators[rand.nextInt(generators.length)];
StringBuilder result = new StringBuilder(depth * 2);
randomGenerator.generate(rand, depth, result);
return sanitize(result.toString());
}
public static String stringAlphaNumeric(Random rand, int depth) {
StringBuilder result = new StringBuilder(depth);
normalStrings.generate(rand, depth, result);
return sanitize(result.toString());
}
public static String stringAlpha(Random rand, int depth) {
StringBuilder result = new StringBuilder(depth);
alphaOnly.generate(rand, depth, result);
return sanitize(result.toString());
}
}