# region PROBLEM
'''
<> LL: Append
Implement the append method for the LinkedList class.

The append method should add a new node with a given value to the end of the
linked list, updating the tail attribute and the length attribute accordingly.

Requirements:
    - Handle both the empty-list case and the non-empty-list case.
    - Create a new node with the given value and add it to the end of the list.
    - Update the tail attribute of the LinkedList correctly.
    - Update the length attribute of the LinkedList to reflect the addition.

Example:
    my_linked_list = LinkedList(1)
    my_linked_list.make_empty()
    my_linked_list.append(1)
    my_linked_list.append(2)

Expected state:
    head  = 1
    tail  = 2
    length = 2
'''

class Node:
    def __init__(self, value):
        self.value = value
        self.next = None


class LinkedList:
    def __init__(self, value):
        new_node = Node(value)
        self.head = new_node
        self.tail = new_node
        self.length = 1

    def print_list(self):
        temp = self.head
        while temp is not None:
            print(temp.value)
            temp = temp.next

    def make_empty(self):
        self.head = None
        self.tail = None
        self.length = 0
# endregion


# region SOLUTION

def append(self, value):
    
    new_node = Node(value)
    
    if self.length == 0:
        self.head = new_node
        self.tail = new_node
        self.length = 1
    else:
        self.tail.next = new_node
        self.tail = new_node
        self.length += 1

LinkedList.append = append

# endregion


# region TESTS

def test_append_to_empty_list():
    ll = LinkedList(1)
    ll.make_empty()
    ll.append(5)
    assert ll.head.value == 5
    assert ll.tail.value == 5
    assert ll.head is ll.tail
    assert ll.length == 1


def test_append_to_non_empty_list():
    ll = LinkedList(1)
    ll.append(2)
    assert ll.head.value == 1
    assert ll.tail.value == 2
    assert ll.head.next is ll.tail
    assert ll.length == 2


def test_append_multiple_nodes():
    ll = LinkedList(1)
    ll.make_empty()
    ll.append(1)
    ll.append(2)
    ll.append(3)
    assert ll.head.value == 1
    assert ll.head.next.value == 2
    assert ll.tail.value == 3
    assert ll.tail.next is None
    assert ll.length == 3


def test_append_links_tail_correctly():
    ll = LinkedList(10)
    old_tail = ll.tail
    ll.append(20)
    assert old_tail.next is ll.tail
    assert ll.tail.value == 20
    assert ll.tail.next is None


if __name__ == "__main__":
    import pytest

    raise SystemExit(pytest.main([__file__, "-v"]))

# endregion
