Skip to content

Commit 69fbd1d

Browse files
committed
Add TreeZipper tests
Signed-off-by: Gábor Lipták <gliptak@gmail.com>
1 parent 21a73c4 commit 69fbd1d

File tree

5 files changed

+117
-4
lines changed

5 files changed

+117
-4
lines changed

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

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import fj.data.*;
44
import fj.data.hamt.BitSet;
55
import fj.data.hlist.HList;
6+
import fj.data.optic.Traversal;
67
import fj.data.vector.V2;
78
import fj.data.vector.V3;
89
import fj.data.vector.V4;
@@ -466,6 +467,25 @@ public static <A> Equal<Zipper<A>> zipperEqual(final Equal<A> ea) {
466467
}
467468

468469
/**
470+
* An equal instance for the {@link TreeZipper} type.
471+
*
472+
* @param ea Equality across the elements of the tree zipper.
473+
* @return An equal instance for the {@link TreeZipper} type.
474+
*/
475+
public static <A> Equal<TreeZipper<A>> treeZipperEqual(final Equal<A> ea) {
476+
final Equal<Tree<A>> te = Equal.treeEqual(ea);
477+
final Equal<Stream<Tree<A>>> st = streamEqual(Equal.treeEqual(ea));
478+
final Equal<Stream<P3<Stream<Tree<A>>, A, Stream<Tree<A>>>>> sp =
479+
streamEqual(p3Equal(streamEqual(treeEqual(ea)), ea, streamEqual(treeEqual(ea))));
480+
return equalDef((a1, a2) ->
481+
te.eq(a1.focus(), a2.focus()) &&
482+
st.eq(a1.lefts(), a2.lefts()) &&
483+
st.eq(a1.rights(), a2.rights()) &&
484+
sp.eq(a1.parents(), a2.parents())
485+
);
486+
}
487+
488+
/**
469489
* An equal instance for the {@link Array} type.
470490
*
471491
* @param ea Equality across the elements of the array.

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

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,7 +302,31 @@ public static <A> Hash<Zipper<A>> zipperHash(final Hash<A> ha) {
302302
});
303303
}
304304

305-
/**
305+
/**
306+
* A hash instance for the {@link TreeZipper} type.
307+
*
308+
* @param ha A hash for the elements of the tree zipper.
309+
* @return A hash instance for the {@link TreeZipper} type.
310+
*/
311+
public static <A> Hash<TreeZipper<A>> treeZipperHash(final Hash<A> ha) {
312+
Hash<Tree<A>> th = treeHash(ha);
313+
Hash<Stream<Tree<A>>> sth = streamHash(treeHash(ha));
314+
Hash<Stream<P3<Stream<Tree<A>>, A, Stream<Tree<A>>>>> tsp =
315+
streamHash(p3Hash(streamHash(treeHash(ha)), ha, streamHash(treeHash(ha))));
316+
return hash(as -> {
317+
final int p = 419;
318+
int r = 239;
319+
320+
r = p * r + th.hash(as.focus());
321+
r = p * r + sth.hash(as.lefts());
322+
r = p * r + sth.hash(as.rights());
323+
r = p * r + tsp.hash(as.parents());
324+
325+
return r;
326+
});
327+
}
328+
329+
/**
306330
* A hash instance for the {@link Tree} type.
307331
*
308332
* @param ha A hash for the elements of the tree.

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

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,17 @@ private TreeZipper(final Tree<A> tree,
5454
this.parents = parents;
5555
}
5656

57-
/**
57+
@Override
58+
public final boolean equals(Object other) {
59+
return Equal.equals0(TreeZipper.class, this, other, () -> Equal.treeZipperEqual(Equal.anyEqual()));
60+
}
61+
62+
@Override
63+
public final int hashCode() {
64+
return Hash.treeZipperHash(Hash.<A>anyHash()).hash(this);
65+
}
66+
67+
/**
5868
* Creates a new tree zipper given a currently selected tree, a forest on the left, a forest on the right,
5969
* and a stream of parent contexts.
6070
*
@@ -341,8 +351,17 @@ public Stream<Tree<A>> lefts() {
341351
* @return the right siblings of the currently focused node.
342352
*/
343353
public Stream<Tree<A>> rights() {
344-
return rights;
345-
}
354+
return rights;
355+
}
356+
357+
/**
358+
* Returns the parents of the currently focused node.
359+
*
360+
* @return the parents of the currently focused node.
361+
*/
362+
public Stream<P3<Stream<Tree<A>>, A, Stream<Tree<A>>>> parents() {
363+
return parents;
364+
}
346365

347366
/**
348367
* Indicates whether the current node is at the top of the tree.

core/src/test/java/fj/FFunctionsTest.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package fj;
22

3+
import fj.data.Tree;
4+
import fj.data.TreeZipper;
35
import org.junit.Test;
46
import static org.hamcrest.core.Is.is;
57
import static org.junit.Assert.*;
@@ -22,4 +24,20 @@ public void testApply() {
2224
F<Integer, Integer> f1 = F2Functions.f(f2, 2);
2325
assertThat(F1Functions.f(f1, 1).f(), is(36));
2426
}
27+
28+
@Test
29+
public void testTreeK() {
30+
final Tree<Integer> t1 = F1Functions.<Integer, Integer>treeK(Function.identity()).f(1);
31+
final Tree<Integer> t2 = F1Functions.<Integer, Integer>treeK(Function.identity()).f(2);
32+
assertThat(F1Functions.<Integer, Integer>mapTree(i -> i + 1).f(t1),
33+
is(F1Functions.<Integer, Integer>mapTree(i -> i * 1).f(t2)));
34+
}
35+
36+
@Test
37+
public void testTreeZipperK() {
38+
final TreeZipper<Integer> tz1 = F1Functions.<Integer, Integer>treeZipperK(Function.identity()).f(1);
39+
final TreeZipper<Integer> tz2 = F1Functions.<Integer, Integer>treeZipperK(Function.identity()).f(2);
40+
assertThat(F1Functions.<Integer, Integer>mapTreeZipper(i -> i + 1).f(tz1),
41+
is(F1Functions.<Integer, Integer>mapTreeZipper(i -> i * 1).f(tz2)));
42+
}
2543
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package fj.data;
2+
3+
import org.junit.Test;
4+
5+
import static fj.data.Option.none;
6+
import static org.hamcrest.core.Is.is;
7+
import static org.junit.Assert.assertThat;
8+
9+
public class TreeZipperTest {
10+
@Test
11+
public void testDelete() {
12+
final Tree<Integer> t = Tree.node(1, List.single(Tree.leaf(2)));
13+
final TreeZipper<Integer> tz = TreeZipper.fromTree(t);
14+
assertThat(tz.delete(), is(none()));
15+
}
16+
17+
@Test
18+
public void testDeleteForest() {
19+
final Tree<Integer> t = Tree.node(1, List.single(Tree.leaf(2)));
20+
final TreeZipper<Integer> tz = TreeZipper.fromForest(Stream.single(t)).some();
21+
assertThat(tz.delete(), is(none()));
22+
23+
}
24+
25+
@Test
26+
public void testHash() {
27+
final Tree<Integer> t = Tree.node(1, List.single(Tree.leaf(2)));
28+
final TreeZipper<Integer> tz1 = TreeZipper.fromForest(Stream.single(t)).some();
29+
final TreeZipper<Integer> tz2 = TreeZipper.fromForest(Stream.single(t)).some();
30+
assertThat(tz1.hashCode(), is(tz2.hashCode()));
31+
}
32+
}

0 commit comments

Comments
 (0)