feat: added reference utils to compare renderings of widgets
@ -145,7 +145,7 @@ tests:
|
|||||||
coverage_format: cobertura
|
coverage_format: cobertura
|
||||||
path: coverage.xml
|
path: coverage.xml
|
||||||
paths:
|
paths:
|
||||||
- tests/unit_tests/reference_failures/
|
- tests/reference_failures/
|
||||||
when: always
|
when: always
|
||||||
|
|
||||||
test-matrix:
|
test-matrix:
|
||||||
|
92
bec_widgets/utils/reference_utils.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from PIL import Image, ImageChops
|
||||||
|
from qtpy.QtGui import QPixmap
|
||||||
|
|
||||||
|
import bec_widgets
|
||||||
|
|
||||||
|
REFERENCE_DIR = os.path.join(
|
||||||
|
os.path.dirname(os.path.dirname(bec_widgets.__file__)), "tests/references"
|
||||||
|
)
|
||||||
|
REFERENCE_DIR_FAILURES = os.path.join(
|
||||||
|
os.path.dirname(os.path.dirname(bec_widgets.__file__)), "tests/reference_failures"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def compare_images(image1_path: str, reference_image_path: str):
|
||||||
|
"""
|
||||||
|
Load two images and compare them pixel by pixel
|
||||||
|
|
||||||
|
Args:
|
||||||
|
image1_path(str): The path to the first image
|
||||||
|
reference_image_path(str): The path to the reference image
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If the images are different
|
||||||
|
"""
|
||||||
|
image1 = Image.open(image1_path)
|
||||||
|
image2 = Image.open(reference_image_path)
|
||||||
|
if image1.size != image2.size:
|
||||||
|
raise ValueError("Image size has changed")
|
||||||
|
diff = ImageChops.difference(image1, image2)
|
||||||
|
if diff.getbbox():
|
||||||
|
# copy image1 to the reference directory to upload as artifact
|
||||||
|
os.makedirs(REFERENCE_DIR_FAILURES, exist_ok=True)
|
||||||
|
image_name = os.path.join(REFERENCE_DIR_FAILURES, os.path.basename(image1_path))
|
||||||
|
image1.save(image_name)
|
||||||
|
print(f"Image saved to {image_name}")
|
||||||
|
|
||||||
|
raise ValueError("Images are different")
|
||||||
|
|
||||||
|
|
||||||
|
def snap_and_compare(widget: any, output_directory: str, suffix: str = ""):
|
||||||
|
"""
|
||||||
|
Save a rendering of a widget and compare it to a reference image
|
||||||
|
|
||||||
|
Args:
|
||||||
|
widget(any): The widget to render
|
||||||
|
output_directory(str): The directory to save the image to
|
||||||
|
suffix(str): A suffix to append to the image name
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If the images are different
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
snap_and_compare(widget, tmpdir, suffix="started")
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not isinstance(output_directory, str):
|
||||||
|
output_directory = str(output_directory)
|
||||||
|
|
||||||
|
os_suffix = sys.platform
|
||||||
|
|
||||||
|
name = (
|
||||||
|
f"{widget.__class__.__name__}_{suffix}_{os_suffix}.png"
|
||||||
|
if suffix
|
||||||
|
else f"{widget.__class__.__name__}_{os_suffix}.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Save the widget to a pixmap
|
||||||
|
test_image_path = os.path.join(output_directory, name)
|
||||||
|
pixmap = QPixmap(widget.size())
|
||||||
|
widget.render(pixmap)
|
||||||
|
pixmap.save(test_image_path)
|
||||||
|
|
||||||
|
try:
|
||||||
|
reference_path = os.path.join(REFERENCE_DIR, f"{widget.__class__.__name__}")
|
||||||
|
reference_image_path = os.path.join(reference_path, name)
|
||||||
|
|
||||||
|
if not os.path.exists(reference_image_path):
|
||||||
|
raise ValueError(f"Reference image not found: {reference_image_path}")
|
||||||
|
|
||||||
|
compare_images(test_image_path, reference_image_path)
|
||||||
|
|
||||||
|
except ValueError:
|
||||||
|
image = Image.open(test_image_path)
|
||||||
|
os.makedirs(REFERENCE_DIR_FAILURES, exist_ok=True)
|
||||||
|
image_name = os.path.join(REFERENCE_DIR_FAILURES, name)
|
||||||
|
image.save(image_name)
|
||||||
|
print(f"Image saved to {image_name}")
|
||||||
|
raise
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
@ -1,11 +1,7 @@
|
|||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import qdarktheme
|
import qdarktheme
|
||||||
from PIL import Image, ImageChops
|
|
||||||
from qtpy.QtGui import QPixmap
|
|
||||||
|
|
||||||
|
from bec_widgets.utils.reference_utils import snap_and_compare
|
||||||
from bec_widgets.widgets.spinner.spinner import SpinnerWidget
|
from bec_widgets.widgets.spinner.spinner import SpinnerWidget
|
||||||
|
|
||||||
|
|
||||||
@ -18,75 +14,17 @@ def spinner_widget(qtbot):
|
|||||||
yield spinner
|
yield spinner
|
||||||
|
|
||||||
|
|
||||||
def save_pixmap(widget, filename):
|
|
||||||
pixmap = QPixmap(widget.size())
|
|
||||||
widget.render(pixmap)
|
|
||||||
pixmap.save(str(filename))
|
|
||||||
return pixmap
|
|
||||||
|
|
||||||
|
|
||||||
def compare_images(image1_path: str, reference_image_path: str):
|
|
||||||
image1 = Image.open(image1_path)
|
|
||||||
image2 = Image.open(reference_image_path)
|
|
||||||
if image1.size != image2.size:
|
|
||||||
raise ValueError("Image size has changed")
|
|
||||||
diff = ImageChops.difference(image1, image2)
|
|
||||||
if diff.getbbox():
|
|
||||||
# copy image1 to the reference directory to upload as artifact
|
|
||||||
output_dir = os.path.join(os.path.dirname(__file__), "reference_failures")
|
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
|
||||||
image_name = os.path.join(output_dir, os.path.basename(image1_path))
|
|
||||||
image1.save(image_name)
|
|
||||||
print(f"Image saved to {image_name}")
|
|
||||||
|
|
||||||
raise ValueError("Images are different")
|
|
||||||
|
|
||||||
|
|
||||||
def test_spinner_widget_paint_event(spinner_widget, qtbot):
|
def test_spinner_widget_paint_event(spinner_widget, qtbot):
|
||||||
spinner_widget.paintEvent(None)
|
spinner_widget.paintEvent(None)
|
||||||
|
|
||||||
|
|
||||||
def snap_and_compare(widget, tmpdir, suffix=""):
|
|
||||||
os_suffix = sys.platform
|
|
||||||
|
|
||||||
name = (
|
|
||||||
f"{widget.__class__.__name__}_{suffix}_{os_suffix}.png"
|
|
||||||
if suffix
|
|
||||||
else f"{widget.__class__.__name__}_{os_suffix}.png"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Save the widget to a pixmap
|
|
||||||
test_image_path = str(tmpdir / name)
|
|
||||||
pixmap = QPixmap(widget.size())
|
|
||||||
widget.render(pixmap)
|
|
||||||
pixmap.save(test_image_path)
|
|
||||||
|
|
||||||
try:
|
|
||||||
references_path = os.path.join(os.path.dirname(__file__), "references")
|
|
||||||
reference_image_path = os.path.join(references_path, name)
|
|
||||||
|
|
||||||
if not os.path.exists(reference_image_path):
|
|
||||||
raise ValueError(f"Reference image not found: {reference_image_path}")
|
|
||||||
|
|
||||||
compare_images(test_image_path, reference_image_path)
|
|
||||||
|
|
||||||
except ValueError:
|
|
||||||
image = Image.open(test_image_path)
|
|
||||||
output_dir = os.path.join(os.path.dirname(__file__), "reference_failures")
|
|
||||||
os.makedirs(output_dir, exist_ok=True)
|
|
||||||
image_name = os.path.join(output_dir, name)
|
|
||||||
image.save(image_name)
|
|
||||||
print(f"Image saved to {image_name}")
|
|
||||||
raise
|
|
||||||
|
|
||||||
|
|
||||||
def test_spinner_widget_rendered(spinner_widget, qtbot, tmpdir):
|
def test_spinner_widget_rendered(spinner_widget, qtbot, tmpdir):
|
||||||
spinner_widget.update()
|
spinner_widget.update()
|
||||||
qtbot.wait(200)
|
qtbot.wait(200)
|
||||||
snap_and_compare(spinner_widget, tmpdir, suffix="")
|
snap_and_compare(spinner_widget, str(tmpdir), suffix="")
|
||||||
|
|
||||||
spinner_widget._started = True
|
spinner_widget._started = True
|
||||||
spinner_widget.update()
|
spinner_widget.update()
|
||||||
qtbot.wait(200)
|
qtbot.wait(200)
|
||||||
|
|
||||||
snap_and_compare(spinner_widget, tmpdir, suffix="started")
|
snap_and_compare(spinner_widget, str(tmpdir), suffix="started")
|
||||||
|