diff --git a/src/linked_list.py b/src/linked_list.py index f0b66db..f1b91db 100644 --- a/src/linked_list.py +++ b/src/linked_list.py @@ -4,10 +4,16 @@ class LinkedList(object): """Class representation of linked list.""" - def __init__(self, head_node): + def __init__(self, iterable=None): """Instantiate linked list.""" - self.head_node = head_node - self.length = 1 + self.head_node = None + self.length = 0 + try: + for item in iterable: + self.push(item) + except TypeError: + if iterable: + raise TypeError("Please only enter iterable values") def push(self, contents): """Add node to this linked list.""" @@ -16,10 +22,12 @@ def push(self, contents): def pop(self): """Remove and return the current head node.""" + if not self.head_node: + raise IndexError("List is already empty") old_head_node = self.head_node self.head_node = self.head_node.next_node self.length -= 1 - return old_head_node + return old_head_node.contents def size(self): """Return the current size of this linked list.""" @@ -27,37 +35,44 @@ def size(self): def search(self, search_value): """Return the node with the searched contents if found.""" - if search_value == self.head_node.contents: - return self.head_node - current_node = self.head_node - while current_node.contents != search_value: - if current_node.next_node is None: - return None - current_node = current_node.next_node - return current_node + if self.length: + if search_value == self.head_node.contents: + return self.head_node + current_node = self.head_node + while current_node.contents != search_value: + if current_node.next_node is None: + return None + current_node = current_node.next_node + return current_node + else: + return None - def remove(self, remove_node): + def remove(self, remove_value): """Remove a node from linked list.""" - if remove_node == self.head_node: - self.head_node = self.head_node.next_node - self.length -= 1 - return None - elif remove_node is None: - raise ValueError("Provided value not in list.") + last_node = None current_node = self.head_node - while current_node.next_node != remove_node: + while current_node: + if current_node.contents == remove_value: + if last_node: + last_node.next_node = current_node.next_node + else: + self.head_node = current_node.next_node + self.length -= 1 + return + last_node = current_node current_node = current_node.next_node - current_node.next_node = current_node.next_node.next_node - self.length -= 1 def display(self): """Return the tuple of all values in linked list.""" - new_list = [self.head_node.contents] - current_node = self.head_node - while current_node.next_node is not None: - current_node = current_node.next_node - new_list.append(current_node.contents) - return tuple(new_list) + if self.length == 0: + return None + else: + new_list = [self.head_node.contents] + current_node = self.head_node + while current_node.next_node is not None: + current_node = current_node.next_node + new_list.append(current_node.contents) + return str(tuple(new_list)) class Node(object): diff --git a/src/test_linked_list.py b/src/test_linked_list.py index 73089c0..085a8b8 100644 --- a/src/test_linked_list.py +++ b/src/test_linked_list.py @@ -1,108 +1,133 @@ """Tests for linked_list.py.""" +import pytest + + +@pytest.fixture +def sample_linked_list(): + """Create testing linked list.""" + from linked_list import LinkedList + one_llist = LinkedList([1]) + empty_llist = LinkedList() + new_llist = LinkedList([1, 2, 3, 4, 5]) + return (empty_llist, one_llist, new_llist) + def test_node_init(): """Test node class init.""" from linked_list import Node - new_node = Node(1, None) - assert new_node.contents == 1 and new_node.next_node is None - - -def test_linkedlist_init(): - """Test for LinkedList init.""" - from linked_list import Node, LinkedList - new_node = Node(34, None) - new_llist = LinkedList(new_node) - assert new_llist.length == 1 - assert new_llist.head_node == new_node - - -def test_linkedlist_push(): - """Test for LinkedList push.""" - from linked_list import Node, LinkedList - new_node = Node(34, None) - new_llist = LinkedList(new_node) - new_llist.push(1) - assert new_llist.length == 2 - assert new_llist.head_node.contents == 1 - - -def test_linkedlist_pop(): - """Test for LinkedList pop.""" - from linked_list import Node, LinkedList - new_node = Node(34, None) - new_llist = LinkedList(new_node) - new_llist.push(1) - new_llist.pop() - assert new_llist.head_node.contents == 34 - assert new_llist.length == 1 - - -def test_linkedlist_size(): - """Test for LinkedList size.""" - from linked_list import Node, LinkedList - new_node = Node(34, None) - new_llist = LinkedList(new_node) - new_llist.push(1) - new_llist.pop() - new_llist.push('test1') - new_llist.push('test2') - new_llist.push('test3') - new_llist.push('test4') - assert new_llist.size() == 5 - - -def test_linkedlist_search(): - """Test for LinkedList search.""" - from linked_list import Node, LinkedList - new_node = Node(34, None) - new_llist = LinkedList(new_node) - new_llist.push(1) - new_llist.pop() - new_llist.push('test1') - new_llist.push('test2') - new_llist.push('test3') - new_llist.push('test4') - assert new_llist.search('test4').contents == 'test4' - assert new_llist.search('test2').contents == 'test2' - assert new_llist.search('test100') is None - - -def test_linkedlist_remove(): - """Test for LinkedList remove.""" - from linked_list import Node, LinkedList - new_node = Node('Test5', None) - new_llist = LinkedList(new_node) - new_llist.push('test4') - new_llist.push('test3') - new_llist.push('test2') - new_llist.push('test1') - new_llist.remove(new_llist.search('test2')) - assert new_llist.size() == 4 - assert new_llist.search('test1').next_node.contents == 'test3' - new_node2 = Node('Test5', None) - new_llist2 = LinkedList(new_node2) - new_llist2.push('test4') - new_llist2.push('test3') - new_llist2.push('test2') - new_llist2.push('test1') - new_llist2.remove(new_llist2.search('test1')) - assert new_llist2.head_node.contents == 'test2' - try: - new_llist.remove(new_llist.search('blah')) - except ValueError: - assert True - - -def test_linkedlist_display(): - """Test for LinkedList remove.""" - from linked_list import Node, LinkedList - new_node = Node('test5', None) - new_llist = LinkedList(new_node) - new_llist.push('test4') - new_llist.push('test3') - new_llist.push('test2') - new_llist.push('test1') - new_llist2 = LinkedList(new_node) - assert new_llist.display() == ('test1', 'test2', 'test3', 'test4', 'test5') - assert new_llist2.display() == ('test5',) + new_node = Node(0, None) + assert new_node.contents == 0 and new_node.next_node is None + + +def test_linkedlist_init_empty_size(sample_linked_list): + """Test for empty LinkedList init.""" + assert sample_linked_list[0].length == 0 + + +def test_linkedlist_init_empty_head(sample_linked_list): + """Test head in empty LinkedList init.""" + assert sample_linked_list[0].head_node is None + + +def test_linkedlist_init_one_size(sample_linked_list): + """Test for LinkedList init single item.""" + assert sample_linked_list[1].length == 1 + + +def test_linkedlist_init_one_head(sample_linked_list): + """Test head in LinkedList init single item.""" + assert sample_linked_list[1].head_node.contents == 1 + + +def test_linkedlist_init_list_size(sample_linked_list): + """Test for LinkedList init with list.""" + assert sample_linked_list[2].length == 5 + + +def test_linkedlist_init_list_head(sample_linked_list): + """Test head in LinkedList init with list.""" + assert sample_linked_list[2].head_node.contents == 5 + + +def test_linkedlist_push_size(sample_linked_list): + """Test for LinkedList size after push.""" + test_linkedlist = sample_linked_list[2] + test_linkedlist.push("new") + assert test_linkedlist.length == 6 + + +def test_linkedlist_push_val(sample_linked_list): + """Test for LinkedList head value after push.""" + test_linkedlist = sample_linked_list[2] + test_linkedlist.push("new") + assert test_linkedlist.head_node.contents == 'new' + + +def test_linkedlist_pop_empty(sample_linked_list): + """Test for Linked List pop on empty.""" + with pytest.raises(IndexError): + sample_linked_list[0].pop() + + +def test_linkedlist_pop_one(sample_linked_list): + """Test for Linked List pop on list with one item.""" + assert sample_linked_list[1].pop() == 1 + + +def test_linkedlist_pop_list(sample_linked_list): + """Test for Linked List pop on multi-item list.""" + assert sample_linked_list[2].pop() == 5 + + +def test_linkedlist_search_list(sample_linked_list): + """Test for LinkedList search list.""" + assert sample_linked_list[2].search(2).contents == 2 + + +def test_linkedlist_search_empty(sample_linked_list): + """Test for LinkedList search empty list.""" + assert sample_linked_list[1].search(2) is None + + +def test_linkedlist_search_list_false(sample_linked_list): + """Test for LinkedList search list when search value is not in list.""" + assert sample_linked_list[2].search(100) is None + + +def test_linkedlist_remove(sample_linked_list): + """Test that removed value is gone after remove().""" + sample_linked_list[2].remove(3) + assert sample_linked_list[2].search(3) is None + + +def test_linkedlist_remove_pointers(sample_linked_list): + """Test that previous node points to correct node after remove().""" + sample_linked_list[2].remove(3) + assert sample_linked_list[2].search(4).next_node.contents == 2 + + +def test_linkedlist_remove_head(sample_linked_list): + """Test LinkedList remove() the head on a list.""" + sample_linked_list[2].remove(5) + assert sample_linked_list[2].head_node.contents == 4 + + +def test_linkedlist_remove_empty(sample_linked_list): + """Test LinkedList remove() on an empty linked list.""" + sample_linked_list[1].remove(5) is None + + +def test_linkedlist_display(sample_linked_list): + """Test for LinkedList display.""" + assert sample_linked_list[2].display() == '(5, 4, 3, 2, 1)' + + +def test_linkedlist_display_one(sample_linked_list): + """Test for LinkedList display on single item list.""" + assert sample_linked_list[1].display() == '(1,)' + + +def test_linkedlist_display_empty(sample_linked_list): + """Test for LinkedList display on empty list.""" + assert sample_linked_list[0].display() is None