package migl.util;

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

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

import org.junit.Test;

public class ConsTest {

    @Test
    public void testNilCons() {
        Cons<String, String> c1 = Cons.nil();
        assertNull(c1.left());
        assertNull(c1.right());
        assertEquals("(null . null)", c1.toString());
    }

    @Test
    public void testSimpleCons() {
        Cons<String, String> c1 = new Cons<>("a", "b");
        assertEquals("(a . b)", c1.toString());
        assertEquals("a", c1.left());
        assertEquals("b", c1.right());
    }

    @Test
    public void testNestedCons() {
        Cons<String, Cons<String, String>> c1 = new Cons<>("a", new Cons<>("b", "c"));
        assertEquals("(a . (b . c))", c1.toString());
    }

    @Test
    public void testEquals() {
        Cons<String, String> c1 = new Cons<>("a", "b");
        Cons<String, String> c2 = new Cons<>("a", "b");
        Cons<String, String> c3 = new Cons<>("a", "c");
        Cons<String, String> c4 = new Cons<>("c", "b");
        Cons<String, String> c5 = new Cons<>("c", "d");
        assertEquals(c1, c2);
        assertNotEquals(c1, null);
        assertNotEquals(c1, true);
        assertNotEquals(null, c2);
        assertNotEquals(true, c2);
        assertNotEquals(c1, c3);
        assertNotEquals(c1, c4);
        assertNotEquals(c1, c5);
    }

    @Test
    public void testConsEquals() {
        Cons<String, String> c1 = new Cons<>("a", "b");
        Cons<String, String> c2 = new Cons<>("a", null);
        Cons<String, String> c3 = new Cons<>("a", "c");
        Cons<String, String> c4 = new Cons<>("a", "a");
        Cons<String, String> c5 = new Cons<>(null, "a");
        Cons<String, String> c6 = new Cons<>("a", "c");
        Cons<String, String> c7 = new Cons<>("a", null);

        assertTrue(c1.equals(c1));
        assertFalse(c2.equals(c3));
        assertFalse(c2.equals(new Cons<>("b", null)));
        assertTrue(c3.equals(c6));
        assertFalse(c4.equals(c5));
        assertFalse(c5.equals(c6));
        assertTrue(c2.equals(c7));
        assertFalse(c5.equals(new Cons<>(null, "b")));
        assertEquals(c1.hashCode(), c1.hashCode());
        assertEquals(c3.hashCode(), c6.hashCode());
        assertEquals(c2.hashCode(), c7.hashCode());
    }

    @Test
    public void testConsHashCode() {
        Cons<String, String> c1 = new Cons<>("a", "b");
        Cons<String, String> c2 = new Cons<>("a", null);
        Cons<String, String> c3 = new Cons<>(null, "a");
        Cons<String, String> c4 = new Cons<>(null, null);
        Map<Cons<String, String>, String> map = new HashMap<>();
        map.put(c1, "C1");
        map.put(c2, "C2");
        map.put(c3, "C3");
        map.put(c4, "C4");
        assertEquals("C1", map.get(c1));
        assertEquals("C2", map.get(c2));
        assertEquals("C3", map.get(c3));
        assertEquals("C4", map.get(c4));
    }
}
