Skip to content

Commit 3777c1f

Browse files
authored
Merge pull request functionaljava#343 from gliptak/coverage6
Implement Zipper Eq and Hash and add tests
2 parents 1849e1d + ae70d20 commit 3777c1f

File tree

4 files changed

+157
-26
lines changed

4 files changed

+157
-26
lines changed

core/src/main/java/fj/Equal.java

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,6 @@
11
package fj;
22

3-
import fj.data.Array;
4-
import fj.data.Either;
5-
import fj.data.LazyString;
6-
import fj.data.List;
7-
import fj.data.Natural;
8-
import fj.data.NonEmptyList;
9-
import fj.data.Option;
10-
import fj.data.Seq;
11-
import fj.data.Set;
12-
import fj.data.Stream;
13-
import fj.data.Tree;
14-
import fj.data.TreeMap;
15-
import fj.data.Validation;
16-
import fj.data.Writer;
3+
import fj.data.*;
174
import fj.data.hamt.BitSet;
185
import fj.data.hlist.HList;
196
import fj.data.vector.V2;
@@ -455,6 +442,21 @@ public static <A> Equal<Stream<A>> streamEqual(final Equal<A> ea) {
455442
});
456443
}
457444

445+
/**
446+
* An equal instance for the {@link Zipper} type.
447+
*
448+
* @param ea Equality across the elements of the zipper.
449+
* @return An equal instance for the {@link Zipper} type.
450+
*/
451+
public static <A> Equal<Zipper<A>> zipperEqual(final Equal<A> ea) {
452+
Equal<Stream<A>> se = Equal.streamEqual(ea);
453+
return equalDef((a1, a2) ->
454+
se.eq(a1.lefts(), a2.lefts()) &&
455+
ea.eq(a1.focus(), a2.focus()) &&
456+
se.eq(a1.rights(), a2.rights())
457+
);
458+
}
459+
458460
/**
459461
* An equal instance for the {@link Array} type.
460462
*

core/src/main/java/fj/Hash.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,26 @@ public static <A> Hash<Array<A>> arrayHash(final Hash<A> ha) {
262262
});
263263
}
264264

265+
/**
266+
* A hash instance for the {@link Zipper} type.
267+
*
268+
* @param ha A hash for the elements of the zipper.
269+
* @return A hash instance for the {@link Zipper} type.
270+
*/
271+
public static <A> Hash<Zipper<A>> zipperHash(final Hash<A> ha) {
272+
Hash<Stream<A>> sh = streamHash(ha);
273+
return hash(as -> {
274+
final int p = 419;
275+
int r = 239;
276+
277+
r = p * r + sh.hash(as.lefts());
278+
r = p * r + ha.hash(as.focus());
279+
r = p * r + sh.hash(as.rights());
280+
281+
return r;
282+
});
283+
}
284+
265285
/**
266286
* A hash instance for the {@link Tree} type.
267287
*

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

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

3-
import fj.Equal;
4-
import fj.F;
5-
import fj.F2;
6-
import fj.F2Functions;
7-
import fj.F3;
8-
import fj.Function;
9-
import fj.Ord;
10-
import fj.P;
11-
import fj.P1;
12-
import fj.P2;
13-
import fj.P3;
14-
import fj.Show;
3+
import fj.*;
154
import fj.function.Integers;
165

176
import java.util.Iterator;
@@ -106,6 +95,16 @@ public static <A> Ord<Zipper<A>> ord(final Ord<A> o) {
10695
return Ord.p3Ord(so, o, so).contramap(Zipper.p_());
10796
}
10897

98+
@Override
99+
public final boolean equals(Object other) {
100+
return Equal.equals0(Zipper.class, this, other, () -> Equal.zipperEqual(Equal.anyEqual()));
101+
}
102+
103+
@Override
104+
public final int hashCode() {
105+
return Hash.zipperHash(Hash.<A>anyHash()).hash(this);
106+
}
107+
109108
/**
110109
* An Equal instance for Zippers.
111110
*
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package fj.data;
2+
3+
import org.junit.Test;
4+
5+
import static org.hamcrest.core.Is.is;
6+
import static org.junit.Assert.assertThat;
7+
8+
public class ZipperTest {
9+
@Test
10+
public void testZipper() {
11+
Zipper<Integer> z = Zipper.zipper(Stream.nil(), 0, Stream.range(1, 9));
12+
assertThat(z.map(i -> i + 13).toStream(), is(Stream.range(13, 22)));
13+
}
14+
15+
@Test
16+
public void testNext() {
17+
Zipper<Integer> z = Zipper.zipper(Stream.single(1), 2, Stream.single(3));
18+
z = z.next().some();
19+
assertThat(z.lefts(), is(Stream.arrayStream(new Integer[]{2, 1})));
20+
assertThat(z.focus(), is(3));
21+
assertThat(z.rights(), is(Stream.nil()));
22+
}
23+
24+
@Test
25+
public void testNextNone() {
26+
Zipper<Integer> z = Zipper.zipper(Stream.single(1), 2, Stream.nil());
27+
assertThat(z.next().isNone(), is(true));
28+
}
29+
30+
@Test
31+
public void testCycleNext() {
32+
Zipper<Integer> z = Zipper.zipper(Stream.single(1), 2, Stream.single(3));
33+
assertThat(z.cycleNext(), is(z.next().some()));
34+
}
35+
36+
@Test
37+
public void testCycleNextLast() {
38+
Zipper<Integer> z = Zipper.zipper(Stream.single(1), 2, Stream.nil());
39+
z = z.cycleNext();
40+
assertThat(z.lefts(), is(Stream.nil()));
41+
assertThat(z.focus(), is(1));
42+
assertThat(z.rights(), is(Stream.single(2)));
43+
}
44+
45+
@Test
46+
public void testPrevious() {
47+
Zipper<Integer> z = Zipper.zipper(Stream.single(1), 2, Stream.single(3));
48+
z = z.previous().some();
49+
assertThat(z.lefts(), is(Stream.nil()));
50+
assertThat(z.focus(), is(1));
51+
assertThat(z.rights(), is(Stream.arrayStream(new Integer[]{2, 3})));
52+
}
53+
54+
@Test
55+
public void testPreviousNone() {
56+
Zipper<Integer> z = Zipper.zipper(Stream.nil(), 2, Stream.single(3));
57+
assertThat(z.previous().isNone(), is(true));
58+
}
59+
60+
@Test
61+
public void testCyclePrevious() {
62+
Zipper<Integer> z = Zipper.zipper(Stream.single(1), 2, Stream.single(3));
63+
assertThat(z.cyclePrevious(), is(z.previous().some()));
64+
}
65+
66+
@Test
67+
public void testCyclePreviousFirst() {
68+
Zipper<Integer> z = Zipper.zipper(Stream.nil(), 1, Stream.single(2));
69+
z = z.cyclePrevious();
70+
assertThat(z.lefts(), is(Stream.single(1)));
71+
assertThat(z.focus(), is(2));
72+
assertThat(z.rights(), is(Stream.nil()));
73+
}
74+
75+
@Test
76+
public void testInsertLeft() {
77+
Zipper<Integer> z = Zipper.single(2);
78+
z = z.insertLeft(1);
79+
assertThat(z.lefts(), is(Stream.nil()));
80+
assertThat(z.focus(), is(1));
81+
assertThat(z.rights(), is(Stream.single(2)));
82+
}
83+
84+
@Test
85+
public void testInsertRight() {
86+
Zipper<Integer> z = Zipper.single(2);
87+
z = z.insertRight(3);
88+
assertThat(z.lefts(), is(Stream.single(2)));
89+
assertThat(z.focus(), is(3));
90+
assertThat(z.rights(), is(Stream.nil()));
91+
}
92+
93+
@Test
94+
public void testDeleteOthers() {
95+
Zipper<Integer> z = Zipper.zipper(Stream.single(1), 2, Stream.single(3));
96+
z = z.deleteOthers();
97+
assertThat(z.lefts(), is(Stream.nil()));
98+
assertThat(z.focus(), is(2));
99+
assertThat(z.rights(), is(Stream.nil()));
100+
}
101+
102+
@Test
103+
public void testFind() {
104+
Zipper<Integer> z = Zipper.zipper(Stream.nil(), 0, Stream.range(1));
105+
z = z.find(i -> i == 4).some();
106+
assertThat(z.lefts(), is(Stream.arrayStream(new Integer[]{3, 2, 1, 0})));
107+
assertThat(z.focus(), is(4));
108+
assertThat(z.rights().take(3), is(Stream.range(5, 8)));
109+
}
110+
}

0 commit comments

Comments
 (0)