Skip to content

Commit 69b3865

Browse files
committed
Fixed bugs in standard random generator, Gen.listOf(). Added Arbitrary.arbNonEmptyList(), NonEmptyList.tail(), NonEmptyList.head(), NonEmptyList.equals(), NonEmptyList.toString(), NonEmptyListProperties.
1 parent 3845b21 commit 69b3865

6 files changed

Lines changed: 99 additions & 58 deletions

File tree

core/src/main/java/fj/data/NonEmptyList.java

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
package fj.data;
22

3+
import fj.Equal;
34
import fj.F;
45
import fj.F1Functions;
6+
import fj.Show;
57
import fj.function.Effect1;
68

7-
import static fj.data.Option.some;
8-
import static fj.data.Option.somes;
9-
109
import java.util.Collection;
1110
import java.util.Iterator;
1211

12+
import static fj.data.Option.some;
13+
import static fj.data.Option.somes;
14+
1315
/**
1416
* Provides an in-memory, immutable, singly linked list with total <code>head</code> and <code>tail</code>.
1517
*
@@ -26,17 +28,19 @@ public Iterator<A> iterator() {
2628
return toCollection().iterator();
2729
}
2830

31+
private final A head;
32+
33+
private final List<A> tail;
34+
2935
/**
3036
* The first element of this linked list.
3137
*/
32-
@SuppressWarnings({"PublicField", "ClassEscapesDefinedScope"})
33-
public final A head;
38+
public A head() { return head; }
3439

3540
/**
3641
* This list without the first element.
3742
*/
38-
@SuppressWarnings({"PublicField"})
39-
public final List<A> tail;
43+
public List<A> tail() { return tail; }
4044

4145
private NonEmptyList(final A head, final List<A> tail) {
4246
this.head = head;
@@ -53,6 +57,13 @@ public NonEmptyList<A> cons(final A a) {
5357
return nel(a, tail.cons(head));
5458
}
5559

60+
/**
61+
* The length of this list.
62+
*
63+
* @return The length of this list.
64+
*/
65+
public int length() { return 1 + tail.length(); }
66+
5667
/**
5768
* Appends the given list to this list.
5869
*
@@ -203,4 +214,17 @@ public static <A> Option<NonEmptyList<A>> fromList(final List<A> as) {
203214
Option.<NonEmptyList<A>>none() :
204215
some(nel(as.head(), as.tail()));
205216
}
217+
218+
/**
219+
* Perform an equality test on this list which delegates to the .equals() method of the member instances.
220+
* This is implemented with Equal.nonEmptyListEqual using the anyEqual rule.
221+
*
222+
* @param obj the other object to check for equality against.
223+
* @return true if this list is equal to the provided argument
224+
*/
225+
@Override public boolean equals( final Object obj ) {
226+
return Equal.equals0(NonEmptyList.class, this, obj, () -> Equal.nonEmptyListEqual(Equal.<A>anyEqual()));
227+
}
228+
229+
@Override public String toString() { return Show.nonEmptyListShow(Show.<A>anyShow()).showS(this); }
206230
}

core/src/main/java/fj/test/Arbitrary.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,10 @@ public static <A> Arbitrary<List<A>> arbList(final Arbitrary<A> aa) {
733733
return arbitrary(listOf(aa.gen));
734734
}
735735

736+
public static <A> Arbitrary<NonEmptyList<A>> arbNonEmptyList(final Arbitrary<A> aa) {
737+
return arbitrary(Gen.listOf1(aa.gen).map(list -> NonEmptyList.fromList(list).some()));
738+
}
739+
736740
/**
737741
* Returns an arbitrary implementation for streams.
738742
*

core/src/main/java/fj/test/Gen.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -554,15 +554,7 @@ public Gen<A> f(final Integer i) {
554554
* @return A generator of lists whose values come from the given generator.
555555
*/
556556
public static <A> Gen<List<A>> listOf(final Gen<A> g, final int x) {
557-
return sized(new F<Integer, Gen<List<A>>>() {
558-
public Gen<List<A>> f(final Integer size) {
559-
return choose(x, size).bind(new F<Integer, Gen<List<A>>>() {
560-
public Gen<List<A>> f(final Integer n) {
561-
return sequenceN(n, g);
562-
}
563-
});
564-
}
565-
});
557+
return sized(size -> choose(x, max(x, size)).bind(n -> sequenceN(n, g)));
566558
}
567559

568560
/**
@@ -576,7 +568,7 @@ public static <A> Gen<List<A>> listOf(final Gen<A> g) {
576568
}
577569

578570
/**
579-
* Returns a generator of lists whose values come from the given generator.
571+
* Returns a generator of non empty lists whose values come from the given generator.
580572
*
581573
* @param g The generator to produce values from for the returned generator.
582574
* @return A generator of lists whose values come from the given generator.

core/src/main/java/fj/test/Rand.java

Lines changed: 10 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -124,38 +124,15 @@ public Random f(final Long x) {
124124
/**
125125
* A standard random generator that uses {@link Random}.
126126
*/
127-
public static final Rand standard = new Rand(new F<Option<Long>, F<Integer, F<Integer, Integer>>>() {
128-
public F<Integer, F<Integer, Integer>> f(final Option<Long> seed) {
129-
return new F<Integer, F<Integer, Integer>>() {
130-
public F<Integer, Integer> f(final Integer from) {
131-
return new F<Integer, Integer>() {
132-
public Integer f(final Integer to) {
133-
if(from == to){
134-
return from;
135-
}else{
136-
final int f = min(from, to);
137-
final int t = max(from, to);
138-
final int x = Math.abs(t - f);
139-
return f + seed.map(fr).orSome(new Random()).nextInt(x == Integer.MIN_VALUE ? Integer.MAX_VALUE : x);
140-
}
141-
}
142-
};
143-
}
144-
};
145-
}
146-
}, new F<Option<Long>, F<Double, F<Double, Double>>>() {
147-
public F<Double, F<Double, Double>> f(final Option<Long> seed) {
148-
return new F<Double, F<Double, Double>>() {
149-
public F<Double, Double> f(final Double from) {
150-
return new F<Double, Double>() {
151-
public Double f(final Double to) {
152-
final double f = min(from, to);
153-
final double t = max(from, to);
154-
return seed.map(fr).orSome(new Random()).nextDouble() * (t - f) + f;
155-
}
156-
};
157-
}
158-
};
159-
}
127+
public static final Rand standard = new Rand(seed -> from -> to -> {
128+
final int min = min(from, to);
129+
final int max = max(from, to);
130+
final Random random = seed.map(fr).orSome(new Random());
131+
return (int) ((random.nextLong() & Long.MAX_VALUE) % (1L + max - min)) + min;
132+
}, seed -> from -> to -> {
133+
final double min = min(from, to);
134+
final double max = max(from, to);
135+
final Random random = seed.map(fr).orSome(new Random());
136+
return random.nextDouble() * (max - min) + min;
160137
});
161138
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package fj.data.properties;
2+
3+
import fj.runner.PropertyTestRunner;
4+
import fj.test.Property;
5+
import org.junit.runner.RunWith;
6+
7+
import static fj.Function.identity;
8+
import static fj.data.NonEmptyList.nel;
9+
import static fj.test.Arbitrary.arbInteger;
10+
import static fj.test.Arbitrary.arbNonEmptyList;
11+
import static fj.test.Property.prop;
12+
import static fj.test.Property.property;
13+
14+
/**
15+
* Created by Zheka Kozlov on 02.06.2015.
16+
*/
17+
@RunWith(PropertyTestRunner.class)
18+
public class NonEmptyListProperties {
19+
20+
public Property consHead() {
21+
return property(arbNonEmptyList(arbInteger), arbInteger, (list, n) -> prop(list.cons(n).head().equals(n)));
22+
}
23+
24+
public Property consLength() {
25+
return property(arbNonEmptyList(arbInteger), arbInteger, (list, n) -> prop(list.cons(n).length() == list.length() + 1));
26+
}
27+
28+
public Property positiveLength() {
29+
return property(arbNonEmptyList(arbInteger), list -> prop(list.length() > 0));
30+
}
31+
32+
public Property appendLength() {
33+
return property(arbNonEmptyList(arbInteger), arbNonEmptyList(arbInteger), (list1, list2) ->
34+
prop(list1.append(list2).length() == list1.length() + list2.length()));
35+
}
36+
37+
public Property appendSingle() {
38+
return property(arbNonEmptyList(arbInteger), arbInteger, (list, n) -> prop(nel(n).append(list).equals(list.cons(n))));
39+
}
40+
41+
public Property tailLength() {
42+
return property(arbNonEmptyList(arbInteger), list -> prop(list.length() == 1 + list.tail().length()));
43+
}
44+
45+
public Property mapId() {
46+
return property(arbNonEmptyList(arbInteger), list -> prop(list.map(identity()).equals(list)));
47+
}
48+
}

core/src/test/java/fj/data/properties/SeqProperties.java

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package fj.data.properties;
22

33

4-
import fj.Function;
54
import fj.P;
65
import fj.P2;
76
import fj.data.Option;
@@ -10,10 +9,7 @@
109
import fj.test.Arbitrary;
1110
import fj.test.Gen;
1211
import fj.test.Property;
13-
import org.junit.Assert;
14-
import org.junit.Test;
1512
import org.junit.runner.RunWith;
16-
import org.junit.runners.BlockJUnit4ClassRunner;
1713

1814
import static fj.Function.identity;
1915
import static fj.data.Option.none;
@@ -81,12 +77,12 @@ public Property splitLength() {
8177

8278
public Property tailLength() {
8379
return property(arbSeq(arbInteger), seq ->
84-
Property.implies(!seq.isEmpty(), P.lazy(() -> prop(seq.length() == 1 + seq.tail().length()))));
80+
implies(!seq.isEmpty(), () -> prop(seq.length() == 1 + seq.tail().length())));
8581
}
8682

8783
public Property initLength() {
8884
return property(arbSeq(arbInteger), seq ->
89-
Property.implies(!seq.isEmpty(), P.lazy(() -> prop(seq.length() == seq.init().length() + 1))));
85+
implies(!seq.isEmpty(), () -> prop(seq.length() == seq.init().length() + 1)));
9086
}
9187

9288
public Property mapId() {
@@ -103,11 +99,11 @@ public Property updateAndIndex() {
10399
});
104100

105101
return property(Arbitrary.arbitrary(gen), arbInteger, (pair, n) ->
106-
implies(pair._2().isSome(), P.lazy(() -> {
102+
implies(pair._2().isSome(), () -> {
107103
final Seq<Integer> seq = pair._1();
108104
final int index = pair._2().some();
109105
return prop(seq.update(index, n).index(index).equals(n));
110-
})));
106+
}));
111107
}
112108

113109
public Property foldLeft() {

0 commit comments

Comments
 (0)