summaryrefslogtreecommitdiffstats
path: root/yolean/src/test/java/com
diff options
context:
space:
mode:
Diffstat (limited to 'yolean/src/test/java/com')
-rw-r--r--yolean/src/test/java/com/yahoo/yolean/ExceptionsTestCase.java23
-rw-r--r--yolean/src/test/java/com/yahoo/yolean/chain/ChainBuilderTest.java394
-rw-r--r--yolean/src/test/java/com/yahoo/yolean/chain/ChainTest.java55
-rw-r--r--yolean/src/test/java/com/yahoo/yolean/chain/ContainsSameElements.java74
-rw-r--r--yolean/src/test/java/com/yahoo/yolean/chain/DirectedGraphTest.java54
-rw-r--r--yolean/src/test/java/com/yahoo/yolean/chain/EnumeratedIdentitySetTest.java249
-rw-r--r--yolean/src/test/java/com/yahoo/yolean/concurrent/CopyOnWriteHashMapTest.java106
-rw-r--r--yolean/src/test/java/com/yahoo/yolean/concurrent/ThreadRobustListTestCase.java146
-rw-r--r--yolean/src/test/java/com/yahoo/yolean/trace/TraceNodeTestCase.java231
-rw-r--r--yolean/src/test/java/com/yahoo/yolean/trace/TraceVisitorTestCase.java21
10 files changed, 1353 insertions, 0 deletions
diff --git a/yolean/src/test/java/com/yahoo/yolean/ExceptionsTestCase.java b/yolean/src/test/java/com/yahoo/yolean/ExceptionsTestCase.java
new file mode 100644
index 00000000000..36c295ba7f4
--- /dev/null
+++ b/yolean/src/test/java/com/yahoo/yolean/ExceptionsTestCase.java
@@ -0,0 +1,23 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.yolean;
+
+/**
+ * @author <a href="mailto:bratseth@yahoo-inc.com">Jon Bratseth</a>
+ */
+public class ExceptionsTestCase extends junit.framework.TestCase {
+
+ public ExceptionsTestCase(String name) {
+ super(name);
+ }
+
+ public void testToMessageStrings() {
+ assertEquals("Blah",Exceptions.toMessageString(new Exception("Blah")));
+ assertEquals("Blah", Exceptions.toMessageString(new Exception(new Exception("Blah"))));
+ assertEquals("Exception",Exceptions.toMessageString(new Exception()));
+ assertEquals("Foo: Blah",Exceptions.toMessageString(new Exception("Foo",new Exception(new IllegalArgumentException("Blah")))));
+ assertEquals("Foo",Exceptions.toMessageString(new Exception("Foo",new Exception("Foo"))));
+ assertEquals("Foo: Exception",Exceptions.toMessageString(new Exception("Foo",new Exception())));
+ assertEquals("Foo",Exceptions.toMessageString(new Exception(new Exception("Foo"))));
+ }
+
+}
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);
+ }
+ }
+}
diff --git a/yolean/src/test/java/com/yahoo/yolean/concurrent/CopyOnWriteHashMapTest.java b/yolean/src/test/java/com/yahoo/yolean/concurrent/CopyOnWriteHashMapTest.java
new file mode 100644
index 00000000000..280fa2bd22f
--- /dev/null
+++ b/yolean/src/test/java/com/yahoo/yolean/concurrent/CopyOnWriteHashMapTest.java
@@ -0,0 +1,106 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.yolean.concurrent;
+
+import org.junit.Test;
+
+import java.util.Iterator;
+import java.util.Map;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * @author <a href="mailto:balder@yahoo-inc.com">Henning Baldersheim</a>
+ * @since 5.2
+ */
+public class CopyOnWriteHashMapTest {
+
+ @Test
+ public void requireThatAccessorsWork() {
+ Map<String, String> map = new CopyOnWriteHashMap<>();
+ assertEquals(0, map.size());
+ assertEquals(true, map.isEmpty());
+ assertEquals(false, map.containsKey("fooKey"));
+ assertEquals(false, map.containsValue("fooVal"));
+ assertNull(map.get("fooKey"));
+ assertNull(map.remove("fooKey"));
+ assertEquals(0, map.keySet().size());
+ assertEquals(0, map.entrySet().size());
+ assertEquals(0, map.values().size());
+
+ map.put("fooKey", "fooVal");
+ assertEquals(1, map.size());
+ assertEquals(false, map.isEmpty());
+ assertEquals(true, map.containsKey("fooKey"));
+ assertEquals(true, map.containsValue("fooVal"));
+ assertEquals("fooVal", map.get("fooKey"));
+ assertEquals(1, map.keySet().size());
+ assertEquals(1, map.entrySet().size());
+ assertEquals(1, map.values().size());
+
+ map.put("barKey", "barVal");
+ assertEquals(2, map.size());
+ assertEquals(false, map.isEmpty());
+ assertEquals(true, map.containsKey("fooKey"));
+ assertEquals(true, map.containsKey("barKey"));
+ assertEquals(true, map.containsValue("fooVal"));
+ assertEquals(true, map.containsValue("barVal"));
+ assertEquals("fooVal", map.get("fooKey"));
+ assertEquals("barVal", map.get("barKey"));
+ assertEquals(2, map.keySet().size());
+ assertEquals(2, map.entrySet().size());
+ assertEquals(2, map.values().size());
+
+ assertEquals("fooVal", map.remove("fooKey"));
+ assertEquals(1, map.size());
+ assertEquals(false, map.isEmpty());
+ assertEquals(false, map.containsKey("fooKey"));
+ assertEquals(true, map.containsKey("barKey"));
+ assertEquals(false, map.containsValue("fooVal"));
+ assertEquals(true, map.containsValue("barVal"));
+ assertNull(map.get("fooKey"));
+ assertEquals("barVal", map.get("barKey"));
+ assertEquals(1, map.keySet().size());
+ assertEquals(1, map.entrySet().size());
+ assertEquals(1, map.values().size());
+ }
+
+ @Test
+ public void requireThatEntrySetDoesNotReflectConcurrentModifications() {
+ Map<String, String> map = new CopyOnWriteHashMap<>();
+ map.put("fooKey", "fooVal");
+
+ Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
+ assertEquals("fooVal", map.remove("fooKey"));
+
+ assertTrue(it.hasNext());
+ Map.Entry<String, String> entry = it.next();
+ assertEquals("fooKey", entry.getKey());
+ assertEquals("fooVal", entry.getValue());
+ }
+
+ @Test
+ public void requireThatKeySetDoesNotReflectConcurrentModifications() {
+ Map<String, String> map = new CopyOnWriteHashMap<>();
+ map.put("fooKey", "fooVal");
+
+ Iterator<String> it = map.keySet().iterator();
+ assertEquals("fooVal", map.remove("fooKey"));
+
+ assertTrue(it.hasNext());
+ assertEquals("fooKey", it.next());
+ }
+
+ @Test
+ public void requireThatValuesDoNotReflectConcurrentModifications() {
+ Map<String, String> map = new CopyOnWriteHashMap<>();
+ map.put("fooKey", "fooVal");
+
+ Iterator<String> it = map.values().iterator();
+ assertEquals("fooVal", map.remove("fooKey"));
+
+ assertTrue(it.hasNext());
+ assertEquals("fooVal", it.next());
+ }
+}
diff --git a/yolean/src/test/java/com/yahoo/yolean/concurrent/ThreadRobustListTestCase.java b/yolean/src/test/java/com/yahoo/yolean/concurrent/ThreadRobustListTestCase.java
new file mode 100644
index 00000000000..794a8f4e75f
--- /dev/null
+++ b/yolean/src/test/java/com/yahoo/yolean/concurrent/ThreadRobustListTestCase.java
@@ -0,0 +1,146 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.yolean.concurrent;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
+ */
+public class ThreadRobustListTestCase {
+
+ private final static int NUM_THREADS = 64;
+ private final static int NUM_ITEMS_TO_WRITE = 1000000;
+ private final static int NUM_TIMES_TO_READ = 10;
+
+ @Test
+ public void requireThatListIsThreadRobust() throws Exception {
+ final CountDownLatch latch = new CountDownLatch(NUM_THREADS);
+ final ThreadRobustList<Integer> sharedList = new ThreadRobustList<>();
+
+ List<Callable<Boolean>> tasks = new ArrayList<>(NUM_THREADS);
+ tasks.add(new WriterTask(latch, sharedList));
+ for (int i = 1; i < NUM_THREADS; ++i) {
+ tasks.add(new ReaderTask(latch, sharedList));
+ }
+ for (Future<Boolean> result : Executors.newFixedThreadPool(NUM_THREADS).invokeAll(tasks)) {
+ assertTrue(result.get(60, TimeUnit.SECONDS));
+ }
+ }
+
+ @Test
+ public void requireThatAccessorsWork() {
+ ThreadRobustList<Object> lst = new ThreadRobustList<>();
+ assertTrue(lst.isEmpty());
+ assertFalse(lst.iterator().hasNext());
+
+ Object foo = new Object();
+ lst.add(foo);
+ assertFalse(lst.isEmpty());
+ Iterator<Object> it = lst.iterator();
+ assertNotNull(it);
+ assertTrue(it.hasNext());
+ assertSame(foo, it.next());
+ assertFalse(it.hasNext());
+
+ Object bar = new Object();
+ lst.add(bar);
+ assertFalse(lst.isEmpty());
+ assertNotNull(it = lst.iterator());
+ assertTrue(it.hasNext());
+ assertSame(foo, it.next());
+ assertTrue(it.hasNext());
+ assertSame(bar, it.next());
+ assertFalse(it.hasNext());
+ }
+
+ @Test
+ public void requireThatIteratorNextThrowsNoSuchElementExceptionWhenDone() {
+ ThreadRobustList<Object> lst = new ThreadRobustList<>();
+ Iterator<Object> it = lst.iterator();
+ assertFalse(it.hasNext());
+ try {
+ it.next();
+ fail();
+ } catch (NoSuchElementException e) {
+
+ }
+ }
+
+ @Test
+ public void requireThatIteratorRemoveIsNotSupported() {
+ ThreadRobustList<Object> lst = new ThreadRobustList<>();
+ Object obj = new Object();
+ lst.add(obj);
+ Iterator<Object> it = lst.iterator();
+ assertTrue(it.hasNext());
+ assertSame(obj, it.next());
+ try {
+ it.remove();
+ fail();
+ } catch (UnsupportedOperationException e) {
+
+ }
+ }
+
+ private static class WriterTask implements Callable<Boolean> {
+
+ final CountDownLatch latch;
+ final ThreadRobustList<Integer> sharedList;
+
+ WriterTask(CountDownLatch latch, ThreadRobustList<Integer> sharedList) {
+ this.latch = latch;
+ this.sharedList = sharedList;
+ }
+
+ @Override
+ public Boolean call() throws Exception {
+ latch.countDown();
+ assertTrue(latch.await(60, TimeUnit.SECONDS));
+ for (int i = 0; i < NUM_ITEMS_TO_WRITE; ++i) {
+ sharedList.add(i);
+ }
+ return true;
+ }
+ }
+
+ private static class ReaderTask implements Callable<Boolean> {
+
+ final CountDownLatch latch;
+ final ThreadRobustList<Integer> sharedList;
+
+ ReaderTask(CountDownLatch latch, ThreadRobustList<Integer> sharedList) {
+ this.latch = latch;
+ this.sharedList = sharedList;
+ }
+
+ @Override
+ public Boolean call() throws Exception {
+ latch.countDown();
+ assertTrue(latch.await(60, TimeUnit.SECONDS));
+ for (int i = 0; i < NUM_TIMES_TO_READ; ++i) {
+ Iterator<Integer> it = sharedList.iterator();
+ for (int j = 0; it.hasNext(); ++j) {
+ assertEquals(j, it.next().intValue());
+ }
+ }
+ return true;
+ }
+ }
+}
diff --git a/yolean/src/test/java/com/yahoo/yolean/trace/TraceNodeTestCase.java b/yolean/src/test/java/com/yahoo/yolean/trace/TraceNodeTestCase.java
new file mode 100644
index 00000000000..cc25ecf4cd0
--- /dev/null
+++ b/yolean/src/test/java/com/yahoo/yolean/trace/TraceNodeTestCase.java
@@ -0,0 +1,231 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.yolean.trace;
+
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+/**
+ * @author <a href="mailto:bratseth@yahoo-inc.com">Jon Bratseth</a>
+ */
+public class TraceNodeTestCase {
+
+ @Test
+ public void requireThatAccessorsWork() {
+ TraceNode node = new TraceNode(null, 6);
+ assertNull(node.payload());
+ assertEquals(6, node.timestamp());
+ assertFalse(node.children().iterator().hasNext());
+ assertFalse(node.descendants(Object.class).iterator().hasNext());
+ assertTrue(node.isRoot());
+ assertNull(node.parent());
+ assertSame(node, node.root());
+ }
+
+ @Test
+ public void requireThatToStringIsReadable() {
+ TraceNode trace = new TraceNode(null, 0)
+ .add(new TraceNode("a", 1))
+ .add(new TraceNode("b", 2)
+ .add(new TraceNode("c", 3)));
+ assertEquals("[ [ a b [ c ] ] ]", trace.toString());
+ }
+
+ @Test
+ public void requireThatPayloadMayBeNull() {
+ TraceNode node = new TraceNode(null, 6);
+ assertNull(node.payload());
+ }
+
+ @Test
+ public void requireThatRootNodesCanBeAdded() {
+ TraceNode parent = new TraceNode(null, 1);
+
+ TraceNode foo = new TraceNode(null, 2);
+ parent.add(foo);
+ assertSame(parent, foo.parent());
+
+ TraceNode bar = new TraceNode(null, 3);
+ parent.add(bar);
+ assertSame(parent, bar.parent());
+
+ Iterator<TraceNode> children = parent.children().iterator();
+ assertTrue(children.hasNext());
+ assertSame(foo, children.next());
+ assertTrue(children.hasNext());
+ assertSame(bar, children.next());
+ assertFalse(children.hasNext());
+
+ Iterator<Object> payloads = parent.descendants(Object.class).iterator();
+ assertFalse(payloads.hasNext());
+ }
+
+ @Test
+ public void requireThatNonRootNodeCanNotBeAdded() {
+ TraceNode foo = new TraceNode(null, 0);
+ TraceNode bar = new TraceNode(null, 0);
+ TraceNode baz = new TraceNode(null, 0);
+ bar.add(baz);
+ try {
+ foo.add(baz);
+ fail();
+ } catch (IllegalArgumentException e) {
+
+ }
+ assertSame(bar, baz.parent());
+ assertTrue(bar.children().iterator().hasNext());
+ assertFalse(foo.children().iterator().hasNext());
+ }
+
+ @Test
+ public void requireThatChildrenIsNeverNull() {
+ assertNotNull(new TraceNode(null, 69).children());
+ }
+
+ @Test
+ public void requireThatDescendantsIsNeverNull() {
+ assertNotNull(new TraceNode(null, 69).descendants(Object.class));
+ }
+
+ @Test
+ public void requireThatDescendantsOrderIsDepthFirstPrefix() {
+ TraceNode trace = new TraceNode(null, 0)
+ .add(new TraceNode("a", 0)
+ .add(new TraceNode("b", 0))
+ .add(new TraceNode("c", 0)
+ .add(new TraceNode("d", 0))
+ .add(new TraceNode("e", 0))))
+ .add(new TraceNode("f", 0)
+ .add(new TraceNode("g", 0)));
+
+ Iterator<String> it = trace.descendants(String.class).iterator();
+ assertTrue(it.hasNext());
+ assertEquals("a", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("b", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("c", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("d", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("e", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("f", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("g", it.next());
+ assertFalse(it.hasNext());
+ }
+
+ @Test
+ public void requireThatDescendantsFilterPayloads() {
+ TraceNode trace = new TraceNode(null, 0)
+ .add(new TraceNode("a", 0)
+ .add(new TraceNode(69, 0))
+ .add(new TraceNode("b", 0)
+ .add(new TraceNode("c", 0))
+ .add(new TraceNode(new Object(), 0))))
+ .add(new TraceNode("d", 0)
+ .add(new TraceNode("e", 0)));
+
+ Iterator<String> it = trace.descendants(String.class).iterator();
+ assertTrue(it.hasNext());
+ assertEquals("a", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("b", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("c", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("d", it.next());
+ assertTrue(it.hasNext());
+ assertEquals("e", it.next());
+ assertFalse(it.hasNext());
+ }
+
+ @Test
+ public void requireThatVisitorOrderIsDepthFirstPrefix() {
+ TraceNode trace = new TraceNode(null, 0)
+ .add(new TraceNode("a", 0)
+ .add(new TraceNode("b", 0))
+ .add(new TraceNode("c", 0)
+ .add(new TraceNode("d", 0))
+ .add(new TraceNode(3, 0))))
+ .add(new TraceNode("f", 0)
+ .add(new TraceNode("g", 0)));
+
+ final List<Object> payloads = new ArrayList<>();
+ trace.accept(new TraceVisitor() {
+
+ @Override
+ public void visit(TraceNode node) {
+ payloads.add(node.payload());
+ }
+ });
+ assertEquals(Arrays.<Object>asList(null, "a", "b", "c", "d", 3, "f", "g"),
+ payloads);
+ }
+
+ @Test
+ public void requireThatVisitorDoesNotEnterOrLeaveNodesThatHaveNoChildren() {
+ TraceNode trace = new TraceNode(null, 0);
+ trace.accept(new TraceVisitor() {
+
+ @Override
+ public void visit(TraceNode node) {
+
+ }
+
+ @Override
+ public void entering(TraceNode node) {
+ fail();
+ }
+
+ @Override
+ public void leaving(TraceNode node) {
+ fail();
+ }
+ });
+ }
+
+ @Test
+ public void requireThatVisitorEntersAndLeavesNodesThatHaveChildren() {
+ TraceNode trace = new TraceNode("", 0)
+ .add(new TraceNode("a", 0)
+ .add(new TraceNode("b", 0))
+ .add(new TraceNode("c", 0)
+ .add(new TraceNode("d", 0))
+ .add(new TraceNode("e", 0))))
+ .add(new TraceNode("f", 0)
+ .add(new TraceNode("g", 0)));
+
+ final StringBuilder out = new StringBuilder();
+ trace.accept(new TraceVisitor() {
+
+ @Override
+ public void visit(TraceNode node) {
+ out.append(node.payload());
+ }
+
+ @Override
+ public void entering(TraceNode node) {
+ out.append("[");
+ }
+
+ @Override
+ public void leaving(TraceNode node) {
+ out.append("]");
+ }
+ });
+ assertEquals("[a[bc[de]]f[g]]", out.toString());
+ }
+}
diff --git a/yolean/src/test/java/com/yahoo/yolean/trace/TraceVisitorTestCase.java b/yolean/src/test/java/com/yahoo/yolean/trace/TraceVisitorTestCase.java
new file mode 100644
index 00000000000..3b04c210c2f
--- /dev/null
+++ b/yolean/src/test/java/com/yahoo/yolean/trace/TraceVisitorTestCase.java
@@ -0,0 +1,21 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.yolean.trace;
+
+import org.junit.Test;
+
+/**
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen Hult</a>
+ */
+public class TraceVisitorTestCase {
+
+ @Test
+ public void requireThatTraceVisitorCompilesWithOnlyVisitImplemented() {
+ new TraceNode(null, 0).accept(new TraceVisitor() {
+
+ @Override
+ public void visit(TraceNode node) {
+
+ }
+ });
+ }
+}