fix tests
All checks were successful
Python CI / test (push) Successful in 1m24s
Lint / lint (push) Successful in 1m13s
Tests / test (3.11) (push) Successful in 1m37s
Tests / test (3.12) (push) Successful in 1m41s
Tests / test (3.13) (push) Successful in 1m34s
Tests / test (3.14) (push) Successful in 1m12s

This commit is contained in:
Duncan Tourolle 2025-12-13 17:32:37 +01:00
parent c1ee894e7b
commit 254a95d83c
3 changed files with 81 additions and 33 deletions

View File

@ -257,25 +257,50 @@ class TestLoadCallbacks:
class TestSaveProject:
"""Test save_project method"""
@patch("pyPhotoAlbum.mixins.operations.file_ops.save_to_zip")
def test_save_project_with_existing_path(self, mock_save, qtbot):
@patch("pyPhotoAlbum.mixins.operations.file_ops.save_to_zip_async")
@patch("pyPhotoAlbum.mixins.operations.file_ops.LoadingWidget")
def test_save_project_with_existing_path(self, mock_loading_widget, mock_save_async, qtbot):
"""Test saves to existing file path"""
window = TestFileOpsWindow()
qtbot.addWidget(window)
window.project.file_path = "/path/to/existing.ppz"
mock_save.return_value = (True, None)
# Mock loading widget
mock_loading_instance = Mock()
mock_loading_widget.return_value = mock_loading_instance
# Capture status messages
status_messages = []
original_show_status = window.show_status
def capture_status(msg, timeout=0):
status_messages.append(msg)
original_show_status(msg, timeout)
window.show_status = capture_status
# Mock save_to_zip_async to call on_complete immediately with success
def mock_save_call(project, path, on_complete=None, on_progress=None):
if on_complete:
on_complete(True, None)
return Mock() # Return mock thread
mock_save_async.side_effect = mock_save_call
window.save_project()
# Verify save was called with existing path
mock_save.assert_called_once_with(window.project, "/path/to/existing.ppz")
assert "Project saved" in window._status_message
assert mock_save_async.call_count == 1
call_args = mock_save_async.call_args
assert call_args[0][0] == window.project
assert call_args[0][1] == "/path/to/existing.ppz"
# Check that "Project saved" was shown at some point
assert any("Project saved" in msg for msg in status_messages)
assert not window.project.is_dirty() # is_dirty() is a method
@patch("pyPhotoAlbum.mixins.operations.file_ops.save_to_zip")
@patch("pyPhotoAlbum.mixins.operations.file_ops.save_to_zip_async")
@patch("pyPhotoAlbum.mixins.operations.file_ops.LoadingWidget")
@patch("pyPhotoAlbum.mixins.operations.file_ops.QFileDialog.getSaveFileName")
def test_save_project_prompts_for_path(self, mock_file_dialog, mock_save, qtbot):
def test_save_project_prompts_for_path(self, mock_file_dialog, mock_loading_widget, mock_save_async, qtbot):
"""Test prompts for path when none exists"""
window = TestFileOpsWindow()
qtbot.addWidget(window)
@ -285,18 +310,33 @@ class TestSaveProject:
# Mock dialog to return path
mock_file_dialog.return_value = ("/path/to/new.ppz", "")
mock_save.return_value = (True, None)
# Mock loading widget
mock_loading_instance = Mock()
mock_loading_widget.return_value = mock_loading_instance
# Mock save_to_zip_async to call on_complete immediately with success
def mock_save_call(project, path, on_complete=None, on_progress=None):
if on_complete:
on_complete(True, None)
return Mock() # Return mock thread
mock_save_async.side_effect = mock_save_call
window.save_project()
# Verify dialog was shown and save was called
mock_file_dialog.assert_called_once()
mock_save.assert_called_once_with(window.project, "/path/to/new.ppz")
assert mock_save_async.call_count == 1
call_args = mock_save_async.call_args
assert call_args[0][0] == window.project
assert call_args[0][1] == "/path/to/new.ppz"
assert window.project.file_path == "/path/to/new.ppz"
assert not window.project.is_dirty()
@patch("pyPhotoAlbum.mixins.operations.file_ops.save_to_zip")
@patch("pyPhotoAlbum.mixins.operations.file_ops.save_to_zip_async")
@patch("pyPhotoAlbum.mixins.operations.file_ops.QFileDialog.getSaveFileName")
def test_save_project_user_cancels(self, mock_file_dialog, mock_save, qtbot):
def test_save_project_user_cancels(self, mock_file_dialog, mock_save_async, qtbot):
"""Test returns when user cancels file dialog"""
window = TestFileOpsWindow()
qtbot.addWidget(window)
@ -307,22 +347,34 @@ class TestSaveProject:
window.save_project()
# Should not call save
mock_save.assert_not_called()
mock_save_async.assert_not_called()
@patch("pyPhotoAlbum.mixins.operations.file_ops.save_to_zip")
def test_save_project_handles_error(self, mock_save, qtbot):
@patch("pyPhotoAlbum.mixins.operations.file_ops.save_to_zip_async")
@patch("pyPhotoAlbum.mixins.operations.file_ops.LoadingWidget")
def test_save_project_handles_error(self, mock_loading_widget, mock_save_async, qtbot):
"""Test handles save errors"""
window = TestFileOpsWindow()
qtbot.addWidget(window)
window.project.file_path = "/path/to/project.ppz"
mock_save.return_value = (False, "Disk full")
# Mock loading widget
mock_loading_instance = Mock()
mock_loading_widget.return_value = mock_loading_instance
# Mock save_to_zip_async to call on_complete with error
def mock_save_call(project, path, on_complete=None, on_progress=None):
if on_complete:
on_complete(False, "Disk full")
return Mock() # Return mock thread
mock_save_async.side_effect = mock_save_call
window.save_project()
# Verify error was shown
assert "Failed to save project" in window._status_message
assert "Disk full" in window._status_message
assert "Failed to save project" in window._error_message
assert "Disk full" in window._error_message
class TestHealAssets:

View File

@ -1099,8 +1099,7 @@ class TestTextBoxData:
@patch("pyPhotoAlbum.models.glTranslatef")
@patch("pyPhotoAlbum.models.glDisable")
@patch("pyPhotoAlbum.models.glEnable")
@patch("pyPhotoAlbum.models.glBlendFunc")
@patch("pyPhotoAlbum.models.glColor4f")
@patch("pyPhotoAlbum.models.glLineStipple")
@patch("pyPhotoAlbum.models.glColor3f")
@patch("pyPhotoAlbum.models.glVertex2f")
@patch("pyPhotoAlbum.models.glBegin")
@ -1111,8 +1110,7 @@ class TestTextBoxData:
mock_glBegin,
mock_glVertex2f,
mock_glColor3f,
mock_glColor4f,
mock_glBlendFunc,
mock_glLineStipple,
mock_glEnable,
mock_glDisable,
mock_glTranslatef,
@ -1125,18 +1123,15 @@ class TestTextBoxData:
textbox.render()
# Should enable and disable blending
from pyPhotoAlbum.models import GL_BLEND, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
# Should enable and disable line stipple for dashed border
from pyPhotoAlbum.models import GL_LINE_STIPPLE
mock_glEnable.assert_called_with(GL_BLEND)
mock_glBlendFunc.assert_called_once_with(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
mock_glDisable.assert_called_with(GL_BLEND)
mock_glEnable.assert_called_with(GL_LINE_STIPPLE)
mock_glLineStipple.assert_called_once_with(2, 0xAAAA)
mock_glDisable.assert_called_with(GL_LINE_STIPPLE)
# Should draw semi-transparent yellow background
mock_glColor4f.assert_called_with(1.0, 1.0, 0.7, 0.3)
# Should draw black border
mock_glColor3f.assert_called_with(0.0, 0.0, 0.0)
# Should draw light gray dashed border
mock_glColor3f.assert_called_with(0.7, 0.7, 0.7)
# Should NOT push/pop matrix when rotation is 0
mock_glPushMatrix.assert_not_called()

View File

@ -313,9 +313,10 @@ class TestPageLayoutSnapLines:
layout.render(dpi=300, project=mock_project)
# Cyan color should be used for guides (0.0, 0.7, 0.9, 0.8)
# Cyan color should be used for guides (0.0, 0.7, 0.9)
# Check if cyan color was set (at least once)
assert mock_color4f.call_count > 0
cyan_calls = [call for call in mock_color3f.call_args_list if call[0] == (0.0, 0.7, 0.9)]
assert len(cyan_calls) > 0, "Cyan color for guides should be set"
class TestPageLayoutEdgeCases: