Many improvements and stability fixes
Lint / lint (push) Successful in 1m47s
Tests / test (3.11) (push) Successful in 57s
Tests / test (3.12) (push) Successful in 55s
Tests / test (3.13) (push) Successful in 56s
Tests / test (3.14) (push) Successful in 1m3s
Python CI / test (push) Failing after 6m1s

This commit is contained in:
2026-04-09 21:39:20 +02:00
parent f0aa005d8c
commit f96200c799
19 changed files with 953 additions and 233 deletions
+7 -4
View File
@@ -809,13 +809,14 @@ class TestExportPdf:
page = Page(layout=layout, page_number=1)
window.project.pages = [page]
window.project.export_dpi = 150
mock_file_dialog.return_value = ("/path/to/output.pdf", "")
window.gl_widget.export_pdf_async.return_value = True
window.export_pdf()
# Verify export was called
window.gl_widget.export_pdf_async.assert_called_once_with(window.project, "/path/to/output.pdf", export_dpi=300)
# Verify export was called with project's export_dpi, not a hardcoded value
window.gl_widget.export_pdf_async.assert_called_once_with(window.project, "/path/to/output.pdf", export_dpi=150)
assert "PDF export started" in window._status_message
@patch("pyPhotoAlbum.mixins.operations.file_ops.QFileDialog.getSaveFileName")
@@ -833,8 +834,10 @@ class TestExportPdf:
window.export_pdf()
# Verify .pdf was added
window.gl_widget.export_pdf_async.assert_called_once_with(window.project, "/path/to/output.pdf", export_dpi=300)
# Verify .pdf was added and project's export_dpi is used
window.gl_widget.export_pdf_async.assert_called_once_with(
window.project, "/path/to/output.pdf", export_dpi=window.project.export_dpi
)
@patch("pyPhotoAlbum.mixins.operations.file_ops.QFileDialog.getSaveFileName")
def test_export_pdf_failed_to_start(self, mock_file_dialog, qtbot):
+20 -19
View File
@@ -75,7 +75,7 @@ class TestFrameDefinition:
frame_type=FrameType.FULL,
)
assert frame.description == ""
assert frame.assets == {}
assert frame.asset_path is None
assert frame.colorizable is True
assert frame.default_thickness == 5.0
@@ -144,19 +144,20 @@ class TestFrameManager:
assert isinstance(names, list)
assert "simple_line" in names
assert "double_line" in names
assert "leafy_corners" in names
assert "geometric_corners" in names
def test_bundled_frames_exist(self, frame_manager):
"""Test that expected bundled frames exist"""
expected_frames = [
"simple_line",
"double_line",
"rounded_modern",
"geometric_corners",
"leafy_corners",
"ornate_flourish",
"victorian",
"art_nouveau",
"floral_corner",
"floral_flourish",
"ornate_corner",
"simple_corner",
"corner_decoration",
"corner_ornament",
]
for name in expected_frames:
frame = frame_manager.get_frame(name)
@@ -164,15 +165,15 @@ class TestFrameManager:
def test_modern_frames_are_full_type(self, frame_manager):
"""Test that modern frames are FULL type"""
modern_frames = ["simple_line", "double_line", "rounded_modern"]
modern_frames = ["simple_line", "double_line"]
for name in modern_frames:
frame = frame_manager.get_frame(name)
assert frame is not None
assert frame.frame_type == FrameType.FULL
def test_leafy_corners_is_corners_type(self, frame_manager):
"""Test that leafy_corners is CORNERS type"""
frame = frame_manager.get_frame("leafy_corners")
def test_geometric_corners_is_corners_type(self, frame_manager):
"""Test that geometric_corners is CORNERS type"""
frame = frame_manager.get_frame("geometric_corners")
assert frame is not None
assert frame.frame_type == FrameType.CORNERS
@@ -207,7 +208,7 @@ class TestFrameCategories:
def test_modern_category_not_empty(self, frame_manager):
"""Test MODERN category has frames"""
frames = frame_manager.get_frames_by_category(FrameCategory.MODERN)
assert len(frames) >= 3 # simple_line, double_line, rounded_modern
assert len(frames) >= 2 # simple_line, double_line
def test_vintage_category_not_empty(self, frame_manager):
"""Test VINTAGE category has frames"""
@@ -238,9 +239,9 @@ class TestFrameDescriptions:
frame = frame_manager.get_frame("simple_line")
assert frame.description != ""
def test_leafy_corners_has_description(self, frame_manager):
"""Test leafy_corners has a description"""
frame = frame_manager.get_frame("leafy_corners")
def test_floral_corner_has_description(self, frame_manager):
"""Test floral_corner has a description"""
frame = frame_manager.get_frame("floral_corner")
assert frame.description != ""
def test_all_frames_have_descriptions(self, frame_manager):
@@ -268,11 +269,11 @@ class TestFrameThickness:
def test_vintage_frames_are_thicker(self, frame_manager):
"""Test vintage frames have thicker default"""
leafy = frame_manager.get_frame("leafy_corners")
victorian = frame_manager.get_frame("victorian")
floral = frame_manager.get_frame("floral_corner")
ornate = frame_manager.get_frame("ornate_corner")
assert leafy.default_thickness >= 8.0
assert victorian.default_thickness >= 10.0
assert floral.default_thickness >= 8.0
assert ornate.default_thickness >= 8.0
def test_all_thicknesses_positive(self, frame_manager):
"""Test all frames have positive thickness"""
+152 -7
View File
@@ -110,7 +110,8 @@ class TestPageSetupDialog:
# Size editing should be disabled for covers
assert not dialog.width_spinbox.isEnabled()
assert not dialog.height_spinbox.isEnabled()
assert not dialog.set_default_checkbox.isEnabled()
assert not dialog.scope_non_manual.isEnabled()
assert not dialog.scope_all_pages.isEnabled()
def test_dialog_double_spread_width_calculation(self, qtbot):
"""Test double spread shows per-page width, not total width"""
@@ -182,7 +183,7 @@ class TestPageSetupDialog:
dialog.height_spinbox.setValue(280)
dialog.working_dpi_spinbox.setValue(150)
dialog.export_dpi_spinbox.setValue(600)
dialog.set_default_checkbox.setChecked(True)
dialog.scope_all_pages.setChecked(True)
dialog.cover_checkbox.setChecked(True)
dialog.thickness_spinbox.setValue(0.15)
dialog.bleed_spinbox.setValue(5.0)
@@ -199,7 +200,7 @@ class TestPageSetupDialog:
assert values["height_mm"] == 280
assert values["working_dpi"] == 150
assert values["export_dpi"] == 600
assert values["set_as_default"] is True
assert values["apply_scope"] == 2
def test_dialog_page_change_updates_values(self, qtbot):
"""Test changing selected page updates displayed values"""
@@ -552,7 +553,7 @@ class TestPageSetupIntegration:
"height_mm": 280,
"working_dpi": 150,
"export_dpi": 600,
"set_as_default": True,
"apply_scope": 1,
}
# Access the unwrapped function to test business logic directly
@@ -586,7 +587,7 @@ class TestPageSetupIntegration:
assert window.project.cover_bleed_mm == 5.0
assert window.project.working_dpi == 150
assert window.project.export_dpi == 600
assert window.project.page_size_mm == (200, 280) # set_as_default=True
assert window.project.page_size_mm == (200, 280) # apply_scope=1
# Check page size updated
assert window.project.pages[0].layout.size == (200, 280)
@@ -644,7 +645,7 @@ class TestPageSetupIntegration:
"height_mm": 297,
"working_dpi": 96,
"export_dpi": 300,
"set_as_default": False,
"apply_scope": 0,
}
# Get the undecorated method
@@ -716,7 +717,7 @@ class TestPageSetupIntegration:
"height_mm": 280, # New height
"working_dpi": 96,
"export_dpi": 300,
"set_as_default": False,
"apply_scope": 0,
}
from pyPhotoAlbum.mixins.operations import page_ops
@@ -731,3 +732,147 @@ class TestPageSetupIntegration:
assert window.project.pages[0].layout.base_width == 200
assert window.project.pages[0].layout.size == (400, 280) # Double width
assert window.project.pages[0].manually_sized is True
def test_set_as_default_updates_double_spread_pages(self, qtbot):
"""Test set_as_default updates existing double spread pages with doubled width"""
from PyQt6.QtWidgets import QMainWindow
from pyPhotoAlbum.mixins.base import ApplicationStateMixin
from pyPhotoAlbum.mixins.operations.page_ops import PageOperationsMixin
class TestWindow(PageOperationsMixin, ApplicationStateMixin, QMainWindow):
def __init__(self):
super().__init__()
self._project = Project(name="Test")
self._project.page_size_mm = (210, 297)
self._project.working_dpi = 96
self._project.export_dpi = 300
self._project.paper_thickness_mm = 0.1
self._project.cover_bleed_mm = 3.0
# Normal page being edited
page1 = Page(layout=PageLayout(width=210, height=297), page_number=1)
# Double spread page (not manually sized - should be updated)
page2 = Page(layout=PageLayout(width=420, height=297), page_number=2)
page2.is_double_spread = True
page2.layout.base_width = 210
page2.layout.is_facing_page = True
# Manually sized page (should NOT be updated)
page3 = Page(layout=PageLayout(width=150, height=200), page_number=3)
page3.manually_sized = True
self._project.pages = [page1, page2, page3]
self._gl_widget = Mock()
self._gl_widget._page_renderers = []
self._status_bar = Mock()
self._update_view_called = False
def _get_most_visible_page_index(self):
return 0
def update_view(self):
self._update_view_called = True
def show_status(self, message, timeout=0):
pass
window = TestWindow()
qtbot.addWidget(window)
values = {
"selected_index": 0,
"selected_page": window.project.pages[0],
"is_cover": False,
"paper_thickness_mm": 0.1,
"cover_bleed_mm": 3.0,
"width_mm": 200,
"height_mm": 280,
"working_dpi": 96,
"export_dpi": 300,
"apply_scope": 1,
}
from pyPhotoAlbum.mixins.operations import page_ops
undecorated_page_setup = page_ops.PageOperationsMixin.page_setup
while hasattr(undecorated_page_setup, "__wrapped__"):
undecorated_page_setup = undecorated_page_setup.__wrapped__
undecorated_page_setup(window, values)
# Project default updated
assert window.project.page_size_mm == (200, 280)
# Double spread page updated with doubled width
assert window.project.pages[1].layout.base_width == 200
assert window.project.pages[1].layout.size == (400, 280)
# Manually sized page NOT updated
assert window.project.pages[2].layout.size == (150, 200)
def test_apply_scope_all_pages_overrides_manual_sizing(self, qtbot):
"""Test apply_scope=2 updates all pages including manually sized ones"""
from PyQt6.QtWidgets import QMainWindow
from pyPhotoAlbum.mixins.base import ApplicationStateMixin
from pyPhotoAlbum.mixins.operations.page_ops import PageOperationsMixin
class TestWindow(PageOperationsMixin, ApplicationStateMixin, QMainWindow):
def __init__(self):
super().__init__()
self._project = Project(name="Test")
self._project.page_size_mm = (210, 297)
self._project.working_dpi = 96
self._project.export_dpi = 300
self._project.paper_thickness_mm = 0.1
self._project.cover_bleed_mm = 3.0
page1 = Page(layout=PageLayout(width=210, height=297), page_number=1)
page2 = Page(layout=PageLayout(width=420, height=297), page_number=2)
page2.is_double_spread = True
page2.layout.base_width = 210
page2.layout.is_facing_page = True
page3 = Page(layout=PageLayout(width=150, height=200), page_number=3)
page3.manually_sized = True
self._project.pages = [page1, page2, page3]
self._gl_widget = Mock()
self._gl_widget._page_renderers = []
self._status_bar = Mock()
self._update_view_called = False
def _get_most_visible_page_index(self):
return 0
def update_view(self):
self._update_view_called = True
def show_status(self, message, timeout=0):
pass
window = TestWindow()
qtbot.addWidget(window)
values = {
"selected_index": 0,
"selected_page": window.project.pages[0],
"is_cover": False,
"paper_thickness_mm": 0.1,
"cover_bleed_mm": 3.0,
"width_mm": 200,
"height_mm": 280,
"working_dpi": 96,
"export_dpi": 300,
"apply_scope": 2,
}
from pyPhotoAlbum.mixins.operations import page_ops
undecorated_page_setup = page_ops.PageOperationsMixin.page_setup
while hasattr(undecorated_page_setup, "__wrapped__"):
undecorated_page_setup = undecorated_page_setup.__wrapped__
undecorated_page_setup(window, values)
# Project default updated
assert window.project.page_size_mm == (200, 280)
# Double spread updated
assert window.project.pages[1].layout.size == (400, 280)
# Manually sized page IS updated when scope=2
assert window.project.pages[2].layout.size == (200, 280)
+11 -6
View File
@@ -53,7 +53,9 @@ class TestPageSetupDialogWithMocks:
dialog.cover_checkbox = Mock()
dialog.width_spinbox = Mock()
dialog.height_spinbox = Mock()
dialog.set_default_checkbox = Mock()
dialog.scope_non_manual = Mock()
dialog.scope_all_pages = Mock()
dialog.scope_page_only = Mock()
# Mock the update spine info method
dialog._update_spine_info = Mock()
@@ -187,8 +189,8 @@ class TestPageSetupDialogWithMocks:
dialog.export_dpi_spinbox = Mock()
dialog.export_dpi_spinbox.value.return_value = 600
dialog.set_default_checkbox = Mock()
dialog.set_default_checkbox.isChecked.return_value = True
dialog._apply_scope_group = Mock()
dialog._apply_scope_group.checkedId.return_value = 2
# Get values
values = dialog.get_values()
@@ -203,7 +205,7 @@ class TestPageSetupDialogWithMocks:
assert values["height_mm"] == 280.0
assert values["working_dpi"] == 150
assert values["export_dpi"] == 600
assert values["set_as_default"] is True
assert values["apply_scope"] == 2
def test_cover_page_width_display(self):
"""Test cover page shows full width, not base width"""
@@ -224,7 +226,9 @@ class TestPageSetupDialogWithMocks:
dialog.cover_checkbox = Mock()
dialog.width_spinbox = Mock()
dialog.height_spinbox = Mock()
dialog.set_default_checkbox = Mock()
dialog.scope_non_manual = Mock()
dialog.scope_all_pages = Mock()
dialog.scope_page_only = Mock()
dialog._update_spine_info = Mock()
# Call _on_page_changed for cover page
@@ -238,7 +242,8 @@ class TestPageSetupDialogWithMocks:
# Verify widgets were disabled for cover
dialog.width_spinbox.setEnabled.assert_called_with(False)
dialog.height_spinbox.setEnabled.assert_called_with(False)
dialog.set_default_checkbox.setEnabled.assert_called_with(False)
dialog.scope_non_manual.setEnabled.assert_called_with(False)
dialog.scope_all_pages.setEnabled.assert_called_with(False)
# Note: Additional widget state tests are covered in test_page_setup_dialog.py
# using qtbot which properly handles Qt widget initialization
+218
View File
@@ -965,6 +965,222 @@ def test_pdf_exporter_image_downsampling():
os.remove(img_path)
def test_pdf_exporter_bleed_expands_page_size():
"""Test that setting page_bleed_mm expands the PDF page dimensions"""
import pdfplumber
MM_TO_POINTS = 2.834645669
page_width_mm = 210.0
page_height_mm = 297.0
bleed_mm = 3.0
# Export WITHOUT bleed
project_no_bleed = Project("No Bleed")
project_no_bleed.page_size_mm = (page_width_mm, page_height_mm)
project_no_bleed.page_bleed_mm = 0.0
page_no_bleed = Page(page_number=1, is_double_spread=False)
project_no_bleed.add_page(page_no_bleed)
# Export WITH bleed
project_bleed = Project("With Bleed")
project_bleed.page_size_mm = (page_width_mm, page_height_mm)
project_bleed.page_bleed_mm = bleed_mm
page_bleed = Page(page_number=1, is_double_spread=False)
project_bleed.add_page(page_bleed)
with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as f1:
path_no_bleed = f1.name
with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as f2:
path_bleed = f2.name
try:
exporter_no_bleed = PDFExporter(project_no_bleed)
success, _ = exporter_no_bleed.export(path_no_bleed)
assert success
exporter_bleed = PDFExporter(project_bleed)
success, _ = exporter_bleed.export(path_bleed)
assert success
with pdfplumber.open(path_no_bleed) as pdf:
w_no_bleed = pdf.pages[0].width
h_no_bleed = pdf.pages[0].height
with pdfplumber.open(path_bleed) as pdf:
w_bleed = pdf.pages[0].width
h_bleed = pdf.pages[0].height
bleed_pt = bleed_mm * MM_TO_POINTS
expected_w = page_width_mm * MM_TO_POINTS + 2 * bleed_pt
expected_h = page_height_mm * MM_TO_POINTS + 2 * bleed_pt
assert abs(w_no_bleed - page_width_mm * MM_TO_POINTS) < 1.0, (
f"No-bleed page width mismatch: {w_no_bleed:.2f} vs {page_width_mm * MM_TO_POINTS:.2f}"
)
assert abs(w_bleed - expected_w) < 1.0, (
f"Bleed page width mismatch: {w_bleed:.2f} vs {expected_w:.2f}"
)
assert abs(h_bleed - expected_h) < 1.0, (
f"Bleed page height mismatch: {h_bleed:.2f} vs {expected_h:.2f}"
)
assert w_bleed > w_no_bleed, "Bleed page should be wider than non-bleed page"
assert h_bleed > h_no_bleed, "Bleed page should be taller than non-bleed page"
finally:
if os.path.exists(path_no_bleed):
os.remove(path_no_bleed)
if os.path.exists(path_bleed):
os.remove(path_bleed)
def test_pdf_exporter_spread_bleed_expands_and_offsets():
"""Test that double spread pages each get bleed on all 4 sides, same as single pages"""
import pdfplumber
from PIL import Image as PILImage
MM_TO_POINTS = 2.834645669
page_width_mm = 210.0
page_height_mm = 297.0
bleed_mm = 3.0
bleed_pt = bleed_mm * MM_TO_POINTS
dpi = 96
img = PILImage.new("RGB", (200, 200), color="red")
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as img_f:
img_path = img_f.name
img.save(img_path)
try:
project = Project("Spread Bleed")
project.page_size_mm = (page_width_mm, page_height_mm)
project.working_dpi = dpi
project.page_bleed_mm = bleed_mm
spread = Page(page_number=1, is_double_spread=True)
page_w_px = page_width_mm * dpi / 25.4
page_h_px = page_height_mm * dpi / 25.4
center_px = page_w_px
# Full-page element on left page (x=0 to center)
left_img = ImageData(image_path=img_path, x=0, y=0, width=page_w_px, height=page_h_px)
# Full-page element on right page (x=center to 2*center)
right_img = ImageData(image_path=img_path, x=center_px, y=0, width=page_w_px, height=page_h_px)
spread.layout.add_element(left_img)
spread.layout.add_element(right_img)
project.add_page(spread)
with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as pdf_f:
pdf_path = pdf_f.name
try:
exporter = PDFExporter(project)
success, warnings = exporter.export(pdf_path)
assert success, f"Export failed: {warnings}"
expected_page_w = page_width_mm * MM_TO_POINTS + 2 * bleed_pt
expected_page_h = page_height_mm * MM_TO_POINTS + 2 * bleed_pt
expected_img_x1 = page_width_mm * MM_TO_POINTS + bleed_pt
with pdfplumber.open(pdf_path) as pdf:
spread_pages = [pg for pg in pdf.pages if pg.images]
assert len(spread_pages) == 2, f"Expected 2 pages with images, got {len(spread_pages)}"
for pg in spread_pages:
# Page size includes bleed on all sides
assert abs(pg.width - expected_page_w) < 1.0, (
f"Page width {pg.width:.2f} != expected {expected_page_w:.2f}"
)
assert abs(pg.height - expected_page_h) < 1.0, (
f"Page height {pg.height:.2f} != expected {expected_page_h:.2f}"
)
# Image starts at bleed_pt from left (3mm inner padding)
img_obj = pg.images[0]
assert abs(img_obj["x0"] - bleed_pt) < 1.0, (
f"Image x0={img_obj['x0']:.2f} != bleed_pt={bleed_pt:.2f}"
)
# Image ends bleed_pt from right edge (3mm outer padding)
assert abs(img_obj["x1"] - expected_img_x1) < 1.0, (
f"Image x1={img_obj['x1']:.2f} != {expected_img_x1:.2f}"
)
finally:
if os.path.exists(pdf_path):
os.remove(pdf_path)
finally:
if os.path.exists(img_path):
os.remove(img_path)
def test_pdf_exporter_bleed_offsets_content():
"""Test that bleed shifts image content by bleed_pt so it appears at correct position"""
import pdfplumber
from PIL import Image as PILImage
MM_TO_POINTS = 2.834645669
page_width_mm = 210.0
page_height_mm = 297.0
bleed_mm = 3.0
bleed_pt = bleed_mm * MM_TO_POINTS
# Create a solid-color test image
test_img = PILImage.new("RGB", (200, 200), color="red")
with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as img_f:
img_path = img_f.name
test_img.save(img_path)
try:
# Place image at page position (50mm, 50mm)
element_x_mm = 50.0
element_y_mm = 50.0
element_w_mm = 40.0
element_h_mm = 40.0
dpi = 96
element_x_px = element_x_mm * dpi / 25.4
element_y_px = element_y_mm * dpi / 25.4
element_w_px = element_w_mm * dpi / 25.4
element_h_px = element_h_mm * dpi / 25.4
project = Project("Bleed Offset")
project.page_size_mm = (page_width_mm, page_height_mm)
project.working_dpi = dpi
project.page_bleed_mm = bleed_mm
page = Page(page_number=1, is_double_spread=False)
image = ImageData(image_path=img_path, x=element_x_px, y=element_y_px,
width=element_w_px, height=element_h_px)
page.layout.add_element(image)
project.add_page(page)
with tempfile.NamedTemporaryFile(suffix=".pdf", delete=False) as pdf_f:
pdf_path = pdf_f.name
try:
exporter = PDFExporter(project)
success, warnings = exporter.export(pdf_path)
assert success, f"Export failed: {warnings}"
with pdfplumber.open(pdf_path) as pdf:
pg = pdf.pages[0]
images = pg.images
assert len(images) > 0, "No images found in PDF"
img_obj = images[0]
# x0 should be element_x_pt + bleed_pt from left edge of expanded page
expected_x0 = element_x_mm * MM_TO_POINTS + bleed_pt
actual_x0 = img_obj["x0"]
assert abs(actual_x0 - expected_x0) < 2.0, (
f"Image X offset mismatch: expected {expected_x0:.2f}, got {actual_x0:.2f}"
)
finally:
if os.path.exists(pdf_path):
os.remove(pdf_path)
finally:
if os.path.exists(img_path):
os.remove(img_path)
if __name__ == "__main__":
print("Running PDF export tests...\n")
@@ -984,6 +1200,8 @@ if __name__ == "__main__":
test_pdf_exporter_varying_aspect_ratios()
test_pdf_exporter_rotated_image()
test_pdf_exporter_image_downsampling()
test_pdf_exporter_bleed_expands_page_size()
test_pdf_exporter_bleed_offsets_content()
print("\n✓ All tests passed!")
+46
View File
@@ -48,6 +48,52 @@ class TestProject:
assert project.working_dpi == 300
assert project.page_size_mm == (140, 140) # Default 14cm x 14cm square
def test_print_guide_defaults(self):
"""Test that print guide settings have correct defaults"""
project = Project()
assert project.page_bleed_mm == 0.0
assert project.page_safe_area_mm == 5.0
assert project.show_print_guides is False
def test_print_guide_serialization_roundtrip(self):
"""Test that print guide settings are serialized and deserialized correctly"""
project = Project()
project.page_bleed_mm = 3.0
project.page_safe_area_mm = 8.0
project.show_print_guides = True
data = project.serialize()
assert data["page_bleed_mm"] == 3.0
assert data["page_safe_area_mm"] == 8.0
assert data["show_print_guides"] is True
# Deserialize into a new project
restored = Project()
restored.deserialize(data)
assert restored.page_bleed_mm == 3.0
assert restored.page_safe_area_mm == 8.0
assert restored.show_print_guides is True
def test_print_guide_deserialization_defaults(self):
"""Test that missing print guide fields in old data fall back to defaults"""
project = Project()
data = project.serialize()
# Simulate old project file without these keys
del data["page_bleed_mm"]
del data["page_safe_area_mm"]
del data["show_print_guides"]
restored = Project()
restored.deserialize(data)
assert restored.page_bleed_mm == 0.0
assert restored.page_safe_area_mm == 5.0
assert restored.show_print_guides is False
def test_initialization_with_name(self):
"""Test Project initialization with custom name"""
project = Project(name="My Album")
+39
View File
@@ -27,6 +27,7 @@ class TestViewWindow(ViewOperationsMixin, QMainWindow):
self.project.snap_to_edges = True
self.project.snap_to_guides = True
self.project.show_snap_lines = True
self.project.show_print_guides = False
self.project.grid_size_mm = 10.0
self.project.snap_threshold_mm = 5.0
self._update_view_called = False
@@ -125,6 +126,44 @@ class TestZoomOperations:
assert not window._update_view_called
class TestPrintGuidesToggle:
"""Test print guides toggle operation"""
def test_toggle_print_guides_show(self, qtbot):
window = TestViewWindow()
qtbot.addWidget(window)
window.project.show_print_guides = False
window.toggle_print_guides()
assert window.project.show_print_guides is True
assert "visible" in window._status_message.lower()
assert window._update_view_called
def test_toggle_print_guides_hide(self, qtbot):
window = TestViewWindow()
qtbot.addWidget(window)
window.project.show_print_guides = True
window.toggle_print_guides()
assert window.project.show_print_guides is False
assert "hidden" in window._status_message.lower()
assert window._update_view_called
def test_toggle_print_guides_no_project(self, qtbot):
window = TestViewWindow()
qtbot.addWidget(window)
window.project = None
window.toggle_print_guides()
assert not window._update_view_called
class TestSnappingToggles:
"""Test snapping toggle operations"""