import unittest

from implementations.linked_list import LinkedList


class LinkedListTest(unittest.TestCase):

    def test_add(self):
        linked = LinkedList()
        linked.add(5)
        self.assertIsNotNone(linked.head)
        self.assertIsNotNone(linked.tail)
        self.assertEqual(linked.head.value, 5)
        self.assertEqual(linked.tail.value, 5)

    def test_add__consecutive(self):
        linked = LinkedList()
        linked.add(5)
        self.assertIsNotNone(linked.head)
        self.assertIsNotNone(linked.tail)
        self.assertEqual(linked.head.value, 5)
        self.assertEqual(linked.tail.value, 5)
        linked.add(0)
        self.assertIsNotNone(linked.head)
        self.assertIsNotNone(linked.tail)
        self.assertEqual(linked.head.value, 5)
        self.assertEqual(linked.tail.value, 0)
        linked.add(-1)
        self.assertIsNotNone(linked.head)
        self.assertIsNotNone(linked.tail)
        self.assertEqual(linked.head.value, 5)
        self.assertEqual(linked.tail.value, -1)

    def test_remove__single_element_list(self):
        linked = LinkedList()
        linked.add(5)
        linked.remove(0)
        self.assertIsNone(linked.head)
        self.assertIsNone(linked.tail)

    def test_remove__many_elements_list(self):
        linked = LinkedList()
        linked.add(5)
        linked.add(0)
        linked.add(-1)
        linked.remove(1)
        self.assertEqual(linked.head.value, 5)
        self.assertEqual(linked.tail.value, -1)
        linked.remove(1)
        self.assertEqual(linked.head.value, 5)
        self.assertEqual(linked.tail.value, 5)

    def test_remove__from_tail(self):
        linked = LinkedList()
        linked.add(5)
        linked.add(0)
        linked.add(-1)
        linked.remove(2)
        self.assertEqual(linked.head.value, 5)
        self.assertEqual(linked.tail.value, 0)

    def test_remove__out_of_bounds(self):
        linked = LinkedList()
        self.assertRaises(IndexError, linked.remove, 2)


if __name__ == '__main__':
    unittest.main()