Files
pyGUI/tests/test_wafer_map_item.py
T
jack 25fa7507ce feat(map): add min/max highlighting toggle and live safeguards
- Add "Highlight Min/Max" option to ReadoutPanel showing peak rings.
- Reset to review mode and blank wafer map when switching away from map tab.
- Disable hover highlights and sensor dialog triggers during live stream.
- Lower trendPane height and add top margin headroom for tick labels.
- Add test coverage for blanking states, toggle overrides, and interactions.
2026-07-10 16:28:55 -07:00

225 lines
7.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Tests for src/pygui/backend/visualization/wafer_map_item.py."""
from unittest.mock import MagicMock
import pytest
# Use the session-scoped qapp fixture from conftest.py so Qt Property/Signal
# descriptors work properly.
pytestmark = pytest.mark.usefixtures("qapp")
def test_export_image_empty_path():
"""export_image returns False for empty/None path."""
from pygui.backend.visualization.wafer_map_item import WaferMapItem
item = WaferMapItem()
assert item.export_image("") is False
assert item.export_image(None) is False
def test_export_image_zero_size_item_fails():
"""export_image returns False when the item has no geometry to render."""
from pygui.backend.visualization.wafer_map_item import WaferMapItem
item = WaferMapItem()
assert item.export_image("/tmp/test_wafer.png") is False
def test_export_image_unwritable_path_fails(tmp_path):
"""export_image returns False when the target directory doesn't exist."""
from pygui.backend.visualization.wafer_map_item import WaferMapItem
item = WaferMapItem()
item.setWidth(100)
item.setHeight(100)
item.values = [10.0, 20.0, 30.0]
assert item.export_image(str(tmp_path / "no_such_dir" / "wafer.png")) is False
def test_thickness_properties():
"""Thickness data properties exist with correct defaults."""
from pygui.backend.visualization.wafer_map_item import WaferMapItem
item = WaferMapItem()
assert item._thickness_data == []
assert item._show_thickness is False
def test_thickness_setter_updates_data():
"""Setting thicknessData updates _thickness_data."""
from pygui.backend.visualization.wafer_map_item import WaferMapItem
item = WaferMapItem()
item._rebuild_thickness = MagicMock()
item.thicknessData = [1.0, 2.0, 3.0]
assert item._thickness_data == [1.0, 2.0, 3.0]
assert item._rebuild_thickness.called
def test_show_thickness_setter():
"""Setting showThickness updates _show_thickness."""
from pygui.backend.visualization.wafer_map_item import WaferMapItem
item = WaferMapItem()
assert item._show_thickness is False
item.showThickness = True
assert item._show_thickness is True
def test_export_image_writes_real_png_headless(tmp_path):
"""export_image must produce an actual decodable image file without a
QQuickWindow — the button was silently failing because grabToImage()
resolves asynchronously and never completes headless/immediately."""
from PySide6.QtGui import QImage
from pygui.backend.visualization.wafer_map_item import WaferMapItem
item = WaferMapItem()
item.setWidth(200)
item.setHeight(200)
item.values = [10.0, 20.0, 30.0]
out = tmp_path / "wafer.png"
assert item.export_image(str(out)) is True
assert out.exists()
loaded = QImage(str(out))
assert not loaded.isNull()
assert loaded.width() == 200
def test_export_image_includes_metrics_footer(tmp_path):
"""With sensor values loaded, the export gains a footer strip below the
map carrying the metric readouts (sensors / min / max / avg)."""
from PySide6.QtGui import QImage
from pygui.backend.visualization.wafer_map_item import WaferMapItem
item = WaferMapItem()
item.setWidth(200)
item.setHeight(200)
item.values = [10.0, 20.0, 30.0]
out = tmp_path / "wafer.png"
assert item.export_image(str(out)) is True
loaded = QImage(str(out))
assert loaded.height() > 200 # footer strip appended
# footer is painted opaque (dark bg), not transparent
assert loaded.pixelColor(5, loaded.height() - 5).alpha() == 255
def test_export_image_extra_line_grows_footer(tmp_path):
"""Live export passes an extra metrics line; the footer gains a second
row for it. Review export (no extra) keeps the single-row footer."""
from PySide6.QtGui import QImage
from pygui.backend.visualization.wafer_map_item import WaferMapItem
item = WaferMapItem()
item.setWidth(200)
item.setHeight(200)
item.values = [10.0, 20.0, 30.0]
review = tmp_path / "review.png"
live = tmp_path / "live.png"
assert item.export_image(str(review)) is True
assert item.export_image(str(live), "Frames: 42 Errors: 0") is True
h_review = QImage(str(review)).height()
h_live = QImage(str(live)).height()
assert h_review > 200 # readout footer present
assert h_live > h_review # extra live row appended
def test_export_image_highlights_hottest_and_coldest(tmp_path):
"""The exported map rings the hottest sensor in the high color and the
coldest in the low color. With no bands set every marker fill is the
in-range green, so any high/low-colored pixels must come from the rings."""
from PySide6.QtGui import QImage
from pygui.backend.visualization.wafer_map_item import WaferMapItem
item = WaferMapItem()
item.setWidth(200)
item.setHeight(200)
item.sensors = [
{"label": "1", "x": -50.0, "y": 0.0},
{"label": "2", "x": 0.0, "y": 0.0},
{"label": "3", "x": 50.0, "y": 0.0},
]
item.values = [10.0, 20.0, 30.0]
out = tmp_path / "wafer.png"
assert item.export_image(str(out)) is True
img = QImage(str(out))
found = {img.pixelColor(x, y).name()
for y in range(img.height()) for x in range(img.width())}
assert "#ef4444" in found # hottest ring (sensorHigh)
assert "#5b9df5" in found # coldest ring (sensorLow)
def test_show_extremes_toggle_gates_peak_rings(tmp_path):
"""showExtremes (Display setting) hides the hot/cold rings when off.
Same pixel probe as the highlight test: with rings off, no high/low
colored pixels should appear anywhere."""
from PySide6.QtGui import QImage
from pygui.backend.visualization.wafer_map_item import WaferMapItem
item = WaferMapItem()
assert item.showExtremes is True # rings on by default
item.setWidth(200)
item.setHeight(200)
item.sensors = [
{"label": "1", "x": -50.0, "y": 0.0},
{"label": "2", "x": 0.0, "y": 0.0},
{"label": "3", "x": 50.0, "y": 0.0},
]
item.values = [10.0, 20.0, 30.0]
item.showExtremes = False
out = tmp_path / "wafer.png"
assert item.export_image(str(out)) is True
img = QImage(str(out))
found = {img.pixelColor(x, y).name()
for y in range(img.height()) for x in range(img.width())}
assert "#ef4444" not in found
assert "#5b9df5" not in found
def test_readout_text_full_stats():
"""Export footer readout carries every READOUT stat with sensor indices.
Worked example: [10, 20, 30] → min 10 (#1), max 30 (#3), diff 20,
avg 20, σ = sqrt(200/3) ≈ 8.16, 3σ ≈ 24.49.
"""
from pygui.backend.visualization.wafer_map_item import readout_text
assert readout_text([10.0, 20.0, 30.0]) == (
"Sensors: 3 Min: 10.00°C (#1) Max: 30.00°C (#3) "
"Diff: 20.00 Avg: 20.00 σ: 8.16 3σ: 24.49"
)
def test_readout_text_empty():
from pygui.backend.visualization.wafer_map_item import readout_text
assert readout_text([]) == ""
def test_export_image_no_data_fails(tmp_path):
"""No file loaded / no stream played -> nothing meaningful to export."""
from pygui.backend.visualization.wafer_map_item import WaferMapItem
item = WaferMapItem()
item.setWidth(200)
item.setHeight(200)
out = tmp_path / "wafer.png"
assert item.export_image(str(out)) is False
assert not out.exists()