Skip to content

Commit 3845b21

Browse files
committed
Fixed bug in FingerTree.append(). Added PropertyTestRunner, SeqProperties and Arbitrary.arbSeq().
1 parent 435cdac commit 3845b21

4 files changed

Lines changed: 188 additions & 1 deletion

File tree

core/src/main/java/fj/data/fingertrees/Deep.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ private static final <V, A> FingerTree<V, A> deepR(final Measured<V, A> measured
155155
@Override public FingerTree<V, A> append(final FingerTree<V, A> t) {
156156
final Measured<V, A> m = measured();
157157
return t.match(
158-
constant(t),
158+
constant(this),
159159
single -> snoc(single.value()),
160160
deep -> new Deep<>(m, m.sum(measure(), deep.measure()), prefix,
161161
addDigits0(m, middle, suffix, deep.prefix, deep.middle), deep.suffix));

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,6 +761,16 @@ public Array<A> f(final List<A> as) {
761761
}));
762762
}
763763

764+
/**
765+
* Returns an arbitrary implementation for sequences.
766+
*
767+
* @param aa An arbitrary implementation for the type over which the sequence is defined.
768+
* @return An arbitrary implementation for sequences.
769+
*/
770+
public static <A> Arbitrary<Seq<A>> arbSeq(final Arbitrary<A> aa) {
771+
return arbitrary(arbArray(aa).gen.map(array -> Seq.seq((A[]) array.array())));
772+
}
773+
764774
/**
765775
* Returns an arbitrary implementation for throwables.
766776
*
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package fj.data.properties;
2+
3+
4+
import fj.Function;
5+
import fj.P;
6+
import fj.P2;
7+
import fj.data.Option;
8+
import fj.data.Seq;
9+
import fj.runner.PropertyTestRunner;
10+
import fj.test.Arbitrary;
11+
import fj.test.Gen;
12+
import fj.test.Property;
13+
import org.junit.Assert;
14+
import org.junit.Test;
15+
import org.junit.runner.RunWith;
16+
import org.junit.runners.BlockJUnit4ClassRunner;
17+
18+
import static fj.Function.identity;
19+
import static fj.data.Option.none;
20+
import static fj.data.Option.some;
21+
import static fj.test.Arbitrary.arbInteger;
22+
import static fj.test.Arbitrary.arbSeq;
23+
import static fj.test.Property.implies;
24+
import static fj.test.Property.prop;
25+
import static fj.test.Property.property;
26+
27+
/**
28+
* Created by Zheka Kozlov on 01.06.2015.
29+
*/
30+
@RunWith(PropertyTestRunner.class)
31+
public class SeqProperties {
32+
33+
public Property consHead() {
34+
return property(arbSeq(arbInteger), arbInteger, (seq, n) -> prop(seq.cons(n).head().equals(n)));
35+
}
36+
37+
public Property consLength() {
38+
return property(arbSeq(arbInteger), arbInteger, (seq, n) -> prop(seq.cons(n).length() == seq.length() + 1));
39+
}
40+
41+
public Property snocLast() {
42+
return property(arbSeq(arbInteger), arbInteger, (seq, n) -> prop(seq.snoc(n).last().equals(n)));
43+
}
44+
45+
public Property snocLength() {
46+
return property(arbSeq(arbInteger), arbInteger, (seq, n) -> prop(seq.snoc(n).length() == seq.length() + 1));
47+
}
48+
49+
public Property appendEmptyLeft() {
50+
return property(arbSeq(arbInteger), seq -> prop(Seq.<Integer>empty().append(seq).equals(seq)));
51+
}
52+
53+
public Property appendEmptyRight() {
54+
return property(arbSeq(arbInteger), seq -> prop(seq.append(Seq.empty()).equals(seq)));
55+
}
56+
57+
public Property appendLength() {
58+
return property(arbSeq(arbInteger), arbSeq(arbInteger), (seq1, seq2) ->
59+
prop(seq1.append(seq2).length() == seq1.length() + seq2.length()));
60+
}
61+
62+
public Property consNotEmpty() {
63+
return property(arbSeq(arbInteger), arbInteger, (seq, n) -> prop(!seq.cons(n).isEmpty()));
64+
}
65+
66+
public Property snocNotEmpty() {
67+
return property(arbSeq(arbInteger), arbInteger, (seq, n) -> prop(!seq.snoc(n).isEmpty()));
68+
}
69+
70+
public Property appendSingleLeft() {
71+
return property(arbSeq(arbInteger), arbInteger, (seq, n) -> prop(Seq.single(n).append(seq).equals(seq.cons(n))));
72+
}
73+
74+
public Property appendSingleRight() {
75+
return property(arbSeq(arbInteger), arbInteger, (seq, n) -> prop(seq.append(Seq.single(n)).equals(seq.snoc(n))));
76+
}
77+
78+
public Property splitLength() {
79+
return property(arbSeq(arbInteger), arbInteger, (seq, i) -> prop(seq.length() == seq.split(i)._1().length() + seq.split(i)._2().length()));
80+
}
81+
82+
public Property tailLength() {
83+
return property(arbSeq(arbInteger), seq ->
84+
Property.implies(!seq.isEmpty(), P.lazy(() -> prop(seq.length() == 1 + seq.tail().length()))));
85+
}
86+
87+
public Property initLength() {
88+
return property(arbSeq(arbInteger), seq ->
89+
Property.implies(!seq.isEmpty(), P.lazy(() -> prop(seq.length() == seq.init().length() + 1))));
90+
}
91+
92+
public Property mapId() {
93+
return property(arbSeq(arbInteger), seq -> prop(seq.map(identity()).equals(seq)));
94+
}
95+
96+
public Property updateAndIndex() {
97+
final Gen<P2<Seq<Integer>, Option<Integer>>> gen = arbSeq(arbInteger).gen.bind(seq -> {
98+
if (seq.isEmpty()) {
99+
return Gen.value(P.p(seq, none()));
100+
} else {
101+
return Gen.choose(0, seq.length() - 1).map(i -> P.p(seq, some(i)));
102+
}
103+
});
104+
105+
return property(Arbitrary.arbitrary(gen), arbInteger, (pair, n) ->
106+
implies(pair._2().isSome(), P.lazy(() -> {
107+
final Seq<Integer> seq = pair._1();
108+
final int index = pair._2().some();
109+
return prop(seq.update(index, n).index(index).equals(n));
110+
})));
111+
}
112+
113+
public Property foldLeft() {
114+
return property(arbSeq(Arbitrary.arbitrary(Gen.value(1))), seq ->
115+
prop(seq.foldLeft((acc, i) -> acc + i, 0) == seq.length()));
116+
}
117+
118+
public Property foldRight() {
119+
return property(arbSeq(Arbitrary.arbitrary(Gen.value(1))), seq ->
120+
prop(seq.foldRight((i, acc) -> acc + i, 0) == seq.length()));
121+
}
122+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package fj.runner;
2+
3+
import org.junit.runner.Description;
4+
import org.junit.runner.Runner;
5+
import org.junit.runner.notification.Failure;
6+
import org.junit.runner.notification.RunNotifier;
7+
8+
import fj.P3;
9+
import fj.data.Option;
10+
import fj.test.CheckResult;
11+
import fj.test.Property;
12+
import fj.test.reflect.Check;
13+
import fj.test.reflect.CheckParams;
14+
15+
public class PropertyTestRunner extends Runner {
16+
private final Class<?> clas;
17+
18+
public PropertyTestRunner(Class<?> clas) {
19+
this.clas = clas;
20+
}
21+
22+
@Override
23+
public Description getDescription() {
24+
Description suite = Description.createSuiteDescription(clas);
25+
for (P3<Property, String, Option<CheckParams>> p : Check.properties(clas)) {
26+
suite.addChild(Description.createTestDescription(clas, p._2()));
27+
}
28+
return suite;
29+
}
30+
31+
@Override
32+
public void run(RunNotifier notifier) {
33+
for (P3<Property, String, Option<CheckParams>> p : Check.properties(clas)) {
34+
Description desc = Description.createTestDescription(clas, p._2());
35+
notifier.fireTestStarted(desc);
36+
CheckResult result = checkProperty(p._1(), p._3());
37+
38+
try {
39+
CheckResult.summaryEx.showS(result);
40+
} catch (Throwable t) {
41+
notifier.fireTestFailure(new Failure(desc, t));
42+
}
43+
44+
notifier.fireTestFinished(desc);
45+
}
46+
}
47+
48+
private static CheckResult checkProperty(Property prop, Option<CheckParams> params) {
49+
for (CheckParams ps : params) {
50+
return prop.check(ps.minSuccessful(), ps.maxDiscarded(), ps.minSize(), ps.maxSize());
51+
}
52+
53+
return prop.check();
54+
}
55+
}

0 commit comments

Comments
 (0)