def test_split_method(helper):
    lst = helper.get_list(length=100)
    cll = CircularLinkedList(lst)
    for i in range(len(lst)):
        # test left list
        left_list, right_list = cll.split(i)
        assert isinstance(left_list, LinkedList)
        assert left_list.to_list() == lst[:i]
        assert left_list.copy().to_list() == lst[:i]
        assert left_list.reverse().to_list() == lst[:i][::-1]
        # test right list
        assert isinstance(right_list, CircularLinkedList)
        assert right_list.to_list() == lst[i:]
        assert right_list.copy().to_list() == lst[i:]
        assert right_list.reverse().to_list() == lst[i:][::-1]
    cll.add_front(0)
    cll.add_end("apple")
    assert cll._length == len(cll) == len(lst) + 2
    assert cll.to_list() == [0] + lst + ["apple"]
def test_creating_circular_linked_list_from_constructor(helper):
    # Using constructor
    val = helper.get_value()
    cll = CircularLinkedList()
    cll.add_front(val)
    assert isinstance(cll._head, Node)
    assert cll._head.get_data() == val
    assert cll._head.get_next() == cll._head._next == cll._head
    assert len(cll) == cll._length == 1
    assert cll.to_list() == [item for item in cll] == [val]
    # Using Node
    cll = CircularLinkedList()
    with pytest.raises(TypeError):
        cll.add_front(DoublyNode(helper.get_value()))
    val = helper.get_value()
    cll = CircularLinkedList()
    cll.add_end(val)
    assert isinstance(cll._head, Node)
    cll._head.get_data() == val
    cll._head.get_next() == cll._head._next == cll._head
    assert len(cll) == cll._length == 1
    assert cll.to_list() == [item for item in cll] == [val]
def test_empty_circular_linked_list(helper):
    EMPTY = "┌─\n│\n└─"  # represents empty LinkedList
    cll = CircularLinkedList([])
    assert str(cll) == EMPTY
    assert cll._length == len(cll) == 0
    assert cll.is_empty()
    assert cll.to_list() == []
    assert [_ for _ in cll] == []
    assert len(cll.copy()) == 0
    assert len(cll.reverse()) == 0
    # ==================== test operators ====================
    assert CircularLinkedList() == CircularLinkedList()
    assert cll == cll.copy()
    assert cll == cll.reverse()
    assert CircularLinkedList() != CircularLinkedList([helper.get_value()])
    assert CircularLinkedList() < CircularLinkedList([helper.get_value()])
    assert CircularLinkedList() <= CircularLinkedList([helper.get_value()])
    assert CircularLinkedList([helper.get_value()]) > CircularLinkedList()
    assert CircularLinkedList([helper.get_value()]) >= CircularLinkedList()
    # ==================== test count ====================
    assert cll.count(0) == 0
    assert cll.count(helper.get_value()) == 0
    assert cll.count(Node(helper.get_value())) == 0
    # ==================== test __contains__ ====================
    assert None not in cll
    assert Node(helper.get_value()) not in cll
    assert 0 not in cll
    assert helper.get_value() not in cll
    assert LinkedList() not in cll
    # assert LinkedList(helper.get_value()) not in ll
    # ==================== test split ====================
    left_list, right_list = cll.split(0)
    assert str(left_list) == str(right_list) == EMPTY
    with pytest.raises(TypeError):
        cll.split(helper.get_string())
    with pytest.raises(TypeError):
        cll.split(helper.get_float())
    with pytest.raises(TypeError):
        cll.split(True)
    with pytest.raises(IndexError):
        cll.split(-1)
    cll.split(helper.get_pos_int())  # shouldn't raise anything
    with pytest.raises(IndexError):
        cll.split(helper.get_neg_int())
    # ==================== test rotate ====================
    assert cll.rotate_left(helper.get_pos_int(), inplace=False) == cll
    assert cll.rotate_right(helper.get_pos_int(), inplace=False) == cll
    assert len(cll.rotate_left(helper.get_pos_int(), inplace=False)) == 0
    assert len(cll.rotate_right(helper.get_pos_int(), inplace=False)) == 0
    with pytest.raises(TypeError):
        cll.rotate_left(helper.get_string())
    with pytest.raises(TypeError):
        cll.rotate_right(helper.get_float())
    with pytest.raises(TypeError):
        cll.rotate_left([])
    with pytest.raises(ValueError):
        cll.rotate_left(helper.get_neg_int())
    with pytest.raises(ValueError):
        cll.rotate_right(helper.get_neg_int())
    # ==================== test remove/del ====================
    cll.remove_front()  # shouldn't raise any Error
    cll.remove_end()  # shouldn't raise any Error
    cll.remove(helper.get_value())
    cll.remove(helper.get_value(), False)
    with pytest.raises(TypeError):
        cll.remove(helper.get_value(), all=helper.get_string(1))
    del cll[0]  # shouldn't raise anything
    del cll[helper.get_pos_int()]  # shouldn't raise anything
    with pytest.raises(IndexError):
        del cll[helper.get_neg_int()]
    # ==================== test __getitem__ ====================
    with pytest.raises(IndexError):
        _ = cll[0]
    with pytest.raises(IndexError):
        _ = cll[helper.get_pos_int()]
    with pytest.raises(IndexError):
        _ = cll[helper.get_neg_int()]
    with pytest.raises(IndexError):
        CircularLinkedList() == cll[0:10]
    # ==================== test insert/set ====================
    # the following line shouldn't raise anything !!
    cll.insert(helper.get_pos_int(), helper.get_value())
    with pytest.raises(IndexError):
        cll.insert(helper.get_neg_int(), helper.get_value())
    cll[0] = helper.get_float()  # shouldn't raise anything
    # the following line shouldn't raise anything !!
    cll[helper.get_pos_int()] = helper.get_float()
    with pytest.raises(ValueError):
        cll.insert(0, None)
    with pytest.raises(TypeError):
        cll.insert(0, Node(helper.get_value()))
def test_extend_method(helper):
    lst = helper.get_list()
    # two linked lists are empty
    cll1 = CircularLinkedList()
    cll1.extend(CircularLinkedList())
    assert cll1 == CircularLinkedList()
    # one linked list is empty
    cll1 = CircularLinkedList([])
    cll2 = CircularLinkedList(lst)
    cll1.extend(cll2)
    assert cll1 == cll2
    assert len(cll1) == len(lst)
    cll2.extend(cll1)
    assert len(cll2) == 2 * len(lst)
    # two linked lists are NOT empty
    cll1 = CircularLinkedList(lst)
    cll2 = CircularLinkedList(lst)
    cll2.extend(cll1)
    assert cll1.to_list() == lst
    assert cll2.to_list() == lst + lst
    assert len(cll2) == 2 * len(lst)
def test_creating_circular_linked_list_from_iterable(helper):
    # Using from_iterable (small length)
    lst = helper.get_list()
    cll = CircularLinkedList(lst)
    assert cll._head.get_data() == lst[0]
    assert len(cll) == cll._length == len(lst)
    assert cll.to_list() == [item for item in cll] == lst
    # Using from_iterable (has None)
    with pytest.raises(ValueError):
        CircularLinkedList([1, 2, None, 3])
    with pytest.raises(TypeError):
        CircularLinkedList().add_end(LinkedList())
    with pytest.raises(TypeError):
        CircularLinkedList().add_front(DoublyLinkedList())
    with pytest.raises(TypeError):
        CircularLinkedList().add_front(CircularLinkedList())
    # Using from_iterable (big length)
    lst = helper.get_list(length=10000)
    cll = CircularLinkedList(lst)
    assert cll._head.get_data() == lst[0]
    assert len(cll) == cll._length == len(lst)
    assert cll.to_list() == [item for item in cll] == lst
    for _ in range(100):  # check random indices
        idx = helper.get_pos_int(b=10000 - 1)
        assert cll[idx] == lst[idx]
    # Using Linked List
    lst = helper.get_list()
    tmp_cll = CircularLinkedList(lst)
    cll = CircularLinkedList(tmp_cll)
    # assert cll == tmp_cll
    assert len(cll) == cll._length == len(lst)
    assert cll.to_list() == [item for item in cll] == lst
def test_rotate():
    # rotate when inplace = False
    cll = CircularLinkedList([1, 2, 3, 4, 5, 6])
    rotated = cll.rotate_right(1, inplace=False)
    assert rotated.to_list() == [6, 1, 2, 3, 4, 5]
    assert isinstance(rotated._head, Node)
    assert rotated._head.get_data() == 6
    assert rotated[4] == 4
    rotated = cll.rotate_left(3, inplace=False)
    assert isinstance(rotated._head, Node)
    assert rotated.to_list() == [4, 5, 6, 1, 2, 3]
    assert rotated._head.get_data() == 4
    with pytest.raises(IndexError):
        rotated[-1] == 3
    assert cll.to_list() == [1, 2, 3, 4, 5, 6]
    # rotate when inplace = True
    cll.rotate_right(1)
    assert cll.to_list() == [6, 1, 2, 3, 4, 5]
    assert isinstance(cll._head, Node)
    assert cll._head.get_data() == 6
    cll.rotate_left(3)
    assert cll.to_list() == [3, 4, 5, 6, 1, 2]
    assert cll._head.get_data() == 3
    assert isinstance(cll._head, Node)
def test_relational_operators(helper):
    # linked lists have just one value
    assert CircularLinkedList([3.14]) == CircularLinkedList([3.14])
    assert (CircularLinkedList([helper.get_int()]) != CircularLinkedList(
        [helper.get_float()]))
    assert (CircularLinkedList([helper.get_string()]) != CircularLinkedList(
        [helper.get_int()]))
    assert (CircularLinkedList([helper.get_float()]) != CircularLinkedList(
        [helper.get_list()]))
    assert CircularLinkedList([2.9999]) < CircularLinkedList([3])
    assert CircularLinkedList([3.14]) <= CircularLinkedList([3.14])
    assert CircularLinkedList([3, 2]) > CircularLinkedList([3])
    assert CircularLinkedList(["3.14"]) >= CircularLinkedList(["3.14"])
    with pytest.raises(TypeError):
        (CircularLinkedList([helper.get_float()]) < CircularLinkedList(
            [helper.get_string()]))
    with pytest.raises(TypeError):
        (CircularLinkedList([helper.get_value()]) <= CircularLinkedList(
            [helper.get_list()]))
    with pytest.raises(TypeError):
        (CircularLinkedList([helper.get_string()]) > CircularLinkedList(
            [helper.get_list()]))
    with pytest.raises(TypeError):
        (CircularLinkedList([helper.get_list()]) >= CircularLinkedList(
            [helper.get_float()]))
    # linked lists have more than one value
    cll1 = CircularLinkedList([1, "2", 3.14])
    cll2 = CircularLinkedList([1, "2", 5.14])
    assert cll1 == cll1
    assert cll1 != cll2
    assert cll1 < cll2
    assert cll1 <= cll2
    assert cll2 > cll1
    assert cll2 >= cll2
    # slicing lists
    with pytest.raises(IndexError):
        cll1[:-1] == cll2[:-1]
    with pytest.raises(IndexError):
        cll1[-1:] != cll2[-1:]
    with pytest.raises(IndexError):
        cll1[:1] < cll2
    with pytest.raises(IndexError):
        cll1[:2] <= cll2
    with pytest.raises(IndexError):
        assert cll1[1:] < cll2
    with pytest.raises(IndexError):
        assert cll1[1:] <= cll2
    # if the other one isn't a circular linked list
    actual_list = [1, "2", 5.14]
    with pytest.raises(TypeError):
        assert cll1 == actual_list
    with pytest.raises(TypeError):
        assert cll1 != actual_list
    with pytest.raises(TypeError):
        assert cll1 < actual_list
    with pytest.raises(TypeError):
        assert cll1 <= actual_list
    with pytest.raises(TypeError):
        assert cll2 > actual_list
    with pytest.raises(TypeError):
        assert cll2 >= actual_list
def test_circular_linked_list_with_random_numbers(helper):
    # test add_end() and remove_end()
    lst = helper.get_list(length=100)
    cll = CircularLinkedList()
    for i in lst:
        cll.add_end(i)
    assert len(cll) == len(lst)
    assert cll._head.get_data() == lst[0]
    assert not cll.is_empty()
    for _ in range(len(lst)):
        assert cll[0] == lst[0]
        cll.remove_end()
        lst.pop()
    assert len(cll) == 0
    assert cll.is_empty()
    # test add_front() and remove_front()
    lst = helper.get_list(length=100)
    for i in lst:
        cll.add_front(i)
    assert len(cll) == len(lst)
    assert cll._head.get_data() == lst[-1]
    assert not cll.is_empty()
    for _ in range(len(lst)):
        assert cll[0] == lst[-1]
        cll.remove_front()
        lst.pop()
    assert len(cll) == 0
    assert cll.is_empty()
def test_circular_linked_list_with_known_values():
    cll = CircularLinkedList()
    cll.add_front(10)
    cll.add_front(5)
    assert cll.to_list() == [5, 10]
    cll.remove(20)
    cll.remove_front()
    assert cll == CircularLinkedList([10])
    cll.remove_end()
    assert cll == CircularLinkedList()
    cll.insert(0, 100)
    cll.insert(1, 200)
    cll.insert(1, 100)
    assert 100 in cll and 200 in cll
    assert cll == CircularLinkedList([100, 100, 200])
    assert cll.copy().to_list() == [100, 100, 200]
    assert cll.reverse() == CircularLinkedList([200, 100, 100])
    cll.remove(100)
    rev = cll.reverse()
    assert cll == rev == CircularLinkedList([200])
    cll.clear()
    assert not rev.is_empty()
    assert cll.is_empty()
    # ==================================================
    cll = LinkedList()
    cll.add_front(6)
    cll.add_end(20)
    cll.insert(1, 10)
    cll.insert(2, 77)
    cll.insert(4, 43)
    cll.insert(0, 2)
    assert 43 in cll
    assert cll[1:4].to_list() == [6, 10, 77]
    assert cll.copy().to_list() == [2, 6, 10, 77, 20, 43]
    del cll[len(cll) - 1]
    assert cll.reverse().to_list() == [20, 77, 10, 6, 2]
    assert cll._length == len(cll) == 5
    cll.clear()
    assert cll.is_empty()
def test_list_with_same_value(helper):
    length = helper.get_pos_int()
    val = helper.get_value()
    cll = CircularLinkedList()
    # test add_end
    for _ in range(length):
        cll.add_end(val)
    # test add_front
    for _ in range(length):
        cll.add_front(val)
    # test __setitem__()
    cll[1] = val
    assert cll == cll.reverse()
    assert cll == cll.copy()
    assert not cll.is_empty()
    assert len(cll) == 2 * length
    assert cll.count(val) == 2 * length
    assert cll.to_list() == [val] * (2 * length)
    # test split
    left_list, right_list = cll.split(length)
    assert len(left_list) == len(right_list) == length
    # test clear
    left_list.clear()
    right_list.clear()
    assert len(left_list) == len(right_list) == 0
    # test remove
    for i in range(length):
        if i > length // 2:
            cll.remove_end()
        else:
            cll.remove_front()
    assert len(cll) == cll.count(val) == length
    cll.remove(val, all=True)
    assert cll.is_empty()
    assert len(cll) == 0
def test_circular_linked_list_with_one_element(helper):
    val = helper.get_value()
    cll = CircularLinkedList()
    cll.insert(0, val)
    assert isinstance(cll._head, Node)
    assert cll._head.get_data() == val
    assert cll._head.get_next() == cll._head
    assert len(cll) == 1
    assert not cll.is_empty()
    assert val in cll
    assert [item for item in cll] == [val]
    assert cll.to_list() == [val]
    assert cll == cll.copy()
    assert cll == cll.reverse()
    # ==================== test rotate ====================
    assert cll == cll.rotate_left(helper.get_pos_int(), inplace=False)
    assert cll == cll.rotate_right(helper.get_pos_int(), inplace=False)
    # ==================== test operators ====================
    assert cll != CircularLinkedList()
    assert cll > CircularLinkedList()
    assert cll >= CircularLinkedList()
    assert CircularLinkedList() < cll
    assert CircularLinkedList() <= cll
    # ==================== test add/remove ====================
    new_value = helper.get_value()
    cll.add_front(new_value)
    cll.remove_front()
    cll.add_end(new_value)
    cll.remove_end()
    assert cll == CircularLinkedList([val])
    # ==================== test insert/split ====================
    with pytest.raises(IndexError):
        cll.insert(-1, helper.get_value())
    cll.insert(2, helper.get_value())  # shouldn't raise anything
    cll.split(helper.get_pos_int())  # shouldn't raise anything