All checks were successful
Python CI / test (push) Successful in 1m20s
Lint / lint (push) Successful in 1m4s
Tests / test (3.11) (push) Successful in 1m27s
Tests / test (3.12) (push) Successful in 2m25s
Tests / test (3.13) (push) Successful in 2m52s
Tests / test (3.14) (push) Successful in 1m9s
403 lines
13 KiB
Python
403 lines
13 KiB
Python
"""
|
|
Tests for ribbon_widget module
|
|
"""
|
|
|
|
import pytest
|
|
from unittest.mock import Mock, MagicMock, patch
|
|
|
|
|
|
class TestRibbonWidgetInit:
|
|
"""Tests for RibbonWidget initialization"""
|
|
|
|
def test_init_with_custom_config(self, qtbot):
|
|
"""Test initialization with custom ribbon config"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
|
|
mock_main_window = Mock()
|
|
config = {
|
|
"File": {
|
|
"groups": [
|
|
{"name": "Project", "actions": [{"label": "New", "action": "new_project", "tooltip": "Create new"}]}
|
|
]
|
|
}
|
|
}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
assert widget.main_window == mock_main_window
|
|
assert widget.ribbon_config == config
|
|
assert widget.buttons_per_row == 4 # default
|
|
|
|
def test_init_with_custom_buttons_per_row(self, qtbot):
|
|
"""Test initialization with custom buttons_per_row"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
|
|
mock_main_window = Mock()
|
|
config = {"Test": {"groups": []}}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config, buttons_per_row=6)
|
|
qtbot.addWidget(widget)
|
|
|
|
assert widget.buttons_per_row == 6
|
|
|
|
def test_init_creates_tab_widget(self, qtbot):
|
|
"""Test that initialization creates a tab widget"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
|
|
mock_main_window = Mock()
|
|
config = {"Tab1": {"groups": []}}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
assert widget.tab_widget is not None
|
|
assert widget.tab_widget.count() == 1
|
|
|
|
|
|
class TestBuildRibbon:
|
|
"""Tests for _build_ribbon method"""
|
|
|
|
def test_build_ribbon_creates_tabs(self, qtbot):
|
|
"""Test that _build_ribbon creates tabs from config"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
|
|
mock_main_window = Mock()
|
|
config = {"File": {"groups": []}, "Edit": {"groups": []}, "View": {"groups": []}}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
assert widget.tab_widget.count() == 3
|
|
# Tab names should be present
|
|
tab_names = [widget.tab_widget.tabText(i) for i in range(widget.tab_widget.count())]
|
|
assert "File" in tab_names
|
|
assert "Edit" in tab_names
|
|
assert "View" in tab_names
|
|
|
|
def test_build_ribbon_empty_config(self, qtbot):
|
|
"""Test _build_ribbon with empty config"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
|
|
mock_main_window = Mock()
|
|
config = {}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
assert widget.tab_widget.count() == 0
|
|
|
|
|
|
class TestCreateTab:
|
|
"""Tests for _create_tab method"""
|
|
|
|
def test_create_tab_with_groups(self, qtbot):
|
|
"""Test tab creation with groups"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
|
|
mock_main_window = Mock()
|
|
config = {"Test": {"groups": [{"name": "Group1", "actions": []}, {"name": "Group2", "actions": []}]}}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
# Get the tab widget content
|
|
tab_content = widget.tab_widget.widget(0)
|
|
assert tab_content is not None
|
|
|
|
def test_create_tab_empty_groups(self, qtbot):
|
|
"""Test tab creation with no groups"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
|
|
mock_main_window = Mock()
|
|
config = {"Test": {"groups": []}}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
tab_content = widget.tab_widget.widget(0)
|
|
assert tab_content is not None
|
|
|
|
|
|
class TestCreateGroup:
|
|
"""Tests for _create_group method"""
|
|
|
|
def test_create_group_with_actions(self, qtbot):
|
|
"""Test group creation with action buttons"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
from PyQt6.QtWidgets import QPushButton
|
|
|
|
mock_main_window = Mock()
|
|
config = {
|
|
"Test": {
|
|
"groups": [
|
|
{
|
|
"name": "Actions",
|
|
"actions": [
|
|
{"label": "Action1", "action": "do_action1"},
|
|
{"label": "Action2", "action": "do_action2"},
|
|
],
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
tab_content = widget.tab_widget.widget(0)
|
|
# Find buttons in the tab
|
|
buttons = tab_content.findChildren(QPushButton)
|
|
assert len(buttons) == 2
|
|
|
|
button_labels = [btn.text() for btn in buttons]
|
|
assert "Action1" in button_labels
|
|
assert "Action2" in button_labels
|
|
|
|
def test_create_group_respects_buttons_per_row(self, qtbot):
|
|
"""Test that group respects buttons_per_row from config"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
from PyQt6.QtWidgets import QPushButton
|
|
|
|
mock_main_window = Mock()
|
|
config = {
|
|
"Test": {
|
|
"groups": [
|
|
{
|
|
"name": "Grid",
|
|
"buttons_per_row": 2,
|
|
"actions": [
|
|
{"label": "A", "action": "a"},
|
|
{"label": "B", "action": "b"},
|
|
{"label": "C", "action": "c"},
|
|
{"label": "D", "action": "d"},
|
|
],
|
|
}
|
|
]
|
|
}
|
|
}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
tab_content = widget.tab_widget.widget(0)
|
|
buttons = tab_content.findChildren(QPushButton)
|
|
assert len(buttons) == 4
|
|
|
|
|
|
class TestCreateActionButton:
|
|
"""Tests for _create_action_button method"""
|
|
|
|
def test_button_has_correct_label(self, qtbot):
|
|
"""Test that button has correct label"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
from PyQt6.QtWidgets import QPushButton
|
|
|
|
mock_main_window = Mock()
|
|
config = {"Test": {"groups": [{"name": "Test", "actions": [{"label": "My Button", "action": "my_action"}]}]}}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
buttons = widget.tab_widget.widget(0).findChildren(QPushButton)
|
|
assert len(buttons) == 1
|
|
assert buttons[0].text() == "My Button"
|
|
|
|
def test_button_has_tooltip(self, qtbot):
|
|
"""Test that button has correct tooltip"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
from PyQt6.QtWidgets import QPushButton
|
|
|
|
mock_main_window = Mock()
|
|
config = {
|
|
"Test": {
|
|
"groups": [
|
|
{"name": "Test", "actions": [{"label": "Button", "action": "action", "tooltip": "My tooltip"}]}
|
|
]
|
|
}
|
|
}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
buttons = widget.tab_widget.widget(0).findChildren(QPushButton)
|
|
assert buttons[0].toolTip() == "My tooltip"
|
|
|
|
def test_button_without_tooltip(self, qtbot):
|
|
"""Test button without tooltip configured"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
from PyQt6.QtWidgets import QPushButton
|
|
|
|
mock_main_window = Mock()
|
|
config = {"Test": {"groups": [{"name": "Test", "actions": [{"label": "Button", "action": "action"}]}]}}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
buttons = widget.tab_widget.widget(0).findChildren(QPushButton)
|
|
assert buttons[0].toolTip() == ""
|
|
|
|
def test_button_minimum_size(self, qtbot):
|
|
"""Test that button has minimum size set"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
from PyQt6.QtWidgets import QPushButton
|
|
|
|
mock_main_window = Mock()
|
|
config = {"Test": {"groups": [{"name": "Test", "actions": [{"label": "Button", "action": "action"}]}]}}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
buttons = widget.tab_widget.widget(0).findChildren(QPushButton)
|
|
assert buttons[0].minimumWidth() == 60
|
|
assert buttons[0].minimumHeight() == 40
|
|
|
|
|
|
class TestExecuteAction:
|
|
"""Tests for _execute_action method"""
|
|
|
|
def test_execute_action_calls_main_window_method(self, qtbot):
|
|
"""Test that _execute_action calls the method on main_window"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
|
|
mock_main_window = Mock()
|
|
mock_main_window.my_action = Mock()
|
|
|
|
config = {"Test": {"groups": []}}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
widget._execute_action("my_action")
|
|
|
|
mock_main_window.my_action.assert_called_once()
|
|
|
|
def test_execute_action_missing_method_prints_warning(self, qtbot, capsys):
|
|
"""Test that _execute_action prints warning for missing method"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
|
|
mock_main_window = Mock(spec=[]) # No methods
|
|
|
|
config = {"Test": {"groups": []}}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
widget._execute_action("nonexistent_action")
|
|
|
|
captured = capsys.readouterr()
|
|
assert "Warning" in captured.out
|
|
assert "nonexistent_action" in captured.out
|
|
|
|
def test_execute_action_non_callable_not_called(self, qtbot):
|
|
"""Test that non-callable attributes are not called"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
|
|
mock_main_window = Mock()
|
|
mock_main_window.not_a_method = "just a string"
|
|
|
|
config = {"Test": {"groups": []}}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
# Should not raise
|
|
widget._execute_action("not_a_method")
|
|
|
|
def test_button_click_executes_action(self, qtbot):
|
|
"""Test that clicking a button executes the action"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
from PyQt6.QtWidgets import QPushButton
|
|
|
|
mock_main_window = Mock()
|
|
mock_main_window.do_something = Mock()
|
|
|
|
config = {"Test": {"groups": [{"name": "Test", "actions": [{"label": "Do It", "action": "do_something"}]}]}}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
# Find the button and click it
|
|
buttons = widget.tab_widget.widget(0).findChildren(QPushButton)
|
|
assert len(buttons) == 1
|
|
|
|
qtbot.mouseClick(buttons[0], Qt.MouseButton.LeftButton)
|
|
|
|
mock_main_window.do_something.assert_called_once()
|
|
|
|
|
|
class TestGroupLabel:
|
|
"""Tests for group label creation"""
|
|
|
|
def test_group_has_label(self, qtbot):
|
|
"""Test that group has a label"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
from PyQt6.QtWidgets import QLabel
|
|
|
|
mock_main_window = Mock()
|
|
config = {"Test": {"groups": [{"name": "My Group", "actions": []}]}}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
tab_content = widget.tab_widget.widget(0)
|
|
labels = tab_content.findChildren(QLabel)
|
|
|
|
# Should have at least one label with the group name
|
|
label_texts = [lbl.text() for lbl in labels]
|
|
assert "My Group" in label_texts
|
|
|
|
|
|
class TestRibbonLayoutIntegration:
|
|
"""Integration tests for ribbon layout"""
|
|
|
|
def test_full_ribbon_structure(self, qtbot):
|
|
"""Test complete ribbon structure with multiple tabs and groups"""
|
|
from pyPhotoAlbum.ribbon_widget import RibbonWidget
|
|
from PyQt6.QtWidgets import QPushButton
|
|
|
|
mock_main_window = Mock()
|
|
config = {
|
|
"File": {
|
|
"groups": [
|
|
{
|
|
"name": "Project",
|
|
"actions": [
|
|
{"label": "New", "action": "new_project"},
|
|
{"label": "Open", "action": "open_project"},
|
|
{"label": "Save", "action": "save_project"},
|
|
],
|
|
},
|
|
{"name": "Export", "actions": [{"label": "Export PDF", "action": "export_pdf"}]},
|
|
]
|
|
},
|
|
"Edit": {
|
|
"groups": [
|
|
{
|
|
"name": "Clipboard",
|
|
"actions": [{"label": "Copy", "action": "copy"}, {"label": "Paste", "action": "paste"}],
|
|
}
|
|
]
|
|
},
|
|
}
|
|
|
|
widget = RibbonWidget(mock_main_window, ribbon_config=config)
|
|
qtbot.addWidget(widget)
|
|
|
|
# Check tabs
|
|
assert widget.tab_widget.count() == 2
|
|
|
|
# Check File tab has 4 buttons
|
|
file_tab = widget.tab_widget.widget(0)
|
|
file_buttons = file_tab.findChildren(QPushButton)
|
|
assert len(file_buttons) == 4
|
|
|
|
# Check Edit tab has 2 buttons
|
|
edit_tab = widget.tab_widget.widget(1)
|
|
edit_buttons = edit_tab.findChildren(QPushButton)
|
|
assert len(edit_buttons) == 2
|
|
|
|
|
|
# Import Qt for click simulation
|
|
from PyQt6.QtCore import Qt
|