CoreRandomizers.java
/**
* Copyright (C) 2022 Christopher J. Stehno
*
* 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.
*/
package io.github.cjstehno.testthings.rando;
import lombok.NoArgsConstructor;
import lombok.val;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Stream;
import static io.github.cjstehno.testthings.rando.SharedRandom.current;
import static lombok.AccessLevel.PRIVATE;
/**
* Defines the core randomizers.
*/
@NoArgsConstructor(access = PRIVATE)
public final class CoreRandomizers {
/**
* Defines a randomizer which will always return the same value... so not really random at all.
*
* @param value the value to be returned
* @param <V> the type of the generated value
* @return the randomizer
*/
public static <V> Randomizer<V> constant(final V value) {
return () -> value;
}
/**
* A randomizer that returns a value from a collection of values.
*
* @param options the available options
* @param <V> the type of the generated value
* @return the randomizer
*/
@SafeVarargs
public static <V> Randomizer<V> oneOf(final V... options) {
return () -> options[current().nextInt(options.length)];
}
/**
* A randomizer that returns a value from one of the defined enum values.
*
* @param enumType the type of enum (provides the values)
* @param <V> the type of generated value
* @return the randomizer
*/
@SuppressWarnings("unchecked")
public static <V extends Enum<V>> Randomizer<V> oneOf(final Class<V> enumType) {
try {
return oneOf((V[]) enumType.getMethod("values").invoke(enumType));
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
/**
* A randomizer which will randomly select a value from the collection, popping that value off so that each value
* will only be used once.
*
* @param values the collection of values
* @param <V> the type of the generated value
* @return the randomizer
*/
public static <V> Randomizer<V> onceEachOf(final Collection<V> values) {
return new OnceEachRandomizer<>(values);
}
private static class OnceEachRandomizer<V> implements Randomizer<V> {
private final List<V> values = new CopyOnWriteArrayList<>();
private OnceEachRandomizer(final Collection<V> values) {
this.values.addAll(values);
}
@Override public V one() {
return values.isEmpty() ? null : values.remove(current().nextInt(values.size()));
}
}
/**
* A randomizer which will generate a list of random values. The size of the generated list is also random.
*
* @param countRando the randomizer used to determine the list size
* @param valueRando the randomizer used to determine the list values
* @param <V> the type of the generated value
* @return the randomizer
*/
public static <V> Randomizer<List<V>> listOf(final Randomizer<Integer> countRando, final Randomizer<V> valueRando) {
return () -> valueRando.many(countRando.one());
}
/**
* A randomizer which will generate a set of random values. The size of the generated set is also random.
*
* @param countRando the randomizer used to determine the set size
* @param valueRando the randomizer used to determine the set values
* @param <V> the type of the generated value
* @return the randomizer
*/
public static <V> Randomizer<Set<V>> setOf(final Randomizer<Integer> countRando, final Randomizer<V> valueRando) {
return () -> new HashSet<>(valueRando.many(countRando.one()));
}
/**
* A randomizer which will generate a map of random values. The size of the generated map is also random.
*
* @param countRando the randomizer used to determine the map size
* @param keyRando the randomizer used to determine the map keys
* @param valueRando the randomizer used to determine the map values
* @param <K> the type of the key value
* @param <V> the type of the generated value
* @return the randomizer
*/
public static <K, V> Randomizer<Map<K, V>> mapOf(final Randomizer<Integer> countRando, final Randomizer<K> keyRando, final Randomizer<V> valueRando) {
return () -> {
val map = new LinkedHashMap<K, V>();
for (int i = 0; i < countRando.one(); i++) {
map.put(keyRando.one(), valueRando.one());
}
return map;
};
}
/**
* Given a map containing Randomizers mapped to keys, the generated randomizer will generate random values for the
* mapped keys, based on the configured randomizers.
*
* @param randomizers the map of keys to randomizers
* @return the randomizer
* @param <K> the key type
* @param <V> the value type
*/
public static <K,V> Randomizer<Map<K,V>> mapOf(final Map<K, Randomizer<V>> randomizers){
return ()->{
val output = new LinkedHashMap<K,V>();
randomizers.forEach((key, rando) -> output.put(key, rando.one()));
return output;
};
}
/**
* A randomizer which will generate an array of random values. The size of the generated array is also random.
*
* @param countRando the randomizer used to determine the array size
* @param valueRando the randomizer used to determine the array values
* @param <V> the type of the generated value
* @return the randomizer
*/
@SuppressWarnings("unchecked")
public static <V> Randomizer<V[]> arrayOf(final Randomizer<Integer> countRando, final Randomizer<V> valueRando) {
return () -> valueRando.many(countRando.one()).toArray((V[]) new Object[0]);
}
/**
* A randomizer which will generate a stream of random values. The size of the generated stream is also random.
*
* @param countRando the randomizer used to determine the stream size
* @param valueRando the randomizer used to determine the stream values
* @param <V> the type of the generated value
* @return the randomizer
*/
public static <V> Randomizer<Stream<V>> streamOf(final Randomizer<Integer> countRando, final Randomizer<V> valueRando) {
return () -> valueRando.stream(countRando.one());
}
}