package org.testory.common;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.testory.common.Chain.chain;
import static org.testory.testing.Fakes.newObject;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.junit.Before;
import org.junit.Test;
public class TestChain {
private Chain<Object> chain;
private int size;
private Object a, b, c, d;
private Iterator<Object> iterator;
@Before
public void before() {
a = newObject("a");
b = newObject("b");
c = newObject("c");
d = newObject("d");
}
@Test
public void empty_chain_has_size_zero() {
chain = chain();
size = chain.size();
assertEquals(0, size);
}
@Test
public void empty_chain_has_no_element() {
chain = chain();
try {
chain.get();
fail();
} catch (NoSuchElementException e) {}
}
@Test
public void adding_element_increases_size() {
chain = chain().add(a).add(b).add(c);
assertEquals(3, chain.size());
}
@Test
public void adding_same_element_increases_size() {
chain = chain().add(a).add(a).add(a);
assertEquals(3, chain.size());
}
@Test
public void adds_element_to_head() {
chain = chain().add(a).add(b).add(c);
assertEquals(c, chain.get());
}
@Test
public void adding_does_not_change_original_chain() {
chain = chain().add(a);
chain.add(b);
assertEquals(chain().add(a), chain);
}
@Test
public void adding_forbids_null_elements() {
chain = chain();
try {
chain.add(null);
fail();
} catch (NullPointerException e) {}
}
@Test
public void removing_element_decreases_size() {
chain = chain().add(a).add(b).add(c).remove();
assertEquals(2, chain.size());
}
@Test
public void removes_element_from_head() {
chain = chain().add(a).add(b).add(c).add(d).remove();
assertEquals(c, chain.get());
}
@Test
public void removes_all_elements() {
chain = chain().add(a).add(b).remove().remove();
assertEquals(0, chain.size());
}
@Test
public void removing_does_not_change_original_chain() {
chain = chain().add(a).add(b);
chain.remove();
assertEquals(chain().add(a).add(b), chain);
}
@Test
public void removing_is_forbidden_for_empty_chain() {
chain = chain();
try {
chain.remove();
fail();
} catch (NoSuchElementException e) {}
}
@Test
public void reverses_empty_chain() {
chain = chain().reverse();
assertEquals(0, chain.size());
}
@Test
public void reverses_one_element_chain() {
chain = chain().add(a).reverse();
assertEquals(1, chain.size());
assertSame(a, chain.get());
}
@Test
public void reverses_chain() {
chain = chain().add(a).add(b).add(c).reverse();
assertEquals(3, chain.size());
assertEquals(a, chain.get());
assertEquals(b, chain.remove().get());
assertEquals(c, chain.remove().remove().get());
}
@Test
public void iterates_over_empty_chain() {
iterator = chain().iterator();
assertFalse(iterator.hasNext());
}
@Test
public void iterates_over_chain() {
iterator = chain().add(a).add(b).add(c).iterator();
assertTrue(iterator.hasNext());
assertSame(c, iterator.next());
assertTrue(iterator.hasNext());
assertSame(b, iterator.next());
assertTrue(iterator.hasNext());
assertSame(a, iterator.next());
}
@Test
public void iterator_has_end() {
iterator = chain().add(a).iterator();
iterator.next();
try {
iterator.next();
fail();
} catch (NoSuchElementException e) {}
}
@Test
public void iterator_does_not_support_removal() {
iterator = chain().add(a).iterator();
iterator.next();
try {
iterator.remove();
fail();
} catch (UnsupportedOperationException e) {}
}
@Test
public void equals_empty_chain_to_itself() {
chain = chain();
assertEquals(chain, chain);
}
@Test
public void equals_empty_chain_to_empty_chain() {
assertEquals(chain(), chain());
}
@Test
public void equals_not_empty_chain_to_one_element_chain() {
assertNotEquals(chain(), chain().add(a));
}
@Test
public void equals_not_one_element_chain_to_empty_chain() {
assertNotEquals(chain().add(a), chain);
}
@Test
public void equals_not_one_element_chains_with_different_elements() {
assertNotEquals(chain().add(a), chain().add(b));
}
@Test
public void equals_not_chain_to_its_tail() {
chain = chain().add(a).add(b);
assertNotEquals(chain, chain.add(c));
}
@Test
public void equals_not_to_object() {
assertFalse(chain().equals(new Object()));
}
@Test
public void equals_not_to_null() {
assertFalse(chain().equals(null));
}
@Test
public void implements_hash_code() {
assertEquals(chain().hashCode(), chain().hashCode());
assertEquals(chain().add(a).hashCode(), chain().add(a).hashCode());
}
@Test
public void implements_to_string() {
chain = chain().add(a).add(b).add(c);
assertTrue(chain.toString().matches(".*c.*b.*a.*"));
}
@Test
public void performs_adding_and_removing_by_reuses_tail() {
chain = chain().add(a).add(b);
assertSame(chain, chain.add(c).remove());
}
@Test(timeout = 1000)
public void performs_addition_and_removal() {
int million = 1000 * 1000;
chain = chain();
for (int i = 0; i < million; i++) {
chain = chain.add(new Object());
}
assertEquals(million, chain.size());
for (int i = 0; i < million; i++) {
chain = chain.remove();
}
assertEquals(0, chain.size());
}
}