diff options
Diffstat (limited to 'yolean/src/test/java/com/yahoo/yolean/chain')
5 files changed, 826 insertions, 0 deletions
diff --git a/yolean/src/test/java/com/yahoo/yolean/chain/ChainBuilderTest.java b/yolean/src/test/java/com/yahoo/yolean/chain/ChainBuilderTest.java new file mode 100644 index 00000000000..86dba99e333 --- /dev/null +++ b/yolean/src/test/java/com/yahoo/yolean/chain/ChainBuilderTest.java @@ -0,0 +1,394 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.yolean.chain; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static com.yahoo.yolean.chain.Dependencies.after; +import static com.yahoo.yolean.chain.Dependencies.before; +import static com.yahoo.yolean.chain.Dependencies.provides; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.collection.IsIterableContainingInOrder.contains; +import static org.junit.Assert.assertTrue; + +/** + * @author tonytv + * @author gjoranv + */ +public class ChainBuilderTest { + + static class Filter { + + } + + static class FilterA extends Filter { + + } + + static class FilterB extends Filter { + + } + + static class FilterExtendsA extends FilterA { + + } + + static class FilterExtendsB extends FilterB { + + } + + @Provides("A") + static class ProvidesA extends Filter { + + } + + @Provides("B") + static class ProvidesB extends Filter { + + } + + @Before("A") + static class BeforeA extends Filter { + + } + + @After("A") + static class AfterA extends Filter { + + } + + @Before("*") + @Provides("BeforeAll") + static class BeforeAll extends Filter { + + } + + @After("*") + @Provides("AfterAll") + static class AfterAll extends Filter { + + } + + @Before({ "BeforeAll", "*" }) + static class BeforeBeforeAll extends Filter { + + } + + @After({ "AfterAll", "*" }) + static class AfterAfterAll extends Filter { + + } + + static class ExtendsProvidesA extends ProvidesA { + + } + + @Provides("ExtendsA") + static class ProvidesA_and_ProvidesExtendsA extends ProvidesA { + + } + + @Before("B") + static class BeforeA_and_BeforeB extends BeforeA { + + } + + @Test + public void build_empty_chain() { + Chain<Filter> chain = getChain().build(); + assertTrue(chain.isEmpty()); + assertThat(chain.id(), is("myChain")); + } + + @Test + public void filters_without_dependencies_are_not_reordered() { + List<Filter> filters = new ArrayList<>(); + + ChainBuilder<Filter> chain = new ChainBuilder<>("myChain"); + for (int i = 0; i < 10; ++i) { + Filter filter = new Filter(); + filters.add(filter); + chain.add(filter); + } + + assertThat(chain.build(), contains(filters.toArray())); + } + + @Test(expected = ChainCycleException.class) + public void cycles_are_detected() { + Filter a = new Filter(); + Filter b = new Filter(); + + getChain().add(b, before(a)).add(a, before(b)).build(); + } + + @Test(expected = IllegalArgumentException.class) + public void adding_same_instance_twice_is_illegal() { + Filter a = new Filter(); + + getChain().add(a).add(a).build(); + } + + @Test + public void before_instance() { + Filter a = new Filter(); + Filter b = new Filter(); + + Chain<Filter> chain = getChain(). + add(b).add(a, before(b)).build(); + + assertThat(chain, is(new Chain<>("myChain", a, b))); + } + + @Test + public void after_instance() { + Filter a = new Filter(); + Filter b = new Filter(); + + Chain<Filter> chain = getChain(). + add(b, after(a)).add(a).build(); + + assertThat(chain, is(new Chain<>("myChain", a, b))); + } + + @Test + public void before_class() { + Filter a = new FilterA(); + Filter b = new FilterB(); + + Chain<Filter> chain = getChain(). + add(b).add(a, before(b.getClass())).build(); + + assertThat(chain, is(new Chain<>("myChain", a, b))); + } + + @Test + public void after_class() { + Filter a = new FilterA(); + Filter b = new FilterB(); + + Chain<Filter> chain = getChain(). + add(b, after(a.getClass())).add(a).build(); + + assertThat(chain, is(new Chain<>("myChain", a, b))); + } + + @Test + public void before_subclass() { + Filter a = new FilterA(); + Filter b = new FilterExtendsB(); + + Chain<Filter> chain = getChain(). + add(b).add(a, before(FilterB.class)).build(); + + assertThat(chain, is(new Chain<>("myChain", a, b))); + } + + @Test + public void after_subclass() { + Filter a = new FilterExtendsA(); + Filter b = new FilterB(); + + Chain<Filter> chain = getChain(). + add(b, after(FilterA.class)).add(a).build(); + + assertThat(chain, is(new Chain<>("myChain", a, b))); + } + + @Test + public void before_provided_name() { + Filter a = new Filter(); + Filter b = new Filter(); + + Chain<Filter> chain = getChain(). + add(b, provides("B")).add(a, before("B")).build(); + + assertThat(chain, is(new Chain<>("myChain", a, b))); + } + + @Test + public void after_provided_name() { + Filter a = new Filter(); + Filter b = new Filter(); + + Chain<Filter> chain = getChain(). + add(b, after("A")).add(a, provides("A")).build(); + + assertThat(chain, is(new Chain<>("myChain", a, b))); + } + + @Test + public void before_provided_name_in_annotations() { + Filter providesA = new ProvidesA(); + Filter beforeA = new BeforeA(); + + Chain<Filter> chain = getChain(). + add(providesA).add(beforeA).build(); + + assertThat(chain, is(new Chain<>("myChain", beforeA, providesA))); + } + + @Test + public void after_provided_name_in_annotations() { + Filter providesA = new ProvidesA(); + Filter afterA = new AfterA(); + + Chain<Filter> chain = getChain(). + add(afterA).add(providesA).build(); + + assertThat(chain, is(new Chain<>("myChain", providesA, afterA))); + } + + @Test + public void before_all() { + Filter a = new Filter(); + Filter b = new Filter(); + + Chain<Filter> chain = getChain(). + add(b).add(a, before("*")).build(); + + assertThat(chain, is(new Chain<>("myChain", a, b))); + } + + @Test + public void after_all() { + Filter a = new Filter(); + Filter b = new Filter(); + + Chain<Filter> chain = getChain(). + add(b, after("*")).add(a).build(); + + assertThat(chain, is(new Chain<>("myChain", a, b))); + } + + @Test + public void before_all_annotation() { + Filter a = new Filter(); + Filter beforeAll = new BeforeAll(); + + Chain<Filter> chain = getChain(). + add(a).add(beforeAll).build(); + + assertThat(chain, is(new Chain<>("myChain", beforeAll, a))); + } + + @Test + public void after_all_annotation() { + Filter a = new Filter(); + Filter afterAll = new AfterAll(); + + Chain<Filter> chain = getChain(). + add(afterAll).add(a).build(); + + assertThat(chain, is(new Chain<>("myChain", a, afterAll))); + } + + @Test + public void before_all_annotated_component_can_be_before_another_component_that_is_also_before_all_annotated() { + Filter beforeAll = new BeforeAll(); + Filter beforeBeforeAll = new BeforeBeforeAll(); + + Chain<Filter> chain = getChain(). + add(beforeAll).add(beforeBeforeAll).build(); + + assertThat(chain, is(new Chain<>("myChain", beforeBeforeAll, beforeAll))); + } + + @Test + public void after_all_annotated_component_can_be_after_another_component_that_is_also_after_all_annotated() { + Filter afterAll = new AfterAll(); + Filter afterAfterAll = new AfterAfterAll(); + + Chain<Filter> chain = getChain(). + add(afterAfterAll).add(afterAll).build(); + + assertThat(chain, is(new Chain<>("myChain", afterAll, afterAfterAll))); + } + + @Test + public void component_that_is_not_annotated_can_be_before_a_before_all_annotated_component() { + Filter first = new Filter(); + Filter beforeAll = new BeforeAll(); + + Chain<Filter> chain = getChain(). + add(beforeAll).add(first, before("BeforeAll")).build(); + + assertThat(chain, is(new Chain<>("myChain", first, beforeAll))); + } + + @Test + public void component_that_is_not_annotated_can_be_after_an_after_all_annotated_component() { + Filter last = new Filter(); + Filter afterAll = new AfterAll(); + + Chain<Filter> chain = getChain(). + add(last, after("AfterAll")).add(afterAll).build(); + + assertThat(chain, is(new Chain<>("myChain", afterAll, last))); + } + + @Test + public void class_name_is_always_provided() { + Filter a = new FilterA(); + Filter b = new FilterB(); + + Chain<Filter> chain = getChain(). + add(b, after(a.getClass().getName())).add(a).build(); + + assertThat(chain, is(new Chain<>("myChain", a, b))); + } + + @Test + public void provides_annotation_on_superclass_is_inherited_by_subclasses() { + Filter extendsA = new ExtendsProvidesA(); + Filter first = new FilterA(); + Filter last = new FilterB(); + + Chain<Filter> chain = getChain(). + add(last, after("A")).add(first, before("A")).add(extendsA).build(); + + assertThat(chain, is(new Chain<>("myChain", first, extendsA, last))); + } + + @Test + public void provides_annotation_on_superclass_is_inherited_by_a_subclass_that_has_its_own_provides_annotation() { + Filter extendsA = new ProvidesA_and_ProvidesExtendsA(); + Filter first = new FilterA(); + Filter last = new FilterB(); + + Chain<Filter> chain = getChain(). + add(last, after("A")).add(first, before("ExtendsA")).add(extendsA).build(); + + assertThat(chain, is(new Chain<>("myChain", first, extendsA, last))); + } + + @Test + public void before_annotation_on_superclass_is_inherited_by_a_subclass_that_has_its_own_before_annotation() { + Filter beforeA_and_beforeB = new BeforeA_and_BeforeB(); + Filter A = new ProvidesA(); + Filter B = new ProvidesB(); + + Chain<Filter> chain = getChain(). + add(A, before("*")).add(beforeA_and_beforeB).add(B).build(); + assertThat(chain, is(new Chain<>("myChain", beforeA_and_beforeB, A, B))); + } + + @Test + public void add_accepts_multiple_dependencies() { + Filter a = new Filter(); + Filter b = new Filter(); + Filter c = new Filter(); + + Chain<Filter> chain = getChain(). + add(a).add(c).add(b, after(a), before(c)).build(); + + assertThat(chain, is(new Chain<>("myChain", a, b, c))); + } + + private ChainBuilder<Filter> getChain() { + return new ChainBuilder<>("myChain"); + } +} diff --git a/yolean/src/test/java/com/yahoo/yolean/chain/ChainTest.java b/yolean/src/test/java/com/yahoo/yolean/chain/ChainTest.java new file mode 100644 index 00000000000..e8a8f9309b0 --- /dev/null +++ b/yolean/src/test/java/com/yahoo/yolean/chain/ChainTest.java @@ -0,0 +1,55 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.yolean.chain; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.junit.Assert.assertThat; + +/** + * @author tonytv + */ +public class ChainTest { + + public static class Filter { + + } + + public static class OtherFilter extends Filter { + + } + + @Test + public void empty_chain_toString() { + Chain<Filter> c = new Chain<>("myChain"); + assertThat(c.toString(), is("chain 'myChain'{}")); + } + + @Test + public void singleton_chain_toString() { + Chain<Filter> c = new Chain<>("myChain", new Filter()); + assertThat(c.toString(), is("chain 'myChain'{ Filter }")); + } + + @Test + public void chain_toString() { + Chain<Filter> c = new Chain<>("myChain", new Filter(), new Filter(), new OtherFilter()); + assertThat(c.toString(), is("chain 'myChain'{ Filter -> Filter -> OtherFilter }")); + } + + @Test + public void non_equal_due_to_different_components() { + assertThat(new Chain<>("a", new Filter()), is(not(new Chain<>("a", new Filter())))); + } + + @Test + public void non_equal_due_to_different_size_comopnents() { + assertThat(new Chain<>("a", new Filter()), is(not(new Chain<Filter>("a")))); + } + + @Test + public void hashCode_equals() { + assertThat(new Chain<>("a").hashCode(), is(new Chain<Filter>("a").hashCode())); + } +} diff --git a/yolean/src/test/java/com/yahoo/yolean/chain/ContainsSameElements.java b/yolean/src/test/java/com/yahoo/yolean/chain/ContainsSameElements.java new file mode 100644 index 00000000000..9eee34a45a3 --- /dev/null +++ b/yolean/src/test/java/com/yahoo/yolean/chain/ContainsSameElements.java @@ -0,0 +1,74 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.yolean.chain; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Set; + +import static java.util.Collections.sort; + +/** + * @author tonytv + */ +class ContainsSameElements<T> extends TypeSafeMatcher<Collection<? super T>> { + + private final Set<T> identitySet; + + public static <T> Matcher<Collection<? super T>> containsSameElements(Collection<T> collection) { + return new ContainsSameElements<>(collection); + } + + public ContainsSameElements(Collection<T> collection) { + identitySet = toIdentitySet(collection); + } + + @SuppressWarnings("SuspiciousMethodCalls") + @Override + protected boolean matchesSafely(Collection<? super T> collection2) { + for (Object elem : collection2) { + if (!identitySet.contains(elem)) { + return false; + } + } + + return collection2.size() == identitySet.size(); + } + + @Override + public void describeTo(Description description) { + description.appendText("containsSameElements "); + appendCollection(description, identitySet); + } + + private void appendCollection(Description description, Collection<?> collection) { + description.appendValueList("{", ", ", "}", elementsToStringSorted(collection)); + } + + private List<String> elementsToStringSorted(Collection<?> collection) { + List<String> result = new ArrayList<>(); + for (Object o : collection) { + result.add(o.toString()); + } + sort(result); + return result; + } + + @Override + protected void describeMismatchSafely(Collection<? super T> collection, Description description) { + description.appendText("was "); + appendCollection(description, collection); + } + + public static <T> Set<T> toIdentitySet(Collection<? extends T> collection) { + Set<T> identitySet = Collections.newSetFromMap(new IdentityHashMap<T, Boolean>()); + identitySet.addAll(collection); + return identitySet; + } +} diff --git a/yolean/src/test/java/com/yahoo/yolean/chain/DirectedGraphTest.java b/yolean/src/test/java/com/yahoo/yolean/chain/DirectedGraphTest.java new file mode 100644 index 00000000000..5097253f8e1 --- /dev/null +++ b/yolean/src/test/java/com/yahoo/yolean/chain/DirectedGraphTest.java @@ -0,0 +1,54 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.yolean.chain; + +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.collection.IsIterableContainingInOrder.contains; +import static org.junit.Assert.assertThat; + +public class DirectedGraphTest { + + private DirectedGraph graph; + private Vertex[] v = new Vertex[10]; + + @Before + public void setup() { + for (int i = 0; i < v.length; i++) { + v[i] = new TestVertex(i); + } + + graph = new DirectedGraph(); + } + + @Test + public void before_all_are_prioritized_first() { + graph.addVertex(v[0]); + graph.addBeginningVertex(v[1]); + + assertThat(graph.topologicalSort(), contains(v[1], v[0])); + } + + @Test + public void vertex_can_be_placed_before_before_all_vertices() { + graph.addVertex(v[0]); + graph.addBeginningVertex(v[1]); + graph.addEdge(v[0], v[1]); + + assertThat(graph.topologicalSort(), contains(v[0], v[1])); + } + + static class TestVertex implements Vertex { + + private final int id; + + TestVertex(int id) { + this.id = id; + } + + @Override + public String toString() { + return "Vertex{" + id + '}'; + } + } +} diff --git a/yolean/src/test/java/com/yahoo/yolean/chain/EnumeratedIdentitySetTest.java b/yolean/src/test/java/com/yahoo/yolean/chain/EnumeratedIdentitySetTest.java new file mode 100644 index 00000000000..8a55381cdef --- /dev/null +++ b/yolean/src/test/java/com/yahoo/yolean/chain/EnumeratedIdentitySetTest.java @@ -0,0 +1,249 @@ +// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.yolean.chain; + +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.IdentityHashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import static com.yahoo.yolean.chain.ContainsSameElements.containsSameElements; +import static com.yahoo.yolean.chain.ContainsSameElements.toIdentitySet; +import static java.util.Collections.singleton; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.collection.IsEmptyCollection.empty; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +/** + * Tests for EnumeratedIdentitySet. + */ +public class EnumeratedIdentitySetTest { + + private final List<Element> elements; + + public EnumeratedIdentitySetTest() { + elements = new ArrayList<>(); + for (int i = 0; i < 10; i++) { + elements.add(new Element()); + } + } + + @Test + public void size() { + EnumeratedIdentitySet<Element> set = new EnumeratedIdentitySet<>(elements); + assertThat(set.size(), is(elements.size())); + + set.add(elements.get(0)); + assertThat(set.size(), is(elements.size())); + + set.remove(elements.get(0)); + assertThat(set.size(), is(elements.size() - 1)); + } + + @Test + public void isEmpty() { + EnumeratedIdentitySet<Element> set = new EnumeratedIdentitySet<>(); + assertTrue(set.isEmpty()); + + set.add(elements.get(0)); + assertFalse(set.isEmpty()); + } + + @Test + public void contains2() { + EnumeratedIdentitySet<Element> set = new EnumeratedIdentitySet<>(elements); + assertTrue(set.contains(elements.get(0))); + assertFalse(set.contains(new Element())); + } + + @Test + public void iterator() { + EnumeratedIdentitySet<Element> set = new EnumeratedIdentitySet<>(elements); + + IdentityHashMap<Element, Void> collectedElements = new IdentityHashMap<>(); + int count = 0; + for (Element element : set) { + collectedElements.put(element, null); + count++; + } + + assertThat(collectedElements.size(), is(count)); + assertThat(collectedElements.size(), is(elements.size())); + + for (Element element : elements) { + assertTrue(collectedElements.containsKey(element)); + } + } + + @Test + public void toArray() { + EnumeratedIdentitySet<Element> set = new EnumeratedIdentitySet<>(elements); + + Object[] array = set.toArray(); + Element[] array2 = set.toArray(new Element[0]); + + assertThat(Arrays.asList(array), containsSameElements(set)); + assertThat(Arrays.asList(array2), containsSameElements(set)); + } + + @Test + public void add() { + EnumeratedIdentitySet<Element> set = new EnumeratedIdentitySet<>(); + assertTrue(set.add(elements.get(0))); + assertFalse(set.add(elements.get(0))); + } + + @Test + public void remove() { + EnumeratedIdentitySet<Element> set = new EnumeratedIdentitySet<>(elements); + assertTrue(set.remove(elements.get(0))); + assertFalse(set.remove(elements.get(0))); + } + + @Test + public void containsAll() { + EnumeratedIdentitySet<Element> set = new EnumeratedIdentitySet<>(elements); + assertTrue(set.containsAll(elements.subList(0, 7))); + assertTrue(set.containsAll(elements)); + + List<Element> extendedElements = new ArrayList<>(elements); + extendedElements.add(new Element()); + assertFalse(set.containsAll(extendedElements)); + } + + @Test + public void addAll() { + EnumeratedIdentitySet<Element> set = new EnumeratedIdentitySet<>(); + set.addAll(elements); + + assertThat(set, containsSameElements(elements)); + } + + @Test + public void retainAll() { + Set<Element> set = new EnumeratedIdentitySet<>(); + + set.addAll(elements.subList(0, 5)); + boolean changed = set.retainAll(toIdentitySet(elements.subList(3, 10))); + + assertTrue(changed); + assertThat(set, containsSameElements(elements.subList(3, 5))); + + changed = set.retainAll(toIdentitySet(elements)); + assertFalse(changed); + } + + @Test + public void removeAll() { + EnumeratedIdentitySet<Element> set = new EnumeratedIdentitySet<>(elements); + set.removeAll(elements.subList(0, 5)); + assertThat(set, containsSameElements(elements.subList(5, 10))); + } + + @Test + public void clear() { + EnumeratedIdentitySet<Element> set = new EnumeratedIdentitySet<>(elements); + set.clear(); + assertThat(set, empty()); + } + + @Test + public void removeNulls() { + Element[] singletonArray = { null, elements.get(0), null }; + assertThat(EnumeratedIdentitySet.removeNulls(singletonArray), + containsSameElements(Arrays.asList(elements.get(0)))); + + Element[] elementsWithNull = new Element[20]; + + Iterator<Element> iterator = elements.iterator(); + + copyElementsTo(iterator, elementsWithNull, 2, 1); + copyElementsTo(iterator, elementsWithNull, 4, 8); + copyElementsTo(iterator, elementsWithNull, 19, 1); + + assertThat(EnumeratedIdentitySet.removeNulls(elementsWithNull), containsSameElements(elements)); + } + + private void copyElementsTo(Iterator<Element> iterator, Element[] array, int startIndex, int numItems) { + for (int i = 0; i < numItems; i++) { + array[i + startIndex] = iterator.next(); + } + } + + @Test + public void renumber_preserves_ordering() { + EnumeratedIdentitySet<Element> set = new EnumeratedIdentitySet<>(); + + for (int i = 0; i < 200; i++) { + set.add(new Element()); + } + + set.addAll(elements); + + EnumeratedIdentitySet<Element> elementsToPreserve = new EnumeratedIdentitySet<>(elements); + + for (Iterator<Element> i = set.iterator(); i.hasNext(); ) { + if (!elementsToPreserve.contains(i.next())) { + i.remove(); + } + } + + List<Element> forceRenumber = set.insertionOrderedList(); + assertThat(forceRenumber.size(), is(elements.size())); + + for (int i = 0; i < elements.size(); i++) { + assertSame(forceRenumber.get(i), elements.get(i)); + } + + set.add(new Element()); + assertThat(set.numbers(), containsSameElements(range(0, 10))); + } + + @Test + public void renumber_when_empty() { + EnumeratedIdentitySet<Element> set = new EnumeratedIdentitySet<>(elements); + for (Iterator<Element> i = set.iterator(); i.hasNext(); ) { + i.next(); + i.remove(); + } + + set.insertionOrderedList(); + assertThat(set.numbers(), empty()); + + set.add(new Element()); + assertThat(set.numbers(), containsSameElements(singleton(0))); + } + + private List<Integer> range(int start, int endInclusive) { + List<Integer> result = new ArrayList<>(); + for (int i = start; i <= endInclusive; i++) { + result.add(i); + } + + return result; + } + + static class Element { + + @Override + public int hashCode() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object obj) { + throw new UnsupportedOperationException(); + } + + @Override + public String toString() { + return "Element@" + System.identityHashCode(this); + } + } +} |