summaryrefslogtreecommitdiff
path: root/src/main/java/au/id/zancanaro/javacheck/Generators.java
blob: bf1b1b3070b78e5bbe958a1d849bdfe7853e28d5 (about) (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
package au.id.zancanaro.javacheck;

import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.function.Function;
import java.util.function.Predicate;

public final class Generators {
    private Generators() {
    }

    public static <T> Generator<T> sized(Function<Integer, Generator<T>> makeGenerator) {
        return (random, size) -> makeGenerator.apply(size).generate(random, size);
    }

    public static <T> Generator<T> suchThat(Generator<T> gen, Predicate<T> predicate) {
        return (random, size) -> {
            RoseTree<T> result = gen.generate(random, size);
            if (predicate.test(result.getValue())) {
                return result.filter(predicate);
            } else {
                return suchThat(gen, predicate).generate(random, size);
            }
        };
    }

    @SafeVarargs
    public static <T> Generator<T> oneOf(Generator<T>... gens) {
        return integer(0, gens.length).flatMap(index -> gens[index]);
    }

    public static <T> Generator<T> elements(T[] elements) {
        return elements(Arrays.asList(elements));
    }

    public static <T> Generator<T> elements(List<T> elements) {
        return integer(0, elements.size()).map(elements::get);
    }

    public static Generator<Boolean> bool() {
        return (random, size) ->
                random.nextBoolean() ?
                        new RoseTree<>(true, Collections.singletonList(new RoseTree<>(false, Collections.emptyList()))) :
                        new RoseTree<>(false, Collections.emptyList());
    }

    public static Generator<Integer> integer(int lower, int upper) {
        return (random, size) -> {
            int value = lower + random.nextInt(upper - lower);
            int bound = lower > 0 ? lower : (upper < 0 ? upper : 0);
            return new RoseTree<>(value, intShrinkingIterable(value, bound));
        };
    }

    public static Generator<Integer> integer() {
        return sized(size -> integer(-size, size));
    }

    public static Generator<Integer> natural() {
        return sized(size -> integer(0, size));
    }

    private static Iterable<RoseTree<Integer>> intShrinkingIterable(final int value, final int bound) {
        return () -> new Iterator<RoseTree<Integer>>() {
            int curr = value - bound;

            @Override
            public boolean hasNext() {
                return curr != 0;
            }

            @Override
            public RoseTree<Integer> next() {
                int prevCurr = curr;
                curr = curr / 2;
                return new RoseTree<>(value - prevCurr, intShrinkingIterable(value - prevCurr, bound));
            }
        };
    }

    public static <T> Generator<List<T>> listOf(Generator<T> gen) {
        return (random, size) -> {
            Generator<Integer> countGen = sized(s -> integer(0, s));
            int count = countGen.generate(random, size).getValue();
            return Generator.list(count, gen).generate(random, size);
        };
    }

    public static Generator<Character> character() {
        return integer(0, 256).map(i -> (char) i.intValue());
    }

    public static Generator<Character> asciiCharacter() {
        return integer(32, 127).map(i -> (char) i.intValue());
    }

    public static Generator<Character> alphaNumericCharacter() {
        return oneOf(
                integer(48, 58),
                integer(65, 91),
                integer(97, 123)).map(i -> (char) i.intValue());
    }

    public static Generator<Character> alphaCharacter() {
        return oneOf(
                integer(65, 91),
                integer(97, 123)).map(i -> (char) i.intValue());
    }

    private static String makeString(Character[] arr) {
        StringBuilder builder = new StringBuilder(arr.length);
        for (Character c : arr) {
            builder.append(c);
        }
        return builder.toString();
    }

    public static Generator<String> string() {
        return stringOf(character());
    }

    public static Generator<String> stringOf(Generator<Character> charGen) {
        return listOf(charGen).map(list -> {
            char[] chars = new char[list.size()];
            int i = 0;
            for (Character c : list) {
                chars[i++] = c;
            }
            return String.valueOf(chars);
//            return new String(chars);
        });
    }
}