mirror of
https://github.com/rbreu/beeref.git
synced 2026-03-11 08:54:28 +00:00
372 lines
12 KiB
Python
372 lines
12 KiB
Python
import os.path
|
|
from unittest.mock import patch, MagicMock, call
|
|
|
|
from PyQt6 import QtWidgets
|
|
|
|
from beeref.actions import ActionsMixin
|
|
from beeref.actions.actions import Action
|
|
from beeref.actions.menu_structure import MENU_SEPARATOR
|
|
from beeref.utils import ActionList
|
|
|
|
|
|
class FooWidget(QtWidgets.QWidget, ActionsMixin):
|
|
settings = MagicMock()
|
|
undo_stack = MagicMock()
|
|
scene = MagicMock()
|
|
|
|
def on_foo(self):
|
|
pass
|
|
|
|
def on_bar(self):
|
|
pass
|
|
|
|
def on_action_open_recent_file(self, filename):
|
|
pass
|
|
|
|
|
|
@patch('PyQt6.QtGui.QAction.triggered')
|
|
@patch('PyQt6.QtGui.QAction.toggled')
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': ['foo']}])
|
|
@patch('beeref.actions.mixin.actions',
|
|
ActionList([Action(
|
|
id='foo',
|
|
text='&Foo',
|
|
shortcuts=['Ctrl+F'],
|
|
callback='on_foo',
|
|
)]))
|
|
@patch('beeref.config.KeyboardSettings.get_list')
|
|
def test_create_actions(kb_mock, toggle_mock, trigger_mock, qapp):
|
|
kb_mock.side_effect = lambda group, key, default: default
|
|
widget = FooWidget()
|
|
widget.build_menu_and_actions()
|
|
trigger_mock.connect.assert_called_once_with(widget.on_foo)
|
|
toggle_mock.connect.assert_not_called()
|
|
|
|
assert len(widget.actions()) == 1
|
|
qaction = widget.actions()[0]
|
|
assert qaction.text() == '&Foo'
|
|
assert qaction.shortcut() == 'Ctrl+F'
|
|
assert qaction.isEnabled() is True
|
|
from beeref.actions.mixin import actions
|
|
assert actions['foo'].qaction == qaction
|
|
kb_mock.assert_called_once_with('Actions', 'foo', ['Ctrl+F'])
|
|
|
|
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': ['foo']}])
|
|
def test_create_actions_with_shortcut_from_settings(qapp, kbsettings):
|
|
with patch('beeref.actions.mixin.actions',
|
|
ActionList([Action(
|
|
id='foo',
|
|
text='&Foo',
|
|
shortcuts=['Ctrl+F'],
|
|
callback='on_foo')])):
|
|
# Create Action inside the test function so that its
|
|
# kbsettings get created after the kbsettings fixture changes
|
|
# the file path
|
|
kbsettings.set_list('Actions', 'foo', ['Alt+O'])
|
|
widget = FooWidget()
|
|
widget.build_menu_and_actions()
|
|
qaction = widget.actions()[0]
|
|
assert qaction.shortcuts() == ['Alt+O']
|
|
|
|
|
|
@patch('PyQt6.QtGui.QAction.triggered')
|
|
@patch('PyQt6.QtGui.QAction.toggled')
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': ['foo']}])
|
|
@patch('beeref.actions.mixin.actions',
|
|
ActionList([Action(
|
|
id='foo',
|
|
text='&Foo',
|
|
checkable=True,
|
|
callback='on_foo',
|
|
)]))
|
|
def test_create_actions_checkable(toggle_mock, trigger_mock, qapp):
|
|
widget = FooWidget()
|
|
widget.build_menu_and_actions()
|
|
trigger_mock.connect.assert_not_called()
|
|
toggle_mock.connect.assert_called_once_with(widget.on_foo)
|
|
|
|
assert len(widget.actions()) == 1
|
|
qaction = widget.actions()[0]
|
|
assert qaction.text() == '&Foo'
|
|
assert qaction.isEnabled() is True
|
|
assert qaction.isChecked() is False
|
|
|
|
|
|
@patch('PyQt6.QtGui.QAction.triggered')
|
|
@patch('PyQt6.QtGui.QAction.toggled')
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': ['foo']}])
|
|
@patch('beeref.actions.mixin.actions',
|
|
ActionList([Action(
|
|
id='foo',
|
|
text='&Foo',
|
|
checkable=True,
|
|
checked=True,
|
|
callback='on_foo',
|
|
)]))
|
|
def test_create_actions_checkable_checked_true(
|
|
toggle_mock, trigger_mock, qapp):
|
|
widget = FooWidget()
|
|
widget.build_menu_and_actions()
|
|
trigger_mock.connect.assert_not_called()
|
|
toggle_mock.connect.assert_called_once_with(widget.on_foo)
|
|
|
|
assert len(widget.actions()) == 1
|
|
qaction = widget.actions()[0]
|
|
assert qaction.text() == '&Foo'
|
|
assert qaction.isEnabled() is True
|
|
assert qaction.isChecked() is True
|
|
|
|
|
|
@patch.object(FooWidget, 'on_foo')
|
|
@patch.object(FooWidget, 'settings')
|
|
@patch('PyQt6.QtGui.QAction.toggled')
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': ['foo']}])
|
|
@patch('beeref.actions.mixin.actions',
|
|
ActionList([Action(
|
|
id='foo',
|
|
text='&Foo',
|
|
checkable=True,
|
|
settings='foo/bar',
|
|
callback='on_foo',
|
|
)]))
|
|
def test_create_actions_checkable_with_settings(
|
|
toggle_mock, settings_mock, callback_mock, qapp):
|
|
widget = FooWidget()
|
|
settings_mock.value.return_value = True
|
|
widget.build_menu_and_actions()
|
|
settings_mock.value.assert_called_once_with(
|
|
'foo/bar', False, type=bool)
|
|
qaction = widget.actions()[0]
|
|
assert qaction.isChecked() is True
|
|
assert toggle_mock.connect.call_count == 2
|
|
callback_mock.assert_called_once_with(True)
|
|
|
|
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': ['foo']}])
|
|
@patch('beeref.actions.mixin.actions',
|
|
ActionList([Action(
|
|
id='foo',
|
|
text='&Foo',
|
|
callback='on_foo',
|
|
group='bar',
|
|
)]))
|
|
def test_create_actions_with_group(qapp):
|
|
widget = FooWidget()
|
|
widget.build_menu_and_actions()
|
|
assert len(widget.actions()) == 1
|
|
qaction = widget.actions()[0]
|
|
assert widget.bee_actiongroups['bar'] == [qaction]
|
|
|
|
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': ['foo']}])
|
|
@patch('beeref.actions.mixin.actions',
|
|
ActionList([Action(
|
|
id='foo',
|
|
text='&Foo',
|
|
callback='on_foo',
|
|
)]))
|
|
def test_build_menu_and_actions_with_actions(qapp):
|
|
widget = FooWidget()
|
|
with patch('PyQt6.QtWidgets.QMenu.addAction') as add_mock:
|
|
widget.build_menu_and_actions()
|
|
assert isinstance(widget.context_menu, QtWidgets.QMenu)
|
|
from beeref.actions.mixin import actions
|
|
add_mock.assert_called_once_with(actions['foo'].qaction)
|
|
|
|
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': [MENU_SEPARATOR]}])
|
|
@patch('beeref.actions.mixin.actions', ActionList([]))
|
|
def test_build_menu_and_actions_with_separator(qapp):
|
|
widget = FooWidget()
|
|
with patch('PyQt6.QtWidgets.QMenu.addSeparator') as sep_mock:
|
|
widget.build_menu_and_actions()
|
|
assert isinstance(widget.context_menu, QtWidgets.QMenu)
|
|
sep_mock.assert_called_once_with()
|
|
|
|
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': [{'menu': 'Bar', 'items': ['foo']}]}])
|
|
@patch('beeref.actions.mixin.actions',
|
|
ActionList([Action(
|
|
id='foo',
|
|
text='&Foo',
|
|
callback='on_foo',
|
|
)]))
|
|
def test_build_menu_and_actions_with_submenu(qapp):
|
|
widget = FooWidget()
|
|
with patch('PyQt6.QtWidgets.QMenu.addAction') as add_mock:
|
|
with patch('PyQt6.QtWidgets.QMenu.addMenu') as addmenu_mock:
|
|
addmenu_mock.return_value = QtWidgets.QMenu()
|
|
widget.build_menu_and_actions()
|
|
assert isinstance(widget.context_menu, QtWidgets.QMenu)
|
|
addmenu_mock.assert_called_with('Bar')
|
|
from beeref.actions.mixin import actions
|
|
add_mock.assert_called_once_with(actions['foo'].qaction)
|
|
|
|
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': ['foo']}])
|
|
@patch('beeref.actions.mixin.actions',
|
|
ActionList([
|
|
Action(
|
|
id='foo',
|
|
text='&Foo',
|
|
callback='on_foo',
|
|
group='g1',
|
|
),
|
|
Action(
|
|
id='bar',
|
|
text='&Bar',
|
|
callback='on_foo',
|
|
group='g2',
|
|
),
|
|
]))
|
|
def test_actiongroup_set_enabled(qapp):
|
|
widget = FooWidget()
|
|
widget.build_menu_and_actions()
|
|
widget.actiongroup_set_enabled('g1', True)
|
|
from beeref.actions.mixin import actions
|
|
assert actions['foo'].qaction.isEnabled() is True
|
|
assert actions['bar'].qaction.isEnabled() is False
|
|
|
|
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': ['foo']}])
|
|
@patch('beeref.actions.mixin.actions',
|
|
ActionList([Action(
|
|
id='foo',
|
|
text='&Foo',
|
|
callback='on_foo',
|
|
group='active_when_selection',
|
|
)]))
|
|
def test_build_menu_and_actions_disables_actiongroups(qapp):
|
|
widget = FooWidget()
|
|
widget.scene.has_selection.return_value = False
|
|
widget.build_menu_and_actions()
|
|
qaction = widget.actions()[0]
|
|
assert qaction.isEnabled() is False
|
|
|
|
|
|
@patch('PyQt6.QtGui.QAction.triggered')
|
|
@patch('beeref.config.KeyboardSettings.get_list')
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': '_build_recent_files'}])
|
|
@patch('beeref.actions.mixin.actions', ActionList([]))
|
|
def test_create_recent_files_more_than_10_files(
|
|
kb_mock, triggered_mock, qapp):
|
|
kb_mock.side_effect = lambda group, key, default: default
|
|
widget = FooWidget()
|
|
widget.settings.get_recent_files.return_value = [
|
|
os.path.abspath(f'{i}.bee') for i in range(15)]
|
|
|
|
widget.build_menu_and_actions()
|
|
triggered_mock.connect.assert_called()
|
|
assert len(widget.actions()) == 10
|
|
|
|
from beeref.actions.mixin import actions
|
|
qaction1 = widget.actions()[0]
|
|
assert qaction1.text() == '0.bee'
|
|
assert qaction1.shortcut() == 'Ctrl+1'
|
|
assert qaction1.isEnabled() is True
|
|
assert actions['recent_files_0'].qaction == qaction1
|
|
qaction10 = widget.actions()[9]
|
|
assert qaction10.text() == '9.bee'
|
|
assert qaction10.shortcut() == 'Ctrl+0'
|
|
assert qaction10.isEnabled() is True
|
|
assert actions['recent_files_9'].qaction == qaction10
|
|
|
|
assert kb_mock.call_count == 10
|
|
kb_mock.assert_has_calls(
|
|
[call('Actions', 'recent_files_0', ['Ctrl+1']),
|
|
call('Actions', 'recent_files_9', ['Ctrl+0'])],
|
|
any_order=True)
|
|
|
|
|
|
@patch('PyQt6.QtGui.QAction.triggered')
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': '_build_recent_files'}])
|
|
@patch('beeref.actions.mixin.actions', ActionList([]))
|
|
@patch('beeref.config.KeyboardSettings.get_list')
|
|
def test_create_recent_files_fewer_files_than_10_files(
|
|
kb_mock, triggered_mock, qapp):
|
|
kb_mock.side_effect = lambda group, key, default: default
|
|
widget = FooWidget()
|
|
widget.settings.get_recent_files.return_value = [
|
|
os.path.abspath(f'{i}.bee') for i in range(5)]
|
|
|
|
widget.build_menu_and_actions()
|
|
triggered_mock.connect.assert_called()
|
|
assert len(widget.actions()) == 5
|
|
|
|
from beeref.actions.mixin import actions
|
|
qaction1 = widget.actions()[0]
|
|
assert qaction1.text() == '0.bee'
|
|
assert qaction1.shortcut() == 'Ctrl+1'
|
|
assert qaction1.isEnabled() is True
|
|
assert actions['recent_files_0'].qaction == qaction1
|
|
qaction5 = widget.actions()[4]
|
|
assert qaction5.text() == '4.bee'
|
|
assert qaction5.shortcut() == 'Ctrl+5'
|
|
assert qaction5.isEnabled() is True
|
|
assert actions['recent_files_4'].qaction == qaction5
|
|
assert actions['recent_files_5'].qaction is None
|
|
|
|
assert kb_mock.call_count == 5
|
|
kb_mock.assert_has_calls(
|
|
[call('Actions', 'recent_files_0', ['Ctrl+1']),
|
|
call('Actions', 'recent_files_4', ['Ctrl+5'])],
|
|
any_order=True)
|
|
|
|
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': '_build_recent_files'}])
|
|
@patch('beeref.actions.mixin.actions', ActionList([]))
|
|
@patch('beeref.config.KeyboardSettings.get_list')
|
|
def test_create_recent_files_when_no_files(kb_mock, qapp):
|
|
kb_mock.side_effect = lambda group, key, default: default
|
|
widget = FooWidget()
|
|
widget.settings.get_recent_files.return_value = []
|
|
widget.build_menu_and_actions()
|
|
assert len(widget.actions()) == 0
|
|
kb_mock.assert_not_called()
|
|
|
|
|
|
@patch('PyQt6.QtGui.QAction.triggered')
|
|
@patch('beeref.actions.mixin.menu_structure',
|
|
[{'menu': 'Foo', 'items': '_build_recent_files'}])
|
|
@patch('beeref.actions.mixin.actions', ActionList([]))
|
|
def test_update_recent_files(triggered_mock, qapp):
|
|
widget = FooWidget()
|
|
widget.settings.get_recent_files.return_value = [
|
|
os.path.abspath('foo.bee')]
|
|
|
|
widget.build_menu_and_actions()
|
|
triggered_mock.connect.reset_mock()
|
|
assert len(widget.actions()) == 1
|
|
qaction1 = widget.actions()[0]
|
|
assert qaction1.text() == 'foo.bee'
|
|
|
|
widget.settings.get_recent_files.return_value = [
|
|
os.path.abspath('bar.bee')]
|
|
widget.update_menu_and_actions()
|
|
triggered_mock.connect.assert_called()
|
|
assert len(widget.actions()) == 1
|
|
qaction1 = widget.actions()[0]
|
|
assert qaction1.text() == 'bar.bee'
|
|
|
|
|
|
def test_create_menubar(qapp):
|
|
widget = FooWidget()
|
|
widget.toplevel_menus = [QtWidgets.QMenu('Foo')]
|
|
menubar = widget.create_menubar()
|
|
assert isinstance(menubar, QtWidgets.QMenuBar)
|
|
assert len(menubar.actions()) == 1
|