package com.googlecode.totallylazy.collections; import org.hamcrest.Matchers; import org.junit.Assert; import org.junit.Test; import java.util.NoSuchElementException; import static com.googlecode.totallylazy.Pair.pair; import static com.googlecode.totallylazy.collections.AVLTree.constructors.avlTree; import static com.googlecode.totallylazy.collections.PersistentList.constructors.list; import static com.googlecode.totallylazy.collections.TreeMap.functions.replace; import static com.googlecode.totallylazy.collections.TreeZipper.Breadcrumb.breadcrumb; import static com.googlecode.totallylazy.collections.TreeZipper.Direction.left; import static com.googlecode.totallylazy.collections.TreeZipper.Direction.right; import static com.googlecode.totallylazy.collections.TreeZipper.zipper; import static com.googlecode.totallylazy.matchers.Matchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.fail; public class TreeZipperTest { @Test public void canGoLeft() { final TreeZipper<Integer, Integer> zipper = zipper(avlTree(0, 0).insert(1, 1).insert(2, 2).insert(3, 3).insert(4, 4).insert(5, 5).insert(6, 6)); final TreeZipper<Integer, Integer> newZipper = zipper.left().left(); assertThat(newZipper.focus, is((TreeMap<Integer, Integer>) avlTree(0, 0))); assertThat(newZipper.breadcrumbs, is(list( breadcrumb(left, pair(1, 1), avlTree(2, 2)), breadcrumb(left, pair(3, 3), avlTree(4, 4).insert(5, 5).insert(6, 6))))); } @Test public void canGoRight() { final TreeZipper<Integer, Integer> zipper = zipper(avlTree(0, 0).insert(1, 1).insert(2, 2).insert(3, 3).insert(4, 4).insert(5, 5).insert(6, 6)); final TreeZipper<Integer, Integer> newZipper = zipper.right().right(); assertThat(newZipper.focus, is((TreeMap<Integer, Integer>) avlTree(6, 6))); assertThat(newZipper.breadcrumbs, is(list( breadcrumb(right, pair(5, 5), avlTree(4, 4)), breadcrumb(right, pair(3, 3), avlTree(0, 0).insert(1, 1).insert(2, 2))))); } @Test public void canGoUpFromRight() { final TreeZipper<Integer, Integer> zipper = zipper(avlTree(0, 0).insert(1, 1).insert(2, 2).insert(3, 3).insert(4, 4).insert(5, 5).insert(6, 6)); final TreeZipper<Integer, Integer> newZipper = zipper.right().right().up(); assertThat(newZipper.focus, is((TreeMap<Integer, Integer>) avlTree(4, 4).insert(5, 5).insert(6, 6))); assertThat(newZipper.breadcrumbs, is(list( breadcrumb(right, pair(3, 3), avlTree(0, 0).insert(1, 1).insert(2, 2))))); } @Test public void canGoUpFromLeft() { final TreeZipper<Integer, Integer> zipper = zipper(avlTree(0, 0).insert(1, 1).insert(2, 2).insert(3, 3).insert(4, 4).insert(5, 5).insert(6, 6)); final TreeZipper<Integer, Integer> newZipper = zipper.left().left().up(); assertThat(newZipper.focus, is((TreeMap<Integer, Integer>) avlTree(0, 0).insert(1, 1).insert(2, 2))); assertThat(newZipper.breadcrumbs, is(list( breadcrumb(left, pair(3, 3), avlTree(4, 4).insert(5, 5).insert(6, 6))))); } @Test public void canGoToTop() { final TreeZipper<Integer, Integer> zipper = zipper(avlTree(0, 0).insert(1, 1).insert(2, 2).insert(3, 3).insert(4, 4).insert(5, 5).insert(6, 6)); final TreeZipper<Integer, Integer> newZipper = zipper.left().left().top(); assertThat(newZipper.focus, is(zipper.focus)); assertThat(newZipper.breadcrumbs, is(PersistentList.constructors.<TreeZipper.Breadcrumb<Integer, Integer>>empty())); } @Test public void canReplaceElementInMiddleOfTree() { final TreeZipper<Integer, Integer> zipper = zipper(avlTree(0, 0).insert(10, 10).insert(20, 20)); final TreeZipper<Integer, Integer> newZipper = zipper.left().modify(replace(5, 5)); assertThat(newZipper.toTreeMap(), is((TreeMap<Integer, Integer>) avlTree(5, 5).insert(10, 10).insert(20, 20))); assertThat(newZipper.focus, is((TreeMap<Integer, Integer>) avlTree(5, 5))); assertThat(zipper.left().replace(5, 5).toTreeMap(), is((TreeMap<Integer, Integer>) avlTree(5, 5).insert(10, 10).insert(20, 20))); } @Test public void canPerformMultipleModifications() throws Exception { final TreeZipper<Integer, Integer> zipper = zipper(avlTree(0, 0).insert(1, 1).insert(2, 2).insert(3, 3).insert(4, 4).insert(5, 5).insert(6, 6)); final TreeZipper<Integer, Integer> newZipper = zipper.left().left().delete().delete(); assertThat(newZipper.toTreeMap(), is((TreeMap<Integer, Integer>) avlTree(2, 2).insert(3, 3).insert(4, 4).insert(5, 5).insert(6, 6))); } @Test public void canDelete() throws Exception { assertThat(zipper(avlTree(0, 0).insert(10, 10).insert(20, 20)).left().delete().toTreeMap(), is((TreeMap<Integer, Integer>) avlTree(10, 10).insert(20, 20))); } @Test public void canDeleteRootNode() throws Exception { assertThat(zipper(avlTree(0, 0).insert(10, 10).insert(20, 20)).delete().toTreeMap(), is((TreeMap<Integer, Integer>) avlTree(0, 0).insert(20, 20))); } @Test(expected = NoSuchElementException.class) public void throwsOnDeletingEmptyNode() throws Exception { zipper(avlTree(0, 0)).delete().delete().toTreeMap(); } @Test public void canGoToFirst() throws Exception { final TreeZipper<Integer, Integer> zipper = zipper(avlTree(0, 0).insert(1, 1).insert(2, 2).insert(3, 3).insert(4, 4).insert(5, 5).insert(6, 6)); final TreeZipper<Integer, Integer> newZipper = zipper.first(); assertThat(newZipper.focus.key(), is((0))); } @Test public void canGoToLast() throws Exception { final TreeZipper<Integer, Integer> zipper = zipper(avlTree(0, 0).insert(1, 1).insert(2, 2).insert(3, 3).insert(4, 4).insert(5, 5).insert(6, 6)); final TreeZipper<Integer, Integer> newZipper = zipper.last(); assertThat(newZipper.focus.key(), is(6)); } @Test public void canGoToNext() throws Exception { final TreeZipper<Integer, Integer> zipper = zipper(avlTree(0, 0).insert(1, 1).insert(2, 2).insert(3, 3).insert(4, 4).insert(5, 5).insert(6, 6)); TreeZipper<Integer, Integer> zero = zipper.first(); assertThat(zero.focus.key(), is(0)); TreeZipper<Integer, Integer> one = zero.next(); assertThat(one.focus.key(), is(1)); TreeZipper<Integer, Integer> two = one.next(); assertThat(two.focus.key(), is(2)); TreeZipper<Integer, Integer> three = two.next(); assertThat(three.focus.key(), is(3)); TreeZipper<Integer, Integer> four = three.next(); assertThat(four.focus.key(), is(4)); TreeZipper<Integer, Integer> five = four.next(); assertThat(five.focus.key(), is(5)); TreeZipper<Integer, Integer> six = five.next(); assertThat(six.focus.key(), is(6)); try { six.next(); fail(); } catch (NoSuchElementException e) { // all good } } @Test public void canGoToPrevious() throws Exception { final TreeZipper<Integer, Integer> zipper = zipper(avlTree(0, 0).insert(1, 1).insert(2, 2).insert(3, 3).insert(4, 4).insert(5, 5).insert(6, 6)); TreeZipper<Integer, Integer> six = zipper.last(); assertThat(six.focus.key(), is(6)); TreeZipper<Integer, Integer> five = six.previous(); assertThat(five.focus.key(), is(5)); TreeZipper<Integer, Integer> four = five.previous(); assertThat(four.focus.key(), is(4)); TreeZipper<Integer, Integer> three = four.previous(); assertThat(three.focus.key(), is(3)); TreeZipper<Integer, Integer> two = three.previous(); assertThat(two.focus.key(), is(2)); TreeZipper<Integer, Integer> one = two.previous(); assertThat(one.focus.key(), is(1)); TreeZipper<Integer, Integer> zero = one.previous(); assertThat(zero.focus.key(), is(0)); try { zero.previous(); fail(); } catch (NoSuchElementException e) { // all good } } @Test public void supportsIndex() throws Exception { TreeZipper<String, String> zipper = TreeZipper.zipper(avlTree("A", "B").insert("C", "D"). insert("E", "F").insert("G", "H"). insert("I", "J").insert("K", "L")).first(); Assert.assertThat(zipper.value(), Matchers.is(pair("A", "B"))); Assert.assertThat(zipper.index(), Matchers.is(0)); zipper = zipper.next(); Assert.assertThat(zipper.value(), Matchers.is(pair("C", "D"))); Assert.assertThat(zipper.index(), Matchers.is(1)); zipper = zipper.next(); Assert.assertThat(zipper.value(), Matchers.is(pair("E", "F"))); Assert.assertThat(zipper.index(), Matchers.is(2)); zipper = zipper.next(); Assert.assertThat(zipper.value(), Matchers.is(pair("G", "H"))); Assert.assertThat(zipper.index(), Matchers.is(3)); zipper = zipper.next(); Assert.assertThat(zipper.value(), Matchers.is(pair("I", "J"))); Assert.assertThat(zipper.index(), Matchers.is(4)); zipper = zipper.next(); Assert.assertThat(zipper.value(), Matchers.is(pair("K", "L"))); Assert.assertThat(zipper.index(), Matchers.is(5)); } @Test public void canSkipToIndex() throws Exception { TreeZipper<String, String> zipper = TreeZipper.zipper(avlTree("A", "B").insert("C", "D"). insert("E", "F").insert("G", "H"). insert("I", "J").insert("K", "L")).first(); Assert.assertThat(zipper.index(5).value(), Matchers.is(pair("K", "L"))); Assert.assertThat(zipper.index(1).value(), Matchers.is(pair("C", "D"))); Assert.assertThat(zipper.index(3).value(), Matchers.is(pair("G", "H"))); Assert.assertThat(zipper.index(4).value(), Matchers.is(pair("I", "J"))); Assert.assertThat(zipper.index(2).value(), Matchers.is(pair("E", "F"))); Assert.assertThat(zipper.index(0).value(), Matchers.is(pair("A", "B"))); } }