"""
Tests for Command pattern implementation
"""

import pytest
from unittest.mock import Mock, MagicMock
from pyPhotoAlbum.commands import (
    AddElementCommand,
    DeleteElementCommand,
    MoveElementCommand,
    ResizeElementCommand,
    RotateElementCommand,
    AdjustImageCropCommand,
    AlignElementsCommand,
    ResizeElementsCommand,
    ChangeZOrderCommand,
    StateChangeCommand,
    CommandHistory,
    _normalize_asset_path,
)
from pyPhotoAlbum.models import ImageData, TextBoxData, PlaceholderData
from pyPhotoAlbum.page_layout import PageLayout
from pyPhotoAlbum.project import Project, Page


class TestNormalizeAssetPath:
    """Test _normalize_asset_path helper function"""

    def test_normalize_absolute_path(self):
        """Test converting absolute path to relative"""
        mock_manager = Mock()
        mock_manager.project_folder = "/project"

        result = _normalize_asset_path("/project/assets/image.jpg", mock_manager)
        assert result == "assets/image.jpg"

    def test_normalize_relative_path_unchanged(self):
        """Test relative path stays unchanged"""
        mock_manager = Mock()
        mock_manager.project_folder = "/project"

        result = _normalize_asset_path("assets/image.jpg", mock_manager)
        assert result == "assets/image.jpg"

    def test_normalize_no_asset_manager(self):
        """Test with no asset manager returns unchanged"""
        result = _normalize_asset_path("/path/to/image.jpg", None)
        assert result == "/path/to/image.jpg"

    def test_normalize_empty_path(self):
        """Test with empty path"""
        mock_manager = Mock()
        result = _normalize_asset_path("", mock_manager)
        assert result == ""


class TestAddElementCommand:
    """Test AddElementCommand"""

    def test_add_element_execute(self):
        """Test adding element to layout"""
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = AddElementCommand(layout, element)
        assert len(layout.elements) == 0

        cmd.execute()

        assert len(layout.elements) == 1
        assert element in layout.elements

    def test_add_element_undo(self):
        """Test undoing element addition"""
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = AddElementCommand(layout, element)
        cmd.execute()
        assert len(layout.elements) == 1

        cmd.undo()

        assert len(layout.elements) == 0

    def test_add_element_redo(self):
        """Test redoing element addition"""
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = AddElementCommand(layout, element)
        cmd.execute()
        cmd.undo()

        cmd.redo()

        assert len(layout.elements) == 1
        assert element in layout.elements

    def test_add_element_serialization(self):
        """Test serializing add element command"""
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = AddElementCommand(layout, element)
        cmd.execute()

        data = cmd.serialize()

        assert data["type"] == "add_element"
        assert "element" in data
        assert data["executed"] is True

    def test_add_element_with_asset_manager(self):
        """Test add element with asset manager reference"""
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        mock_asset_manager = Mock()
        mock_asset_manager.project_folder = "/project"
        mock_asset_manager.acquire_reference = Mock()

        cmd = AddElementCommand(layout, element, asset_manager=mock_asset_manager)

        # Should acquire reference on creation
        assert mock_asset_manager.acquire_reference.called


class TestDeleteElementCommand:
    """Test DeleteElementCommand"""

    def test_delete_element_execute(self):
        """Test deleting element from layout"""
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)
        layout.add_element(element)

        cmd = DeleteElementCommand(layout, element)
        cmd.execute()

        assert len(layout.elements) == 0
        assert element not in layout.elements

    def test_delete_element_undo(self):
        """Test undoing element deletion"""
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)
        layout.add_element(element)

        cmd = DeleteElementCommand(layout, element)
        cmd.execute()

        cmd.undo()

        assert len(layout.elements) == 1
        assert element in layout.elements

    def test_delete_element_serialization(self):
        """Test serializing delete element command"""
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)
        layout.add_element(element)

        cmd = DeleteElementCommand(layout, element)
        data = cmd.serialize()

        assert data["type"] == "delete_element"
        assert "element" in data


class TestMoveElementCommand:
    """Test MoveElementCommand"""

    def test_move_element_execute(self):
        """Test moving element"""
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = MoveElementCommand(element, old_position=(100, 100), new_position=(200, 200))
        cmd.execute()

        assert element.position == (200, 200)

    def test_move_element_undo(self):
        """Test undoing element move"""
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = MoveElementCommand(element, old_position=(100, 100), new_position=(200, 200))
        cmd.execute()

        cmd.undo()

        assert element.position == (100, 100)

    def test_move_element_serialization(self):
        """Test serializing move command"""
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = MoveElementCommand(element, old_position=(100, 100), new_position=(200, 200))
        data = cmd.serialize()

        assert data["type"] == "move_element"
        assert data["old_position"] == (100, 100)
        assert data["new_position"] == (200, 200)


class TestResizeElementCommand:
    """Test ResizeElementCommand"""

    def test_resize_element_execute(self):
        """Test resizing element"""
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = ResizeElementCommand(
            element, old_position=(100, 100), old_size=(200, 150), new_position=(100, 100), new_size=(300, 225)
        )
        cmd.execute()

        assert element.size == (300, 225)

    def test_resize_element_undo(self):
        """Test undoing element resize"""
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = ResizeElementCommand(
            element, old_position=(100, 100), old_size=(200, 150), new_position=(100, 100), new_size=(300, 225)
        )
        cmd.execute()

        cmd.undo()

        assert element.size == (200, 150)

    def test_resize_changes_position(self):
        """Test resize that also changes position"""
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = ResizeElementCommand(
            element, old_position=(100, 100), old_size=(200, 150), new_position=(90, 90), new_size=(220, 165)
        )
        cmd.execute()

        assert element.position == (90, 90)
        assert element.size == (220, 165)


class TestRotateElementCommand:
    """Test RotateElementCommand"""

    def test_rotate_element_execute(self):
        """Test rotating element"""
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)
        element.rotation = 0
        element.pil_rotation_90 = 0

        cmd = RotateElementCommand(element, old_rotation=0, new_rotation=90)
        cmd.execute()

        # After rotation refactoring, ImageData keeps rotation at 0 and uses pil_rotation_90
        assert element.rotation == 0
        assert element.pil_rotation_90 == 1  # 90 degrees = 1 rotation
        # Position and size should be swapped for 90 degree rotation
        assert element.size == (150, 200)  # width and height swapped

    def test_rotate_element_undo(self):
        """Test undoing element rotation"""
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)
        element.rotation = 0
        element.pil_rotation_90 = 0
        original_size = element.size
        original_position = element.position

        cmd = RotateElementCommand(element, old_rotation=0, new_rotation=90)
        cmd.execute()

        cmd.undo()

        assert element.rotation == 0
        assert element.pil_rotation_90 == 0
        assert element.size == original_size
        assert element.position == original_position

    def test_rotate_element_serialization(self):
        """Test serializing rotate command"""
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = RotateElementCommand(element, old_rotation=0, new_rotation=45)
        data = cmd.serialize()

        assert data["type"] == "rotate_element"
        assert data["old_rotation"] == 0
        assert data["new_rotation"] == 45


class TestAdjustImageCropCommand:
    """Test AdjustImageCropCommand"""

    def test_adjust_crop_execute(self):
        """Test adjusting image crop"""
        element = ImageData(
            image_path="/test.jpg",
            x=100,
            y=100,
            width=200,
            height=150,
            crop_info={"x": 0.0, "y": 0.0, "width": 1.0, "height": 1.0},
        )

        new_crop = {"x": 0.1, "y": 0.1, "width": 0.8, "height": 0.8}
        cmd = AdjustImageCropCommand(element, old_crop_info=element.crop_info.copy(), new_crop_info=new_crop)
        cmd.execute()

        assert element.crop_info == new_crop

    def test_adjust_crop_undo(self):
        """Test undoing crop adjustment"""
        old_crop = {"x": 0.0, "y": 0.0, "width": 1.0, "height": 1.0}
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150, crop_info=old_crop.copy())

        new_crop = {"x": 0.1, "y": 0.1, "width": 0.8, "height": 0.8}
        cmd = AdjustImageCropCommand(element, old_crop_info=old_crop, new_crop_info=new_crop)
        cmd.execute()

        cmd.undo()

        assert element.crop_info == old_crop


class TestAlignElementsCommand:
    """Test AlignElementsCommand"""

    def test_align_elements_execute(self):
        """Test aligning elements"""
        element1 = ImageData(image_path="/test1.jpg", x=100, y=100, width=100, height=100)
        element2 = ImageData(image_path="/test2.jpg", x=200, y=150, width=100, height=100)

        # Set new positions before creating command
        element2.position = (100, 150)  # Align left

        # Command expects list of (element, old_position) tuples
        changes = [(element1, (100, 100)), (element2, (200, 150))]

        cmd = AlignElementsCommand(changes)
        cmd.execute()

        # Execute does nothing (positions already set), check they remain
        assert element1.position == (100, 100)
        assert element2.position == (100, 150)

    def test_align_elements_undo(self):
        """Test undoing alignment"""
        element1 = ImageData(image_path="/test1.jpg", x=100, y=100, width=100, height=100)
        element2 = ImageData(image_path="/test2.jpg", x=200, y=150, width=100, height=100)

        # Set new positions before creating command
        element2.position = (100, 150)  # Align left

        # Command expects list of (element, old_position) tuples
        changes = [(element1, (100, 100)), (element2, (200, 150))]

        cmd = AlignElementsCommand(changes)
        cmd.execute()

        cmd.undo()

        # Should restore old positions
        assert element1.position == (100, 100)
        assert element2.position == (200, 150)


class TestResizeElementsCommand:
    """Test ResizeElementsCommand"""

    def test_resize_elements_execute(self):
        """Test resizing multiple elements"""
        element1 = ImageData(image_path="/test1.jpg", x=100, y=100, width=100, height=100)
        element2 = ImageData(image_path="/test2.jpg", x=200, y=200, width=150, height=150)

        # Set new sizes before creating command
        element1.size = (200, 200)
        element2.size = (300, 300)

        # Command expects list of (element, old_position, old_size) tuples
        changes = [(element1, (100, 100), (100, 100)), (element2, (200, 200), (150, 150))]

        cmd = ResizeElementsCommand(changes)
        cmd.execute()

        # Execute does nothing (sizes already set), check they remain
        assert element1.size == (200, 200)
        assert element2.size == (300, 300)

    def test_resize_elements_undo(self):
        """Test undoing multiple element resize"""
        element1 = ImageData(image_path="/test1.jpg", x=100, y=100, width=100, height=100)
        element2 = ImageData(image_path="/test2.jpg", x=200, y=200, width=150, height=150)

        # Set new sizes before creating command
        element1.size = (200, 200)
        element2.size = (300, 300)

        # Command expects list of (element, old_position, old_size) tuples
        changes = [(element1, (100, 100), (100, 100)), (element2, (200, 200), (150, 150))]

        cmd = ResizeElementsCommand(changes)
        cmd.execute()

        cmd.undo()

        # Should restore old sizes
        assert element1.size == (100, 100)
        assert element2.size == (150, 150)


class TestChangeZOrderCommand:
    """Test ChangeZOrderCommand"""

    def test_change_zorder_execute(self):
        """Test changing z-order"""
        layout = PageLayout(width=210, height=297)
        element1 = ImageData(image_path="/test1.jpg", x=100, y=100, width=100, height=100)
        element2 = ImageData(image_path="/test2.jpg", x=120, y=120, width=100, height=100)

        layout.add_element(element1)
        layout.add_element(element2)

        # Move element1 to front (swap order)
        cmd = ChangeZOrderCommand(layout, element1, 0, 1)
        cmd.execute()

        assert layout.elements[1] == element1

    def test_change_zorder_undo(self):
        """Test undoing z-order change"""
        layout = PageLayout(width=210, height=297)
        element1 = ImageData(image_path="/test1.jpg", x=100, y=100, width=100, height=100)
        element2 = ImageData(image_path="/test2.jpg", x=120, y=120, width=100, height=100)

        layout.add_element(element1)
        layout.add_element(element2)

        cmd = ChangeZOrderCommand(layout, element1, 0, 1)
        cmd.execute()

        cmd.undo()

        assert layout.elements[0] == element1


class TestStateChangeCommand:
    """Test StateChangeCommand for generic state changes"""

    def test_state_change_undo(self):
        """Test undoing state change"""
        element = TextBoxData(text_content="Old Text", x=100, y=100, width=200, height=100)

        # Define restore function
        def restore_state(state):
            element.text_content = state["text_content"]

        old_state = {"text_content": "Old Text"}
        new_state = {"text_content": "New Text"}

        # Apply new state first
        element.text_content = "New Text"

        cmd = StateChangeCommand(
            description="Change text", restore_func=restore_state, before_state=old_state, after_state=new_state
        )

        # Undo should restore old state
        cmd.undo()
        assert element.text_content == "Old Text"

    def test_state_change_redo(self):
        """Test redoing state change"""
        element = TextBoxData(text_content="Old Text", x=100, y=100, width=200, height=100)

        # Define restore function
        def restore_state(state):
            element.text_content = state["text_content"]

        old_state = {"text_content": "Old Text"}
        new_state = {"text_content": "New Text"}

        # Apply new state first
        element.text_content = "New Text"

        cmd = StateChangeCommand(
            description="Change text", restore_func=restore_state, before_state=old_state, after_state=new_state
        )

        # Undo then redo
        cmd.undo()
        assert element.text_content == "Old Text"

        cmd.redo()
        assert element.text_content == "New Text"

    def test_state_change_serialization(self):
        """Test serializing state change command"""

        def restore_func(state):
            pass

        cmd = StateChangeCommand(
            description="Test operation",
            restore_func=restore_func,
            before_state={"test": "before"},
            after_state={"test": "after"},
        )

        data = cmd.serialize()

        assert data["type"] == "state_change"
        assert data["description"] == "Test operation"


class TestCommandHistory:
    """Test CommandHistory for undo/redo management"""

    def test_history_execute_command(self):
        """Test executing command through history"""
        history = CommandHistory()
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = AddElementCommand(layout, element)
        history.execute(cmd)

        assert len(layout.elements) == 1
        assert history.can_undo()
        assert not history.can_redo()

    def test_history_undo(self):
        """Test undo through history"""
        history = CommandHistory()
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = AddElementCommand(layout, element)
        history.execute(cmd)

        history.undo()

        assert len(layout.elements) == 0
        assert not history.can_undo()
        assert history.can_redo()

    def test_history_redo(self):
        """Test redo through history"""
        history = CommandHistory()
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = AddElementCommand(layout, element)
        history.execute(cmd)
        history.undo()

        history.redo()

        assert len(layout.elements) == 1
        assert history.can_undo()
        assert not history.can_redo()

    def test_history_multiple_commands(self):
        """Test history with multiple commands"""
        history = CommandHistory()
        layout = PageLayout(width=210, height=297)

        element1 = ImageData(image_path="/test1.jpg", x=100, y=100, width=100, height=100)
        element2 = ImageData(image_path="/test2.jpg", x=200, y=200, width=100, height=100)

        history.execute(AddElementCommand(layout, element1))
        history.execute(AddElementCommand(layout, element2))

        assert len(layout.elements) == 2

        history.undo()
        assert len(layout.elements) == 1

        history.undo()
        assert len(layout.elements) == 0

    def test_history_clears_redo_on_new_command(self):
        """Test that new command clears redo stack"""
        history = CommandHistory()
        layout = PageLayout(width=210, height=297)

        element1 = ImageData(image_path="/test1.jpg", x=100, y=100, width=100, height=100)
        element2 = ImageData(image_path="/test2.jpg", x=200, y=200, width=100, height=100)

        history.execute(AddElementCommand(layout, element1))
        history.undo()

        assert history.can_redo()

        # Execute new command should clear redo stack
        history.execute(AddElementCommand(layout, element2))

        assert not history.can_redo()

    def test_history_clear(self):
        """Test clearing history"""
        history = CommandHistory()
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        history.execute(AddElementCommand(layout, element))

        history.clear()

        assert not history.can_undo()
        assert not history.can_redo()

    def test_history_max_size(self):
        """Test history respects max size limit"""
        history = CommandHistory(max_history=3)
        layout = PageLayout(width=210, height=297)

        for i in range(5):
            element = ImageData(image_path=f"/test{i}.jpg", x=i * 10, y=i * 10, width=100, height=100)
            history.execute(AddElementCommand(layout, element))

        # Should only have 3 commands in history (max_history)
        undo_count = 0
        while history.can_undo():
            history.undo()
            undo_count += 1

        assert undo_count == 3

    def test_history_serialize_deserialize_add_element(self):
        """Test serializing and deserializing history with AddElementCommand"""
        history = CommandHistory()
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd = AddElementCommand(layout, element)
        history.execute(cmd)

        # Serialize
        data = history.serialize()
        assert len(data["undo_stack"]) == 1
        assert data["undo_stack"][0]["type"] == "add_element"

        # Create mock project for deserialization
        mock_project = Mock()
        mock_project.pages = [Mock(layout=layout)]

        # Deserialize
        new_history = CommandHistory()
        new_history.deserialize(data, mock_project)

        assert len(new_history.undo_stack) == 1
        assert len(new_history.redo_stack) == 0

    def test_history_serialize_deserialize_all_command_types(self):
        """Test serializing and deserializing all command types through history"""
        history = CommandHistory()
        layout = PageLayout(width=210, height=297)

        # Create elements and add them to layout first
        img = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)
        txt = TextBoxData(text_content="Test", x=50, y=50, width=100, height=50)
        img2 = ImageData(image_path="/test2.jpg", x=200, y=200, width=100, height=100)

        # Build commands - serialize each type without executing them
        # (we only care about serialization/deserialization, not execution)
        cmd1 = AddElementCommand(layout, img)
        cmd1.serialize()  # Ensure it can serialize

        cmd2 = DeleteElementCommand(layout, txt)
        cmd2.serialize()

        cmd3 = MoveElementCommand(img, (100, 100), (150, 150))
        cmd3.serialize()

        cmd4 = ResizeElementCommand(img, (100, 100), (200, 150), (120, 120), (180, 130))
        cmd4.serialize()

        cmd5 = RotateElementCommand(img, 0, 90)
        cmd5.serialize()

        cmd6 = AdjustImageCropCommand(img, (0, 0, 1, 1), (0.1, 0.1, 0.9, 0.9))
        cmd6.serialize()

        cmd7 = AlignElementsCommand([(img, (100, 100))])
        cmd7.serialize()

        cmd8 = ResizeElementsCommand([(img, (100, 100), (200, 150))])
        cmd8.serialize()

        layout.add_element(img2)
        cmd9 = ChangeZOrderCommand(layout, img2, 0, 0)
        cmd9.serialize()

        # Manually build serialized history data
        data = {
            "undo_stack": [
                cmd1.serialize(),
                cmd2.serialize(),
                cmd3.serialize(),
                cmd4.serialize(),
                cmd5.serialize(),
                cmd6.serialize(),
                cmd7.serialize(),
                cmd8.serialize(),
                cmd9.serialize(),
            ],
            "redo_stack": [],
            "max_history": 100,
        }

        # Create mock project
        mock_project = Mock()
        mock_project.pages = [Mock(layout=layout)]

        # Deserialize
        new_history = CommandHistory()
        new_history.deserialize(data, mock_project)

        assert len(new_history.undo_stack) == 9
        assert new_history.undo_stack[0].__class__.__name__ == "AddElementCommand"
        assert new_history.undo_stack[1].__class__.__name__ == "DeleteElementCommand"
        assert new_history.undo_stack[2].__class__.__name__ == "MoveElementCommand"
        assert new_history.undo_stack[3].__class__.__name__ == "ResizeElementCommand"
        assert new_history.undo_stack[4].__class__.__name__ == "RotateElementCommand"
        assert new_history.undo_stack[5].__class__.__name__ == "AdjustImageCropCommand"
        assert new_history.undo_stack[6].__class__.__name__ == "AlignElementsCommand"
        assert new_history.undo_stack[7].__class__.__name__ == "ResizeElementsCommand"
        assert new_history.undo_stack[8].__class__.__name__ == "ChangeZOrderCommand"

    def test_history_deserialize_unknown_command_type(self):
        """Test deserializing unknown command type returns None and continues"""
        history = CommandHistory()
        mock_project = Mock()
        mock_project.pages = []

        data = {
            "undo_stack": [
                {"type": "unknown_command", "data": "test"},
                {"type": "add_element", "element": ImageData().serialize(), "executed": True},
            ],
            "redo_stack": [],
            "max_history": 100,
        }

        # Should not raise exception, just skip unknown command
        history.deserialize(data, mock_project)

        # Should only have the valid command
        assert len(history.undo_stack) == 1
        assert history.undo_stack[0].__class__.__name__ == "AddElementCommand"

    def test_history_deserialize_malformed_command(self):
        """Test deserializing malformed command handles exception gracefully"""
        history = CommandHistory()
        mock_project = Mock()

        data = {
            "undo_stack": [
                {"type": "add_element"},  # Missing required 'element' field
                {
                    "type": "move_element",
                    "element": ImageData().serialize(),
                    "old_position": (0, 0),
                    "new_position": (10, 10),
                },
            ],
            "redo_stack": [],
            "max_history": 100,
        }

        # Should not raise exception, just skip malformed command
        history.deserialize(data, mock_project)

        # Should only have the valid command
        assert len(history.undo_stack) == 1
        assert history.undo_stack[0].__class__.__name__ == "MoveElementCommand"

    def test_history_serialize_deserialize_with_redo_stack(self):
        """Test serializing and deserializing with items in redo stack"""
        history = CommandHistory()
        layout = PageLayout(width=210, height=297)
        element = ImageData(image_path="/test.jpg", x=100, y=100, width=200, height=150)

        cmd1 = AddElementCommand(layout, element)
        cmd2 = MoveElementCommand(element, (100, 100), (150, 150))

        history.execute(cmd1)
        history.execute(cmd2)
        history.undo()  # Move cmd2 to redo stack

        # Serialize
        data = history.serialize()
        assert len(data["undo_stack"]) == 1
        assert len(data["redo_stack"]) == 1

        # Deserialize
        mock_project = Mock()
        mock_project.pages = []
        new_history = CommandHistory()
        new_history.deserialize(data, mock_project)

        assert len(new_history.undo_stack) == 1
        assert len(new_history.redo_stack) == 1
