javaslang.test.Arbitrary Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of javaslang-test Show documentation
Show all versions of javaslang-test Show documentation
A property check framework for Javaslang.
/* / \____ _ _ ____ ______ / \ ____ __ _______
* / / \/ \ / \/ \ / /\__\/ // \/ \ // /\__\ JΛVΛSLΛNG
* _/ / /\ \ \/ / /\ \\__\\ \ // /\ \ /\\/ \ /__\ \ Copyright 2014-2017 Javaslang, http://javaslang.io
* /___/\_/ \_/\____/\_/ \_/\__\/__/\__\_/ \_// \__/\_____/ Licensed under the Apache License, Version 2.0
*/
package javaslang.test;
import javaslang.collection.Iterator;
import javaslang.collection.List;
import javaslang.collection.Stream;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
/**
* Represents an arbitrary object of type T.
*
* @param The type of the arbitrary object.
* @author Daniel Dietrich
* @since 1.2.0
*/
@FunctionalInterface
public interface Arbitrary {
/**
* Returns a generator for objects of type T.
* Use {@link Gen#map(Function)} and {@link Gen#flatMap(Function)} to
* combine object generators.
*
* Example:
*
*
* // represents arbitrary binary trees of a certain depth n
* final class ArbitraryTree implements Arbitrary<BinaryTree<Integer>> {
* @Override
* public Gen<BinaryTree<Integer>> apply(int n) {
* return Gen.choose(-1000, 1000).flatMap(value -> {
* if (n == 0) {
* return Gen.of(BinaryTree.leaf(value));
* } else {
* return Gen.frequency(
* Tuple.of(1, Gen.of(BinaryTree.leaf(value))),
* Tuple.of(4, Gen.of(BinaryTree.branch(apply(n / 2).get(), value, apply(n / 2).get())))
* );
* }
* });
* }
* }
*
* // tree generator with a size hint of 10
* final Gen<BinaryTree<Integer>> treeGen = new ArbitraryTree().apply(10);
*
* // stream sum of tree node values to console for 100 arbitrary trees
* Stream.of(() -> treeGen.apply(RNG.get())).map(Tree::sum).take(100).stdout();
*
*
*
* @param size A (not necessarily positive) size parameter which may be interpreted individually and is constant for all arbitrary objects regarding one property check.
* @return A generator for objects of type T.
*/
Gen apply(int size);
/**
* Returns an Arbitrary based on this Arbitrary which produces values that fulfill the given predicate.
*
* @param predicate A predicate
* @return A new generator
*/
default Arbitrary filter(Predicate super T> predicate) {
return size -> apply(size).filter(predicate);
}
/**
* Maps arbitrary objects T to arbitrary object U.
*
* @param mapper A function that maps arbitrary Ts to arbitrary Us given a mapper.
* @param New type of arbitrary objects
* @return A new Arbitrary
*/
default Arbitrary flatMap(Function super T, ? extends Arbitrary extends U>> mapper) {
return size -> {
final Gen gen = apply(size);
return random -> mapper.apply(gen.apply(random)).apply(size).apply(random);
};
}
/**
* Maps arbitrary objects T to arbitrary object U.
*
* @param mapper A function that maps an arbitrary T to an object of type U.
* @param Type of the mapped object
* @return A new generator
*/
default Arbitrary map(Function super T, ? extends U> mapper) {
Objects.requireNonNull(mapper, "mapper is null");
return n -> {
final Gen generator = apply(n);
return random -> mapper.apply(generator.apply(random));
};
}
default Arbitrary peek(Consumer super T> action) {
return size -> apply(size).peek(action);
}
/**
* Transforms this {@code Arbitrary}.
*
* @param f A transformation
* @param Type of transformation result
* @return An instance of type {@code U}
* @throws NullPointerException if {@code f} is null
*/
default U transform(Function super Arbitrary, ? extends U> f) {
Objects.requireNonNull(f, "f is null");
return f.apply(this);
}
/**
* Generates arbitrary integer values.
*
* @return A new Arbitrary of Integer
*/
static Arbitrary integer() {
return size -> random -> Gen.choose(-size, size).apply(random);
}
/**
* Generates arbitrary strings based on a given alphabet represented by gen.
*
* Example:
*
*
* Arbitrary.string(
* Gen.frequency(
* Tuple.of(1, Gen.choose('A', 'Z')),
* Tuple.of(1, Gen.choose('a', 'z')),
* Tuple.of(1, Gen.choose('0', '9'))));
*
*
*
* @param gen A character generator
* @return a new Arbitrary of String
*/
static Arbitrary string(Gen gen) {
return size -> random -> Gen.choose(0, size).map(i -> {
final char[] chars = new char[i];
for (int j = 0; j < i; j++) {
chars[j] = gen.apply(random);
}
return new String(chars);
}).apply(random);
}
/**
* Generates arbitrary lists based on a given element generator arbitraryT.
*
* Example:
*
*
* Arbitrary.list(Arbitrary.integer());
*
*
*
* @param arbitraryT Arbitrary elements of type T
* @param Component type of the List
* @return a new Arbitrary of List<T>
*/
static Arbitrary> list(Arbitrary arbitraryT) {
return size -> {
final Gen genT = arbitraryT.apply(size);
return random -> Gen.choose(0, size).map(i -> {
List list = List.empty();
for (int j = 0; j < i; j++) {
final T element = genT.apply(random);
list = list.prepend(element);
}
return list;
}).apply(random);
};
}
/**
* Generates arbitrary streams based on a given element generator arbitraryT.
*
* Example:
*
*
* Arbitrary.stream(Arbitrary.integer());
*
*
*
* @param arbitraryT Arbitrary elements of type T
* @param Component type of the Stream
* @return a new Arbitrary of Stream<T>
*/
static Arbitrary> stream(Arbitrary arbitraryT) {
return size -> {
final Gen genT = arbitraryT.apply(size);
return random -> Gen.choose(0, size).map(i -> Stream.ofAll(new Iterator() {
int count = i;
@Override
public boolean hasNext() {
return count-- > 0;
}
@Override
public T next() {
return genT.apply(random);
}
})).apply(random);
};
}
}