@Test public void generatorThatPicksOtherGeneratorAtRandomWeighted() { when(random.nextInt(6)).thenReturn(2); Gen<Integer> chooser = Gen.frequency( freq(1, pure(-1)), freq(2, pure(-2)), freq(3, pure(-3)) ); assertEquals( Integer.valueOf(-2), chooser.generate(random, new SimpleGenerationStatus(null, null, 0))); } }
/** * Gives a generation strategy that produces a random value by having this * strategy produce a random value, then applying the given function to * that value, and asking the result to produce a value. * * @param <U> type of values produced by the mapped generation strategy * @param mapper function that converts receiver's random values to * another kind of generation strategy * @return a new generation strategy */ default <U> Gen<U> flatMap(Function<? super T, ? extends Gen<? extends U>> mapper) { return (random, status) -> mapper.apply(_gen(random, status))._gen(random, status); }
@Test public void flatMap() { class Coordinate { final int x; final int y; private Coordinate(int x, int y) { this.x = x; this.y = y; } } Gen<Integer> five = (random, status) -> 5; Gen<Integer> six = (random, status) -> 6; Gen<Coordinate> flatMapped = five.flatMap(i -> six.map(j -> new Coordinate(i, j))); Coordinate generated = flatMapped.generate(null, status); assertEquals(5, generated.x); assertEquals(6, generated.y); } }
/** * @deprecated For use by junit-quickcheck only -- when we migrate to Java 9, * this method will likely become {@code private}. * * @param random source of randomness to be used when generating the value * @param status an object that can be used to influence the generated * value. For example, generating lists can use the {@link * GenerationStatus#size() size} method to generate lists with a given * number of elements. * @return the generated value */ @Deprecated default T _gen(SourceOfRandomness random, GenerationStatus status) { T result = generate(random, status); status.semiAttempt(); return result; } }
@Test public void filterOptional() { int[] i = { 0 }; Gen<Integer> ints = (random, status) -> i[0]++; Gen<Optional<Integer>> smaller = ints.filterOptional(n -> n < 2); int first = smaller.generate(null, status) .orElseThrow(AssertionError::new); assertEquals(0, first); int second = smaller.generate(null, status) .orElseThrow(AssertionError::new); assertEquals(1, second); assertEquals(Optional.empty(), smaller.generate(null, status)); assertEquals(3, i[0]); } }
/** * @deprecated For use by junit-quickcheck only -- when we migrate to Java 9, * this method will likely become {@code private}. * * @param random source of randomness to be used when generating the value * @param status an object that can be used to influence the generated * value. For example, generating lists can use the {@link * GenerationStatus#size() size} method to generate lists with a given * number of elements. * @return the generated value */ @Deprecated default T _gen(SourceOfRandomness random, GenerationStatus status) { T result = generate(random, status); status.semiAttempt(); return result; } }
@Override public Schema generate(SourceOfRandomness random, GenerationStatus status) { Map<String, Schema> schemaMap = IntStream.range(0, random.nextInt(0, status.size()) + 1) .mapToObj( i -> { // deterministically avoid collisions in record names branchPush(status, String.valueOf(i)); Schema schema = SchemaGenerator.INSTANCE // nested unions aren't supported in AVRO .filter(x -> x.getType() != Schema.Type.UNION) .generate(random, status); branchPop(status); return schema; }) // AVRO requires uniqueness by full name .collect(Collectors.toMap(Schema::getFullName, Function.identity(), (x, y) -> x)); List<Schema> schemas = new ArrayList<>(schemaMap.values()); if (random.nextBoolean()) { org.apache.avro.Schema nullSchema = org.apache.avro.Schema.create(Schema.Type.NULL); schemas.add(nullSchema); Collections.shuffle(schemas, random.toJDKRandom()); } return Schema.createUnion(schemas); } }
/** * Gives a generation strategy that produces a random value by having this * strategy produce a random value, then applying the given function to * that value, and returning the result. * * @param <U> type of values produced by the mapped generation strategy * @param mapper function that converts receiver's random values to * result's values * @return a new generation strategy */ default <U> Gen<U> map(Function<? super T, ? extends U> mapper) { return (random, status) -> mapper.apply(_gen(random, status)); }
/** * Gives a generation strategy that produces a random value by having this * strategy produce random values until one satisfies the given condition, * then using that value as the result. * * @param condition a condition the generated value is to meet * @return a new generation strategy */ default Gen<T> filter(Predicate<? super T> condition) { return (random, status) -> { T next = _gen(random, status); while (!condition.test(next)) { next = _gen(random, status); } return next; }; }
default Gen<List<T>> times(int times) { if (times < 0) throw new IllegalArgumentException("negative times: " + times); return (random, status) -> { List<T> values = new ArrayList<>(); for (int i = 0; i < times; ++i) values.add(_gen(random, status)); return values; }; }
/** * <p>Gives a generation strategy that produces a random value by having * this strategy produce a random value and wrapping it in an * {@link Optional}; if the value meets the given condition, the wrapping * optional will be {@linkplain Optional#isPresent() present}.</p> * * <p>If the value meets the condition but is {@code null}, the wrapping * optional will not be considered * {@linkplain Optional#isPresent() present}.</p> * * @param condition a condition the generated value is to meet * @return a new generation strategy */ default Gen<Optional<T>> filterOptional(Predicate<? super T> condition) { return (random, status) -> { T next = _gen(random, status); return condition.test(next) ? Optional.ofNullable(next) : Optional.empty(); }; }
/** * Gives a generation strategy that produces a random value by choosing * one of the given generators at random with (approximately) equal * probability, and having it generate a value. * * @param <U> type of values produced by the resulting strategy * @param first first possible generator choice * @param rest the other possible generator choices * @return a new generation strategy */ @SafeVarargs static <U> Gen<U> oneOf( Gen<? extends U> first, Gen<? extends U>... rest) { List<Gen<? extends U>> choices = new ArrayList<>(); choices.add(first); Collections.addAll(choices, rest); return (random, status) -> Items.choose(choices, random)._gen(random, status); }
/** * Gives a generation strategy that produces a random value by choosing * one of the given generators at random with probability in proportion * to their given weights, and having it generate a value. * * @param <U> type of values produced by the resulting strategy * @param first first possible (weighted) generator choice * @param rest the other possible (weighted) generator choices * @return a new generation strategy */ @SafeVarargs static <U> Gen<U> frequency( Pair<Integer, Gen<? extends U>> first, Pair<Integer, Gen<? extends U>>... rest) { List<Pair<Integer, Gen<? extends U>>> pairs = new ArrayList<>(); pairs.add(first); Collections.addAll(pairs, rest); List<Weighted<Gen<? extends U>>> weighted = pairs.stream() .map(p -> new Weighted<Gen<? extends U>>(p.second, p.first)) .collect(toList()); return (random, status) -> Items.chooseWeighted(weighted, random)._gen(random, status); }
/** * Gives a generation strategy that produces a random value by having this * strategy produce a random value, then applying the given function to * that value, and asking the result to produce a value. * * @param <U> type of values produced by the mapped generation strategy * @param mapper function that converts receiver's random values to * another kind of generation strategy * @return a new generation strategy */ default <U> Gen<U> flatMap(Function<? super T, ? extends Gen<? extends U>> mapper) { return (random, status) -> mapper.apply(_gen(random, status))._gen(random, status); }