import static org.junit.Assert.*;

import org.junit.Test;

public class TestLinkedList {

	@Test
	public void testDefaultCtor() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		assertEquals("size should be zero", 0, l.size());
		assertTrue("isEmpty should be true", l.isEmpty());
		assertEquals("Representation not correct", "[ ]", l.toString());
	}

	@Test
	public void testInsertFront() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		l.insertFront(10);
		l.insertFront(20);
		l.insertFront(30);
		assertEquals("size not correct", 3, l.size());
		assertEquals("Representation not correct", "[ 30 20 10 ]", l.toString());
	}
	
	@Test
	public void testInsertBack() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		l.insertBack(10);
		l.insertBack(20);
		l.insertBack(30);
		assertEquals("size not correct", 3, l.size());
		assertEquals("Representation not correct", "[ 10 20 30 ]", l.toString());
	}

	@Test
	public void testInsertBefore() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		l.insertBefore(0, 0);
		for (int i = 0; i < 5; ++i) {
			l.insertBefore(0, i + 1);
		}
		l.insertBefore(3, 99);
		assertEquals("size not correct", 7, l.size());
		assertEquals("Representation not correct", "[ 5 4 3 99 2 1 0 ]", l.toString());
	}
	
	@Test
	public void testInsertAfter() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		l.insertAfter(0, 0);
		for (int i = 0; i < 5; ++i) {
			l.insertAfter(i, i + 1);
		}
		l.insertAfter(3, 99);
		assertEquals("size not correct", 7, l.size());
		assertEquals("Representation not correct", "[ 0 1 2 3 99 4 5 ]", l.toString());
	}

	@Test
	public void testRemoveFront() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		for (int i = 0; i < 10; ++i) {
			l.insertBack(i);
		}
		l.removeFront();
		assertEquals("size not correct", 9, l.size());
		assertEquals("Representation not correct", "[ 1 2 3 4 5 6 7 8 9 ]", l.toString());
	}
	
	@Test
	public void testRemoveBack() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		for (int i = 0; i < 10; ++i) {
			l.insertBack(i);
		}
		l.removeBack();
		assertEquals("size not correct", 9, l.size());
		assertEquals("Representation not correct", "[ 0 1 2 3 4 5 6 7 8 ]", l.toString());
	}

	@Test
	public void testRemoveAt() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		for (int i = 0; i < 10; ++i) {
			l.insertBack(i);
		}
		assertEquals ("removed the wrong element", 5, l.removeAt(5).intValue());
		assertEquals("Representation not correct", "[ 0 1 2 3 4 6 7 8 9 ]", l.toString());
		assertEquals ("removed the wrong element", 0, l.removeAt(0).intValue());
		assertEquals("Representation not correct", "[ 1 2 3 4 6 7 8 9 ]", l.toString());
		assertEquals ("removed the wrong element", 9, l.removeAt(l.size() - 1).intValue());
		assertEquals("Representation not correct", "[ 1 2 3 4 6 7 8 ]", l.toString());
	}
	
	@Test
	public void testAddAll() {
		LinkedList<Integer> a = new LinkedList<Integer>();
		for (int i = 0; i < 5; ++i) {
			a.insertBack(i);
		}
		LinkedList<Integer> b = new LinkedList<Integer>();
		for (int i = 5; i < 10; ++i) {
			b.insertBack(i);
		}
		a.addAll(b);
		assertEquals("Representation not correct", "[ 0 1 2 3 4 5 6 7 8 9 ]", a.toString());
		b.insertBefore(3, 0);
		assertEquals("didn't copy elements", "[ 0 1 2 3 4 5 6 7 8 9 ]", a.toString());
	}
	
	@Test
	public void testAddAllIndex() {
		LinkedList<Integer> a = new LinkedList<Integer>();
		for (int i = 0; i < 5; ++i) {
			a.insertBack(i);
		}
		LinkedList<Integer> b = new LinkedList<Integer>();
		for (int i = 5; i < 10; ++i) {
			b.insertBack(i);
		}
		a.addAll(2, b);
		assertEquals("Representation not correct", "[ 0 1 5 6 7 8 9 2 3 4 ]", a.toString());
		b.insertBefore(3, 0);
		assertEquals("didn't copy elements", "[ 0 1 5 6 7 8 9 2 3 4 ]", a.toString());
	}
	
	@Test
	public void testClear() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		l.insertBack(10);
		l.insertBack(20);
		l.insertBack(30);
		assertEquals("size not correct", 3, l.size());
		assertEquals("Representation not correct", "[ 10 20 30 ]", l.toString());
		l.clear();
		assertEquals("size should be zero", 0, l.size());
		assertTrue("isEmpty should be true", l.isEmpty());
		assertEquals("Representation not correct", "[ ]", l.toString());
	}

	@Test
	public void testGet() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		for (int i = 0; i < 10; ++i) {
			l.insertBack(i);
		}
		for (int i = 0; i < 10; ++i) {
			assertEquals("unexpected value", i, l.get(i).intValue());
		}
	}
	
	@Test
	public void testSet() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		for (int i = 0; i < 10; ++i) {
			l.insertBack(0);
		}
		for (int i = 0; i < 10; ++i) {
			l.set(l.size() - (i + 1), i);
		}
		assertEquals("Representation not correct", "[ 9 8 7 6 5 4 3 2 1 0 ]", l.toString());
	}
	
	@Test
	public void testIndexOf() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		assertEquals("searching within empty should alway be -1", -1, l.indexOf(0));
		for (int i = 0; i < 5; ++i) {
			l.insertBack(i);
		}
		for (int i = 0; i < 5; ++i) {
			assertEquals("didn't find value", i, l.indexOf(i));
		}
		l = new LinkedList<Integer>();
		for (int i = 0; i < 5; ++i) {
			l.insertBack(10);
		}
		assertEquals("Didn't first occurence", 0, l.indexOf(10));
	}

	@Test
	public void testLastIndexOf() {
		LinkedList<Integer> l = new LinkedList<Integer>();
		assertEquals("searching within empty should alway be -1", -1, l.lastIndexOf(0));
		for (int i = 0; i < 5; ++i) {
			l.insertBack(i);
		}
		for (int i = 0; i < 5; ++i) {
			assertEquals("didn't find value", i, l.lastIndexOf(i));
		}
		l = new LinkedList<Integer>();
		for (int i = 0; i < 5; ++i) {
			l.insertBack(10);
		}
		assertEquals("Didn't first occurence", 4, l.lastIndexOf(10));
	}
}
