All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javaslang.test.Arbitrary Maven / Gradle / Ivy

There is a newer version: 2.1.0-alpha
Show newest version
/*     / \____  _    _  ____   ______  / \ ____  __    _______
 *    /  /    \/ \  / \/    \ /  /\__\/  //    \/  \  //  /\__\   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 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> 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 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 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, ? 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); }; } }