mirror of
https://github.com/rbreu/beeref.git
synced 2026-03-11 08:54:28 +00:00
Additional unit tests
This commit is contained in:
parent
fa9572df96
commit
d3f45f2e38
8 changed files with 247 additions and 161 deletions
|
|
@ -46,7 +46,7 @@ class BeeGraphicsView(MainControlsMixin,
|
|||
self.app = app
|
||||
self.parent = parent
|
||||
self.settings = BeeSettings()
|
||||
self.welcome_overlay = widgets.WelcomeOverlay(self)
|
||||
self.welcome_overlay = widgets.welcome_overlay.WelcomeOverlay(self)
|
||||
|
||||
self.setBackgroundBrush(
|
||||
QtGui.QBrush(QtGui.QColor(*constants.COLORS['Scene:Canvas'])))
|
||||
|
|
|
|||
|
|
@ -16,148 +16,17 @@
|
|||
import logging
|
||||
import os.path
|
||||
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
from PyQt6 import QtCore, QtWidgets
|
||||
from PyQt6.QtCore import Qt
|
||||
|
||||
from beeref import constants
|
||||
from beeref.config import logfile_name, BeeSettings
|
||||
from beeref.main_controls import MainControlsMixin
|
||||
from beeref.widgets import settings # noqa: F401
|
||||
from beeref.config import logfile_name
|
||||
from beeref.widgets import settings, welcome_overlay # noqa: F401
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RecentFilesModel(QtCore.QAbstractListModel):
|
||||
"""An entry in the 'Recent Files' list."""
|
||||
|
||||
def __init__(self, files):
|
||||
super().__init__()
|
||||
self.files = files
|
||||
|
||||
def rowCount(self, parent):
|
||||
return len(self.files)
|
||||
|
||||
def data(self, index, role):
|
||||
if role == QtCore.Qt.ItemDataRole.DisplayRole:
|
||||
return os.path.basename(self.files[index.row()])
|
||||
if role == QtCore.Qt.ItemDataRole.FontRole:
|
||||
font = QtGui.QFont()
|
||||
font.setUnderline(True)
|
||||
return font
|
||||
|
||||
|
||||
class RecentFilesView(QtWidgets.QListView):
|
||||
|
||||
def __init__(self, parent, files=None):
|
||||
super().__init__(parent)
|
||||
self.files = files or []
|
||||
self.clicked.connect(self.on_clicked)
|
||||
self.setModel(RecentFilesModel(self.files))
|
||||
self.setMouseTracking(True)
|
||||
|
||||
def on_clicked(self, index):
|
||||
self.parent().parent().open_from_file(self.files[index.row()])
|
||||
|
||||
def update_files(self, files):
|
||||
self.files = files
|
||||
self.model().files = files
|
||||
self.reset()
|
||||
|
||||
def sizeHint(self):
|
||||
size = QtCore.QSize()
|
||||
height = sum(
|
||||
(self.sizeHintForRow(i) + 2) for i in range(len(self.files)))
|
||||
width = max(self.sizeHintForColumn(i) for i in range(len(self.files)))
|
||||
size.setHeight(height)
|
||||
size.setWidth(width + 2)
|
||||
return size
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
index = self.indexAt(
|
||||
QtCore.QPoint(int(event.position().x()),
|
||||
int(event.position().y())))
|
||||
if index.isValid():
|
||||
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
else:
|
||||
self.setCursor(Qt.CursorShape.ArrowCursor)
|
||||
|
||||
super().mouseMoveEvent(event)
|
||||
|
||||
|
||||
class WelcomeOverlay(MainControlsMixin, QtWidgets.QWidget):
|
||||
"""Some basic info to be displayed when the scene is empty."""
|
||||
|
||||
txt = """<p>Paste or drop images here.</p>
|
||||
<p>Right-click for more options.</p>"""
|
||||
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self.control_target = parent
|
||||
self.setAttribute(Qt.WidgetAttribute.WA_NoSystemBackground)
|
||||
self.init_main_controls(main_window=parent.parent)
|
||||
|
||||
# Recent files
|
||||
self.files_layout = QtWidgets.QVBoxLayout()
|
||||
self.files_layout.addStretch(50)
|
||||
self.files_layout.addWidget(
|
||||
QtWidgets.QLabel('<h3>Recent Files</h3>', self))
|
||||
self.files_view = RecentFilesView(self)
|
||||
self.files_layout.addWidget(self.files_view)
|
||||
self.files_layout.addStretch(50)
|
||||
|
||||
# Help text
|
||||
self.label = QtWidgets.QLabel(self.txt, self)
|
||||
self.label.setAlignment(Qt.AlignmentFlag.AlignVCenter
|
||||
| Qt.AlignmentFlag.AlignCenter)
|
||||
self.layout = QtWidgets.QHBoxLayout()
|
||||
self.layout.addStretch(50)
|
||||
self.layout.addWidget(self.label)
|
||||
self.layout.addStretch(50)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def show(self):
|
||||
files = BeeSettings().get_recent_files(existing_only=True)
|
||||
self.files_view.update_files(files)
|
||||
if files and self.layout.indexOf(self.files_layout) < 0:
|
||||
self.layout.insertLayout(0, self.files_layout)
|
||||
super().show()
|
||||
|
||||
def disable_mouse_events(self):
|
||||
self.files_view.setAttribute(
|
||||
Qt.WidgetAttribute.WA_TransparentForMouseEvents)
|
||||
self.label.setAttribute(
|
||||
Qt.WidgetAttribute.WA_TransparentForMouseEvents)
|
||||
|
||||
def enable_mouse_events(self):
|
||||
self.files_view.setAttribute(
|
||||
Qt.WidgetAttribute.WA_TransparentForMouseEvents,
|
||||
on=False)
|
||||
self.label.setAttribute(
|
||||
Qt.WidgetAttribute.WA_TransparentForMouseEvents,
|
||||
on=False)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if self.mousePressEventMainControls(event):
|
||||
return
|
||||
super().mousePressEvent(event)
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
if self.mouseMoveEventMainControls(event):
|
||||
return
|
||||
super().mouseMoveEvent(event)
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
if self.mouseReleaseEventMainControls(event):
|
||||
return
|
||||
super().mouseReleaseEvent(event)
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if self.keyPressEventMainControls(event):
|
||||
return
|
||||
super().keyPressEvent(event)
|
||||
|
||||
|
||||
class BeeProgressDialog(QtWidgets.QProgressDialog):
|
||||
|
||||
def __init__(self, label, worker, maximum=0, parent=None):
|
||||
|
|
|
|||
156
beeref/widgets/welcome_overlay.py
Normal file
156
beeref/widgets/welcome_overlay.py
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# This file is part of BeeRef.
|
||||
#
|
||||
# BeeRef is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# BeeRef is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with BeeRef. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
import os.path
|
||||
|
||||
from PyQt6 import QtCore, QtGui, QtWidgets
|
||||
from PyQt6.QtCore import Qt
|
||||
|
||||
from beeref.config import BeeSettings
|
||||
from beeref.main_controls import MainControlsMixin
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class RecentFilesModel(QtCore.QAbstractListModel):
|
||||
"""An entry in the 'Recent Files' list."""
|
||||
|
||||
def __init__(self, files):
|
||||
super().__init__()
|
||||
self.files = files
|
||||
|
||||
def rowCount(self, parent):
|
||||
return len(self.files)
|
||||
|
||||
def data(self, index, role):
|
||||
if role == QtCore.Qt.ItemDataRole.DisplayRole:
|
||||
return os.path.basename(self.files[index.row()])
|
||||
if role == QtCore.Qt.ItemDataRole.FontRole:
|
||||
font = QtGui.QFont()
|
||||
font.setUnderline(True)
|
||||
return font
|
||||
|
||||
|
||||
class RecentFilesView(QtWidgets.QListView):
|
||||
|
||||
def __init__(self, parent, files=None):
|
||||
super().__init__(parent)
|
||||
self.files = files or []
|
||||
self.clicked.connect(self.on_clicked)
|
||||
self.setModel(RecentFilesModel(self.files))
|
||||
self.setMouseTracking(True)
|
||||
|
||||
def on_clicked(self, index):
|
||||
self.parent().parent().open_from_file(self.files[index.row()])
|
||||
|
||||
def update_files(self, files):
|
||||
self.files = files
|
||||
self.model().files = files
|
||||
self.reset()
|
||||
|
||||
def sizeHint(self):
|
||||
size = QtCore.QSize()
|
||||
height = sum(
|
||||
(self.sizeHintForRow(i) + 2) for i in range(len(self.files)))
|
||||
width = max(self.sizeHintForColumn(i) for i in range(len(self.files)))
|
||||
size.setHeight(height)
|
||||
size.setWidth(width + 2)
|
||||
return size
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
index = self.indexAt(
|
||||
QtCore.QPoint(int(event.position().x()),
|
||||
int(event.position().y())))
|
||||
if index.isValid():
|
||||
self.setCursor(Qt.CursorShape.PointingHandCursor)
|
||||
else:
|
||||
self.setCursor(Qt.CursorShape.ArrowCursor)
|
||||
|
||||
super().mouseMoveEvent(event)
|
||||
|
||||
|
||||
class WelcomeOverlay(MainControlsMixin, QtWidgets.QWidget):
|
||||
"""Some basic info to be displayed when the scene is empty."""
|
||||
|
||||
txt = """<p>Paste or drop images here.</p>
|
||||
<p>Right-click for more options.</p>"""
|
||||
|
||||
def __init__(self, parent):
|
||||
super().__init__(parent)
|
||||
self.control_target = parent
|
||||
self.setAttribute(Qt.WidgetAttribute.WA_NoSystemBackground)
|
||||
self.init_main_controls(main_window=parent.parent)
|
||||
|
||||
# Recent files
|
||||
self.files_layout = QtWidgets.QVBoxLayout()
|
||||
self.files_layout.addStretch(50)
|
||||
self.files_layout.addWidget(
|
||||
QtWidgets.QLabel('<h3>Recent Files</h3>', self))
|
||||
self.files_view = RecentFilesView(self)
|
||||
self.files_layout.addWidget(self.files_view)
|
||||
self.files_layout.addStretch(50)
|
||||
|
||||
# Help text
|
||||
self.label = QtWidgets.QLabel(self.txt, self)
|
||||
self.label.setAlignment(Qt.AlignmentFlag.AlignVCenter
|
||||
| Qt.AlignmentFlag.AlignCenter)
|
||||
self.layout = QtWidgets.QHBoxLayout()
|
||||
self.layout.addStretch(50)
|
||||
self.layout.addWidget(self.label)
|
||||
self.layout.addStretch(50)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def show(self):
|
||||
files = BeeSettings().get_recent_files(existing_only=True)
|
||||
self.files_view.update_files(files)
|
||||
if files and self.layout.indexOf(self.files_layout) < 0:
|
||||
self.layout.insertLayout(0, self.files_layout)
|
||||
super().show()
|
||||
|
||||
def disable_mouse_events(self):
|
||||
self.files_view.setAttribute(
|
||||
Qt.WidgetAttribute.WA_TransparentForMouseEvents)
|
||||
self.label.setAttribute(
|
||||
Qt.WidgetAttribute.WA_TransparentForMouseEvents)
|
||||
|
||||
def enable_mouse_events(self):
|
||||
self.files_view.setAttribute(
|
||||
Qt.WidgetAttribute.WA_TransparentForMouseEvents,
|
||||
on=False)
|
||||
self.label.setAttribute(
|
||||
Qt.WidgetAttribute.WA_TransparentForMouseEvents,
|
||||
on=False)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if self.mousePressEventMainControls(event):
|
||||
return
|
||||
super().mousePressEvent(event)
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
if self.mouseMoveEventMainControls(event):
|
||||
return
|
||||
super().mouseMoveEvent(event)
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
if self.mouseReleaseEventMainControls(event):
|
||||
return
|
||||
super().mouseReleaseEvent(event)
|
||||
|
||||
def keyPressEvent(self, event):
|
||||
if self.keyPressEventMainControls(event):
|
||||
return
|
||||
super().keyPressEvent(event)
|
||||
|
|
@ -336,6 +336,20 @@ def test_key_press_event_enter(exit_mock, key_press_mock, view):
|
|||
exit_mock.assert_called_once_with()
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QGraphicsTextItem.keyPressEvent')
|
||||
@patch('beeref.items.BeeTextItem.exit_edit_mode')
|
||||
def test_key_press_event_escape(exit_mock, key_press_mock, view):
|
||||
item = BeeTextItem('foo bar')
|
||||
view.scene.addItem(item)
|
||||
view.scene.edit_item = item
|
||||
event = MagicMock()
|
||||
event.key.return_value = Qt.Key.Key_Escape
|
||||
event.modifiers.return_value = Qt.KeyboardModifier.NoModifier
|
||||
item.keyPressEvent(event)
|
||||
key_press_mock.assert_not_called()
|
||||
exit_mock.assert_called_once_with(commit=False)
|
||||
|
||||
|
||||
def test_item_to_clipboard(qapp):
|
||||
clipboard = QtWidgets.QApplication.clipboard()
|
||||
item = BeeTextItem('foo bar')
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ def test_init_with_filename(open_file_mock, view, qapp, commandline_args):
|
|||
del view
|
||||
|
||||
|
||||
@patch('beeref.widgets.WelcomeOverlay.hide')
|
||||
@patch('beeref.widgets.welcome_overlay.WelcomeOverlay.hide')
|
||||
def test_on_scene_changed_when_items(hide_mock, view):
|
||||
item = BeePixmapItem(QtGui.QImage())
|
||||
view.scene.addItem(item)
|
||||
|
|
@ -51,7 +51,7 @@ def test_on_scene_changed_when_items(hide_mock, view):
|
|||
assert view.get_scale() == 2
|
||||
|
||||
|
||||
@patch('beeref.widgets.WelcomeOverlay.show')
|
||||
@patch('beeref.widgets.welcome_overlay.WelcomeOverlay.show')
|
||||
def test_on_scene_changed_when_no_items(show_mock, view):
|
||||
view.scale(2, 2)
|
||||
with patch('beeref.view.BeeGraphicsView.recalc_scene_rect') as r:
|
||||
|
|
@ -600,7 +600,7 @@ def test_on_action_show_titlebar_unchecked(
|
|||
create_mock.assert_called_once()
|
||||
|
||||
|
||||
@patch('beeref.widgets.WelcomeOverlay.cursor')
|
||||
@patch('beeref.widgets.welcome_overlay.WelcomeOverlay.cursor')
|
||||
def test_on_action_move_window_when_welcome_overlay(cursor_mock, view):
|
||||
cursor_mock.return_value = MagicMock(
|
||||
pos=MagicMock(return_value=QtCore.QPointF(10.0, 20.0)))
|
||||
|
|
|
|||
45
tests/widgets/test_settings.py
Normal file
45
tests/widgets/test_settings.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
from unittest.mock import patch
|
||||
|
||||
from PyQt6 import QtWidgets
|
||||
from beeref.widgets.settings import (
|
||||
ImageStorageFormatWidget,
|
||||
SettingsDialog,
|
||||
)
|
||||
|
||||
|
||||
def test_image_storage_format_selects_radiobox(settings, view):
|
||||
settings.setValue('Items/image_storage_format', 'jpg')
|
||||
widget = ImageStorageFormatWidget()
|
||||
assert widget.buttons['best'].isChecked() is False
|
||||
assert widget.buttons['png'].isChecked() is False
|
||||
assert widget.buttons['jpg'].isChecked() is True
|
||||
|
||||
|
||||
def test_image_storage_format_saves_change(settings, view):
|
||||
settings.setValue('Items/image_storage_format', 'best')
|
||||
widget = ImageStorageFormatWidget()
|
||||
widget.buttons['jpg'].setChecked(True)
|
||||
assert widget.buttons['best'].isChecked() is False
|
||||
assert widget.buttons['png'].isChecked() is False
|
||||
assert widget.buttons['jpg'].isChecked() is True
|
||||
assert settings.valueOrDefault('Items/image_storage_format', 'jpg')
|
||||
|
||||
|
||||
def test_image_storage_format_on_restore_defaults(settings, view):
|
||||
widget = ImageStorageFormatWidget()
|
||||
widget.buttons['jpg'].setChecked(True)
|
||||
settings.setValue('Items/image_storage_format', 'best')
|
||||
widget.on_restore_defaults()
|
||||
assert widget.buttons['best'].isChecked() is True
|
||||
assert widget.buttons['png'].isChecked() is False
|
||||
assert widget.buttons['jpg'].isChecked() is False
|
||||
|
||||
|
||||
@patch('PyQt6.QtWidgets.QMessageBox.question',
|
||||
return_value=QtWidgets.QMessageBox.StandardButton.Yes)
|
||||
def test_settings_dialog_on_restore_defaults(msg_mock, settings, view):
|
||||
dialog = SettingsDialog(view)
|
||||
settings.setValue('Items/image_storage_format', 'jpg')
|
||||
dialog.on_restore_defaults()
|
||||
msg_mock.assert_called_once()
|
||||
assert settings.valueOrDefault('Items/image_storage_format') == 'best'
|
||||
25
tests/widgets/test_welcome_overlay.py
Normal file
25
tests/widgets/test_welcome_overlay.py
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
from unittest.mock import MagicMock
|
||||
|
||||
from PyQt6 import QtCore
|
||||
|
||||
from beeref.widgets.welcome_overlay import RecentFilesModel
|
||||
|
||||
|
||||
def test_recent_files_model_rowcount(view):
|
||||
model = RecentFilesModel(['foo.png', 'bar.png'])
|
||||
assert model.rowCount(None) == 2
|
||||
|
||||
|
||||
def test_recent_files_model_data_diplayrole(view):
|
||||
model = RecentFilesModel(['foo.png', 'bar.png'])
|
||||
index = MagicMock()
|
||||
index.row.return_value = 1
|
||||
assert model.data(index, QtCore.Qt.ItemDataRole.DisplayRole) == 'bar.png'
|
||||
|
||||
|
||||
def test_recent_files_model_data_fontrole(view):
|
||||
model = RecentFilesModel(['foo.png', 'bar.png'])
|
||||
index = MagicMock()
|
||||
index.row.return_value = 1
|
||||
font = model.data(index, QtCore.Qt.ItemDataRole.FontRole)
|
||||
assert font.underline() is True
|
||||
|
|
@ -1,12 +1,9 @@
|
|||
from unittest.mock import MagicMock
|
||||
|
||||
from PyQt6 import QtCore, QtWidgets
|
||||
from PyQt6.QtCore import Qt
|
||||
|
||||
from beeref.config import logfile_name
|
||||
from beeref.widgets import (
|
||||
DebugLogDialog,
|
||||
RecentFilesModel,
|
||||
SceneToPixmapExporterDialog)
|
||||
|
||||
|
||||
|
|
@ -23,26 +20,6 @@ def test_debug_log_dialog(qtbot, settings, view):
|
|||
assert clipboard.text() == 'my log output'
|
||||
|
||||
|
||||
def test_recent_files_model_rowcount(view):
|
||||
model = RecentFilesModel(['foo.png', 'bar.png'])
|
||||
assert model.rowCount(None) == 2
|
||||
|
||||
|
||||
def test_recent_files_model_data_diplayrole(view):
|
||||
model = RecentFilesModel(['foo.png', 'bar.png'])
|
||||
index = MagicMock()
|
||||
index.row.return_value = 1
|
||||
assert model.data(index, QtCore.Qt.ItemDataRole.DisplayRole) == 'bar.png'
|
||||
|
||||
|
||||
def test_recent_files_model_data_fontrole(view):
|
||||
model = RecentFilesModel(['foo.png', 'bar.png'])
|
||||
index = MagicMock()
|
||||
index.row.return_value = 1
|
||||
font = model.data(index, QtCore.Qt.ItemDataRole.FontRole)
|
||||
assert font.underline() is True
|
||||
|
||||
|
||||
def test_scene_to_pixmap_exporter_dialog_sets_defaults(view):
|
||||
dlg = SceneToPixmapExporterDialog(view, QtCore.QSize(1200, 1600))
|
||||
assert dlg.width_input.value() == 1200
|
||||
Loading…
Reference in a new issue