def test_rotate_right_should_make_previous_root_a_right_child_to_new_root():
    new_root = Node(value=2, right=Node(value=99))
    previous_root = Node(value=1, left=new_root)

    rotate_right(subtree_root=previous_root)

    assert new_root.right is previous_root
def test_rotate_right_should_raise_an_error_when_new_root_has_no_right_child():
    new_root_value = 22
    new_root = Node(value=new_root_value)

    with pytest.raises(MissingRightChildOfNodeError) as err:
        rotate_right(subtree_root=Node(value=33, left=new_root))

    assert f"{new_root_value}" in str(err)
def test_rotate_right_should_raise_an_error_when_subtree_root_has_no_left_child(
):
    root_value = 33

    with pytest.raises(MissingLeftChildOfNodeError) as err:
        rotate_right(subtree_root=Node(value=root_value))

    assert f"{root_value}" in str(err)
def test_rotate_right_should_not_change_left_child_of_new_root():
    left_child_of_new_root = Node(value=3)
    new_root = Node(value=2, left=left_child_of_new_root, right=Node(value=88))
    previous_root = Node(value=1, left=new_root)

    rotate_right(subtree_root=previous_root)

    assert new_root.left is left_child_of_new_root
def test_rotate_right_should_make_new_root_right_child_a_left_child_to_previous_root(
):
    right_child_of_new_root = Node(value=2)
    new_root = Node(value=3, right=right_child_of_new_root)
    previous_root = Node(value=2, left=new_root)

    rotate_right(subtree_root=previous_root)

    assert previous_root.left is right_child_of_new_root
def test_rotate_right_should_not_change_right_child_of_previous_root():
    right_child_of_previous_root = Node(value=0)
    new_root = Node(value=3, right=Node(value=77))
    previous_root = Node(value=1,
                         left=new_root,
                         right=right_child_of_previous_root)

    rotate_right(subtree_root=previous_root)

    assert previous_root.right is right_child_of_previous_root
    def insert(self, value: int) -> None:
        if self.is_empty():
            # Case_I3: N is the root and red
            self.__root = ColorNode(value=value, is_red=False)
            return

        current: Optional[ColorNode] = self.__root

        while current is not None:
            if value == current.value:
                raise DuplicatedValueInTreeError(
                    f"Value {value} is already present")

            previous = current
            current = current.left if value < current.value else current.right

        current = ColorNode(value=value, is_red=True, parent=previous)
        if current.value > previous.value:
            previous.right = current
        else:
            previous.left = current

        if not current.parent.is_red:
            # Case_I1 (P is black)
            return

        if current.parent.parent is None:
            # Case_I4
            current.parent.is_red = False
            return

        if current.is_uncle_black():
            # Case_I6
            if current is current.parent.right:
                new_subtree_root = rotate_left(
                    subtree_root=current.parent.parent)
                new_subtree_root.is_red = False
                new_subtree_root.left.is_red = True
            else:
                new_subtree_root = rotate_right(
                    subtree_root=current.parent.parent)
                new_subtree_root.is_red = False
                new_subtree_root.right.is_red = True
            if new_subtree_root.parent is None:
                self.__root = new_subtree_root