hu.icellmobilsoft.roaster.api.Any Maven / Gradle / Ivy
/*-
* #%L
* Coffee
* %%
* Copyright (C) 2020 i-Cell Mobilsoft Zrt.
* %%
* Licensed 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.
* #L%
*/
package hu.icellmobilsoft.roaster.api;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import java.util.function.Function;
import java.util.function.IntSupplier;
import java.util.function.Supplier;
import javax.xml.datatype.XMLGregorianCalendar;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.text.RandomStringGenerator;
import hu.icellmobilsoft.coffee.tool.utils.date.DateXmlUtil;
import hu.icellmobilsoft.coffee.tool.utils.string.RandomUtil;
import hu.icellmobilsoft.roaster.api.reflect.Getter;
/**
* Collector class to hold all generic method to generate entity field values and test data.
*
*/
public abstract class Any {
private static final int DEFAULT_MIN_STR_LENGTH = 1;
private static final int DEFAULT_MAX_STR_LENGTH = 32;
private static final String ERROR_MSG_ENUMERATION_TYPE_NULL = "The input enumeration type should not be null.";
private static final String ERROR_MSG_ENUMERATION_TYPE_EMPTY = "The enumeration type should contain at least one element.";
private static final String ERROR_MSG_MAX_SIZE_AT_LEAST_ONE = "Maximum size of the array should be least one.";
public enum RandomStringType {
RANDOM, ASCII, ONLY_ALPHABETIC, ONLY_ALPHANUMERIC, ONLY_NUMERIC
}
private Any() {
}
/**
* generate an random X__ID using the default EntityIdGenerator.
*
* @return an random X__ID
*/
public static String xId() {
return RandomUtil.generateId();
}
/**
* Generate an random string that contains only whitespaces. The length will be between {@value DEFAULT_MIN_STR_LENGTH} and
* {@value DEFAULT_MAX_STR_LENGTH}
*
* @return an random only whitespace string
*/
public static String whitespace() {
return whitespace(DEFAULT_MIN_STR_LENGTH, DEFAULT_MAX_STR_LENGTH);
}
/**
* Generate random string what is null, empty or contains only whitespaces.
*
* @return the random string
*/
public static String emptyString() {
ThreadLocalRandom rand = ThreadLocalRandom.current();
return (rand.nextBoolean()) ? whitespace(0, DEFAULT_MAX_STR_LENGTH) : null;
}
/**
* Generate random email address
*
* @return the random email address
*/
public static String emailAddress() {
StringBuilder sb = new StringBuilder();
sb.append(string(30, false, RandomStringType.ONLY_ALPHANUMERIC));
sb.append("@");
sb.append(string(10, false, RandomStringType.ONLY_ALPHANUMERIC));
sb.append(".");
sb.append(string(3, false, RandomStringType.ONLY_ALPHANUMERIC));
return sb.toString();
}
/**
* Generate an random string that contains only whitespaces. The length will be between {@code min} and {@code max}
*
* @param min
* minimum number of characters
* @param max
* maximum number of characters
* @return an random only whitespace string
*/
private static String whitespace(int min, int max) {
RandomStringGenerator randomStringGenerator = new RandomStringGenerator.Builder().filteredBy(Character::isWhitespace).build();
return randomStringGenerator.generate(min, max);
}
/**
* @return random true or false
*/
public static boolean bool() {
ThreadLocalRandom rand = ThreadLocalRandom.current();
return rand.nextBoolean();
}
/**
* @return a fully random UTF-8 encoded string with length between {@value #DEFAULT_MIN_STR_LENGTH} and {@value #DEFAULT_MAX_STR_LENGTH}
*/
public static String string() {
RandomStringGenerator randomStringGenerator = new RandomStringGenerator.Builder().build();
return randomStringGenerator.generate(DEFAULT_MIN_STR_LENGTH, DEFAULT_MAX_STR_LENGTH);
}
/**
* Geerate an printable string with the maximum of {@code count} characters.
*
* @param count
* the max number of characters in the result string;
* @return an printable random string
*/
public static String string(int count) {
return string(count, false);
}
/**
* Geerate an printable string with the maximum of {@code count} characters containing only {@link RandomStringType} characters
*
* @param count
* the max number of characters in the result string;
* @param randomStringType
* random string type
* @return an printable random string
*/
public static String string(int count, RandomStringType randomStringType) {
return string(count, false, randomStringType);
}
/**
* Generate an printable string with the maximum of {@code count} characters.
*
* @param count
* the max number of characters in the result string;
* @param nonBlank
* should not begin and end with an whitespace character
* @return an printable random string
*/
public static String string(int count, boolean nonBlank) {
return string(count, nonBlank, RandomStringType.ASCII);
}
public static String string(int count, boolean nonBlank, RandomStringType randomStringType) {
ThreadLocalRandom rand = ThreadLocalRandom.current();
int randCount = rand.nextInt(count - 1) + 1;
String result;
switch (randomStringType) {
case ASCII:
result = RandomStringUtils.randomAscii(randCount);
break;
case ONLY_ALPHABETIC:
result = RandomStringUtils.randomAlphabetic(randCount);
break;
case ONLY_ALPHANUMERIC:
result = RandomStringUtils.randomAlphanumeric(randCount);
break;
case ONLY_NUMERIC:
result = RandomStringUtils.randomNumeric(randCount);
break;
default:
result = RandomStringUtils.random(randCount);
}
if (nonBlank) {
if (Character.isWhitespace(result.charAt(0))) {
result = RandomStringUtils.randomAscii(1) + result.substring(1);
}
if (Character.isWhitespace(result.charAt(result.length() - 1))) {
result = result.substring(0, result.length() - 1) + RandomStringUtils.randomAscii(1);
}
}
return result;
}
/**
* @return an random date after 1970-01-01T00:00:00Z
*/
public static Date time() {
return time(0, Instant.ofEpochSecond(Integer.MAX_VALUE).atOffset(ZoneOffset.UTC).toEpochSecond(), 0, LocalDateTime.MAX.getNano());
}
/**
* @param time
* bound time
* @return a new time point before the input time
*/
public static Date timeBefore(Date time) {
Condition.notNull(time, "time should not be null.");
Instant limit = time.toInstant();
return time(0, limit.getEpochSecond(), 0, limit.getNano());
}
/**
* @param time
* origin time
* @return a new time point after the input time
*/
public static Date timeAfter(Date time) {
Condition.notNull(time, "time should not be null.");
Instant limit = time.toInstant();
return time(limit.getEpochSecond(), Instant.ofEpochSecond(Integer.MAX_VALUE).atOffset(ZoneOffset.UTC).toEpochSecond(), limit.getNano(),
LocalDateTime.MAX.getNano());
}
/**
*
* @param origin
* origin time
* @param bound
* bound time
* @return an Date object between origin and bound
*/
public static Date time(Date origin, Date bound) {
Condition.notNull(origin, "origin should not be null.");
Condition.notNull(bound, "origin should not be null.");
Instant lhs = origin.toInstant();
Instant rhs = bound.toInstant();
return time(lhs.getEpochSecond(), rhs.getEpochSecond(), lhs.getNano(), rhs.getNano());
}
/**
* @param originEpoch
* the origin epoch seconds
* @param boundEpoch
* the bound epoch seconds
* @param originNano
* the origin nano
* @param boundNano
* the bound nano
* @return a random time in the given boundaries
*/
private static Date time(long originEpoch, long boundEpoch, int originNano, int boundNano) {
ZoneOffset offset = OffsetDateTime.now().getOffset();
LocalDateTime time = LocalDateTime.ofEpochSecond(Any.aLong(originEpoch, boundEpoch), Any.anInt(originNano, boundNano), offset);
return Date.from(time.toInstant(offset));
}
/**
* @return random {@code XMLGregorianCalendar}
*/
public static XMLGregorianCalendar timestamp() {
return DateXmlUtil.toXMLGregorianCalendar(Any.time());
}
/**
* @param bound
* the bound date
* @return an timestamp before bound
*/
public static XMLGregorianCalendar timestampBefore(Date bound) {
return DateXmlUtil.toXMLGregorianCalendar(Any.timeBefore(bound));
}
/**
* @param origin
* the origin date
* @return an timestamp after origin
*/
public static XMLGregorianCalendar timestampAfter(Date origin) {
return DateXmlUtil.toXMLGregorianCalendar(Any.timeAfter(origin));
}
/**
* @param origin
* the origin date
* @param bound
* the bound date
* @return a timestamp between origin and bound
*/
public static XMLGregorianCalendar timestamp(Date origin, Date bound) {
return DateXmlUtil.toXMLGregorianCalendar(Any.time(origin, bound));
}
/**
* @param
* generic type
* @param items
* variadic list of the possible items
* @return one of the item from the input
*/
@SafeVarargs
public static T of(T... items) {
Condition.notNullAll("Variadic item list should not have any null element.", items);
List itemList = Arrays.asList(items);
return of(itemList);
}
/**
* @param itemList
* the list of the possible items
* @param
* the type of possible item
* @return one random item from the {@code itemList}
*/
public static T of(List itemList) {
Condition.notEmpty(itemList, "should provide at least one possible item.");
ThreadLocalRandom rand = ThreadLocalRandom.current();
return itemList.get(rand.nextInt(itemList.size()));
}
/**
* @return an random integer
*/
public static int anInt() {
return ThreadLocalRandom.current().nextInt();
}
/**
* @param origin
* the origin
* @param bound
* the bound
* @return an random integer between {@code origin} (inclusive) and {@code bound} (exclusive)
*/
public static int anInt(int origin, int bound) {
return ThreadLocalRandom.current().nextInt(origin, bound);
}
/**
* @return a random positive integer
*/
public static int aPositiveInt() {
return nextNotZero(() -> ThreadLocalRandom.current().nextInt());
}
/**
* @param bound
* the upper bound (exclusive)
* @return a random positive integer that is less than {@code bound}
*/
public static int aPositiveInt(int bound) {
Condition.expected(bound > 0, "Origin must me be greater than zero!");
return nextNotZero(() -> ThreadLocalRandom.current().nextInt(bound));
}
/**
* @param origin
* the least value returned
* @param bound
* the upper bound (exclusive)
* @return a random positive integer that is between {@code origin} {@code bound}
*/
public static int aPositiveInt(int origin, int bound) {
Condition.expected(origin > 0, "Origin must me be greater than zero!");
Condition.expected(bound > origin, "Bound must me be greater than origin!");
return nextNotZero(() -> ThreadLocalRandom.current().nextInt(origin, bound));
}
private static int nextNotZero(IntSupplier nextSupplier) {
int result;
do {
result = nextSupplier.getAsInt();
} while (result == 0);
return result;
}
/**
* @return true ot false randomly
*/
public static boolean aBoolean() {
return ThreadLocalRandom.current().nextBoolean();
}
/**
* @return a random byte
*/
public static byte aByte() {
return (byte) ThreadLocalRandom.current().nextInt(Byte.MAX_VALUE + 1);
}
/**
* @param origin
* the origin
* @param bound
* the bound
* @return an random byte between {@code origin} (inclusive) and {@code bound} (exclusive)
*/
public static byte aByte(byte origin, byte bound) {
return (byte) ThreadLocalRandom.current().nextInt(origin, bound);
}
/**
* @return a random sort
*/
public static short aShort() {
return (short) ThreadLocalRandom.current().nextInt(Short.MAX_VALUE + 1);
}
/**
* @param origin
* the origin
* @param bound
* the bound
* @return an random short between {@code origin} (inclusive) and {@code bound} (exclusive)
*/
public static short aShort(short origin, short bound) {
return (short) ThreadLocalRandom.current().nextInt(origin, bound);
}
/**
* @return a random long
*/
public static long aLong() {
return ThreadLocalRandom.current().nextLong();
}
/**
* @param origin
* the origin
* @param bound
* the bound
* @return an random long between {@code origin} (inclusive) and {@code bound} (exclusive)
*/
public static long aLong(long origin, long bound) {
return ThreadLocalRandom.current().nextLong(origin, bound);
}
/**
* @return a random float
*/
public static float aFloat() {
return ThreadLocalRandom.current().nextFloat();
}
/**
* @return a random double
*/
public static double aDouble() {
return ThreadLocalRandom.current().nextDouble();
}
/**
* @param origin
* the origin
* @param bound
* the bound
* @return an random double between {@code origin} (inclusive) and {@code bound} (exclusive)
*/
public static double aDouble(double origin, double bound) {
return ThreadLocalRandom.current().nextDouble(origin, bound);
}
/**
* @param
* generic type
* @param enums
* variadic list of the enum values from an given enum type.
* @return one random chosen enum object from the list.
*/
public static > T object(@SuppressWarnings("unchecked") T... enums) {
List items = Arrays.asList(enums);
return object(items);
}
/**
* @param items
* the enumeration value list
* @param
* the type of the enumeration
* @return one random chosen enum object from the list.
*/
public static > T object(List items) {
Condition.notEmpty(items, "should provide at least one possible item.");
ThreadLocalRandom rand = ThreadLocalRandom.current();
return items.get(rand.nextInt(items.size()));
}
/**
* @param enumClass
* the class of the enumeration
* @param
* the type of the enumeration
* @return one random chosen enum object from all of the possible items.
*/
public static > T of(Class enumClass) {
Condition.notNull(enumClass, ERROR_MSG_ENUMERATION_TYPE_NULL);
T[] items = enumClass.getEnumConstants();
Condition.notEmpty(items, ERROR_MSG_ENUMERATION_TYPE_EMPTY);
ThreadLocalRandom rand = ThreadLocalRandom.current();
return items[rand.nextInt(items.length)];
}
/**
* More generic way to handle enumerations. The T type must not be implement the Enum interface, but the {@code Class} must have enum nature
* ({@code enumClass.isEnum() == true}). This way is possible more flexible work with reflection.
*
* @param enumClass
* the class of the enumeration
* @param
* the type of the enumeration
* @return one random chosen enum object from all of the possible items.
*/
public static T enumItem(Class enumClass) {
Condition.notNull(enumClass, ERROR_MSG_ENUMERATION_TYPE_NULL);
Condition.expected(enumClass.isEnum(), "The input type should be an enumeration.");
T[] items = enumClass.getEnumConstants();
Condition.notEmpty(items, ERROR_MSG_ENUMERATION_TYPE_EMPTY);
ThreadLocalRandom rand = ThreadLocalRandom.current();
return items[rand.nextInt(items.length)];
}
public static T fieldValue(Class ifaceClass, Class fieldType) {
Condition.notNull(ifaceClass, "IfaceClass should not be null.");
Condition.expected(ifaceClass.isInterface(), "the input type must be an interface.");
List items = Getter.getFieldsValue(ifaceClass, fieldType);
Condition.notEmpty(items, "Field value list should not be empty.");
return items.get(ThreadLocalRandom.current().nextInt(items.size()));
}
/**
* @param enumClass
* the class of the enumeration
* @param excludeItems
* the list of elements to exclude
* @param
* the type of the enumeration
* @return the enum object list of T without the exluded elements.
*/
public static > T[] exclude(Class enumClass, T... excludeItems) {
Condition.notNull(enumClass, ERROR_MSG_ENUMERATION_TYPE_NULL);
List items = new ArrayList<>(Arrays.asList(enumClass.getEnumConstants()));
Arrays.stream(excludeItems).forEach(items::remove);
Condition.notEmpty(items, ERROR_MSG_ENUMERATION_TYPE_EMPTY);
T[] result = (T[]) java.lang.reflect.Array.newInstance(items.get(0).getClass(), items.size());
for (int i = 0; i < items.size(); i++) {
result[i] = items.get(i);
}
return result;
}
/**
* @param ifaceClass
* the interface class
* @param fieldType
* the type of the fields to use
* @param randomSupplier
* the random value supplier to generate new random value
* @param
* the type of the field
* @param
* the type of the interface
* @return a random value what is not equals with any of the static field of {@code ifaceClass} with type {@code fieldType}
*/
public static T butValue(Class ifaceClass, Class fieldType, Supplier randomSupplier) {
Condition.notNull(ifaceClass, "IfaceClass should not be null.");
Condition.expected(ifaceClass.isInterface(), "the input type must be an interface.");
List items = Getter.getFieldsValue(ifaceClass, fieldType);
Condition.notEmpty(items, "Field value list should not be empty.");
T result = randomSupplier.get();
while (items.contains(result)) {
result = randomSupplier.get();
}
return result;
}
/**
* @param ifaceClass
* the interface class
* @param
* the type of the interface class
* @return a random integer that is not equals with any of the static fields of the {@code ifaceClass}
*/
public static int butInt(Class ifaceClass) {
return butValue(ifaceClass, int.class, () -> ThreadLocalRandom.current().nextInt());
}
/**
* @param text
* the string object
* @return any text but the input param
*/
public static String but(String text) {
return but(text, () -> Any.string(text.length()));
}
/**
* @param text
* the string object
* @param randomSupplier
* the supplier of the random string
* @return any text but the input param
*/
public static String but(String text, Supplier randomSupplier) {
Condition.notEmpty(text, "The input text should not be empty.");
String result = randomSupplier.get();
while (StringUtils.equals(result, text)) {
result = randomSupplier.get();
}
return result;
}
/**
* Create an array with random content.
*
* @param size
* the number of the elements
* @return a boolean array with {@code size}
*/
public static boolean[] booleanArray(int size) {
Condition.expected(size > 0, ERROR_MSG_MAX_SIZE_AT_LEAST_ONE);
boolean[] result = new boolean[size];
for (int i = 0; i < size; ++i) {
result[i] = aBoolean();
}
return result;
}
/**
* Create an array with random content.
*
* @param size
* the number of the elements
* @return a byte array with {@code size}
*/
public static byte[] byteArray(int size) {
Condition.expected(size > 0, ERROR_MSG_MAX_SIZE_AT_LEAST_ONE);
byte[] result = new byte[size];
for (int i = 0; i < size; ++i) {
result[i] = aByte();
}
return result;
}
/**
* Create an array with random content.
*
* @param size
* the number of the elements
* @return a short array with {@code size}
*/
public static short[] shortArray(int size) {
Condition.expected(size > 0, ERROR_MSG_MAX_SIZE_AT_LEAST_ONE);
short[] result = new short[size];
for (int i = 0; i < size; ++i) {
result[i] = aShort();
}
return result;
}
/**
* Create an array with random content.
*
* @param size
* the number of the elements
* @return a int array with {@code size}
*/
public static int[] intArray(int size) {
Condition.expected(size > 0, ERROR_MSG_MAX_SIZE_AT_LEAST_ONE);
int[] result = new int[size];
for (int i = 0; i < size; ++i) {
result[i] = anInt();
}
return result;
}
/**
* Create an array with random content.
*
* @param size
* the number of the elements
* @return a long array with {@code size}
*/
public static long[] longArray(int size) {
Condition.expected(size > 0, ERROR_MSG_MAX_SIZE_AT_LEAST_ONE);
long[] result = new long[size];
for (int i = 0; i < size; ++i) {
result[i] = aLong();
}
return result;
}
/**
* Create an array with random content.
*
* @param size
* the number of the elements
* @return a float array with {@code size}
*/
public static float[] floatArray(int size) {
Condition.expected(size > 0, ERROR_MSG_MAX_SIZE_AT_LEAST_ONE);
float[] result = new float[size];
for (int i = 0; i < size; ++i) {
result[i] = aFloat();
}
return result;
}
/**
* Create an array with random content.
*
* @param size
* the number of the elements
* @return a double array with {@code size}
*/
public static double[] doubleArray(int size) {
Condition.expected(size > 0, ERROR_MSG_MAX_SIZE_AT_LEAST_ONE);
double[] result = new double[size];
for (int i = 0; i < size; ++i) {
result[i] = aDouble();
}
return result;
}
/**
* Add to the {@code list} new elements using the {@code randomSupplier} method.
*
* @param list
* the target list
* @param itemType
* the class of the list elements
* @param randomSupplier
* a supplier that provide a pseudo random new element (has one parameter the {@code itemType})
* @param size
* the desired number of element to add to the list
* @param
* the type of the list elements
*/
public static void fillToSize(List list, Class itemType, Function, T> randomSupplier, int size) {
for (int i = 0; i < size; ++i) {
list.add(randomSupplier.apply(itemType));
}
}
/**
* Add to the {@code list} new elements using the {@code randomSupplier} method.
*
* @param list
* the target list
* @param randomSupplier
* a supplier that provide a pseudo random new element
* @param size
* the desired number of element to add to the list
* @param
* the type of the list elements
*/
public static void fillToSize(List list, Supplier randomSupplier, int size) {
for (int i = 0; i < size; ++i) {
list.add(randomSupplier.get());
}
}
/**
* It will call the {@code newInstance} method through the {@code targetClass} and create a new object. If something goes wrong, it will throw an
* {@code UnexpectedException}.
*
* @param targetClass
* the class of the target type
* @param
* the target type
* @return a new element
*/
// TODO: move seperated class
public static Supplier createEntity(final Class targetClass) {
return () -> {
C instance = null;
try {
instance = targetClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
Condition.shouldNeverThrown("Failed to create the target class", e);
}
return instance;
};
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy