package migl.lisp;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

import java.util.HashMap;
import java.util.Map;

import org.junit.Before;
import org.junit.Test;

public class LispListOwnTest {
	
	private LispList list;

	@Before
	public void init() {
		list = LispList.nil();
	}
	
	@Test
	public void testValueOf1() {
		list.prepend("8").prepend("4").prepend("2").prepend("1").append("16");
		assertEquals(list, LispList.valueOf("(1 2 4 8 16)"));
	}
	
	@Test
	public void testValueOf2() {
		LispList list = LispList.valueOf("(8 )");
		LispList expected = LispList.valueOf("(8)");
		assertEquals(expected, list);
	}
	
	@Test
	public void testIsEmpty() {
		assertTrue(list.isEmpty());
		assertEquals(0, list.size());
		list.prepend(8);
		assertFalse(list.isEmpty());
		assertEquals(1, list.size());
	}
	
	@Test
	public void testSize() {
		list.prepend(8).prepend(4).prepend(2).prepend(1).append(16);
		assertEquals(5, list.size());
		assertEquals(3, list.getSubList(2).size());
	}
	
	@Test
	public void testPrepend() {
		list.prepend("8").prepend("4").prepend("2").prepend("1");
		assertEquals(LispList.valueOf("(1 2 4 8)"), list);
	}
	
	@Test
	public void testAppend() {
		list.append("8").append("4").append("2").append("1");
		assertEquals(LispList.valueOf("(8 4 2 1)"), list);
	}
	
	@Test
	public void testGetElement() {
		list.prepend(8).prepend(4).prepend(2).prepend(1).append(16);
		assertEquals(8, list.get(3));
		assertEquals(4, list.get(2));
		assertEquals(2, list.get(1));
		assertEquals(1, list.get(0));
		assertEquals(16, list.get(4));
		assertNull(list.get(5));
		assertNull(list.get(-1));
	}
	
	@Test
	public void testGetSubList() {
		list.prepend(8).prepend(4).prepend(2).prepend(1).append(16);
		LispList expected = LispList.nil();
		expected.prepend(8).prepend(4).append(16);
		assertEquals(expected, list.getSubList(2));
	}
	
	@Test
	public void testToString() {
		list.prepend(8).prepend(4).prepend(2).prepend(1).append(16);
		assertEquals("(1 2 4 8 16)", list.toString());
		assertEquals("()", LispList.nil().toString());
	}
	
	@Test
	public void testEquals() {
		list.prepend(8).prepend(4).prepend(2).prepend(1);
		LispList l = LispList.nil();
		l.prepend(8).prepend(4).prepend(2).prepend(1);
		assertTrue(list.equals(list));
		assertFalse(list.equals(null));
		assertTrue(list.equals(l));
		assertFalse(list.equals(new Object()));
	}
	
	@Test
	public void testHashCode() {
		list.prepend(8).prepend(4).prepend(2).prepend(1).append(16);
		LispList list2 = list.getSubList(2);
		LispList list3 = LispList.nil();
		LispList list4 = LispList.valueOf("(8 4)");
		Map<LispList, String> map = new HashMap<>();
		map.put(list, "L1");
		map.put(list2, "L2");
		map.put(list3, "L3");
		map.put(list4, "L4");
		assertEquals("L1", map.get(list));
		assertEquals("L2", map.get(list2));
		assertEquals("L3", map.get(list3));
		assertEquals("L4", map.get(list4));
	}

}
