83 lines
3.0 KiB
Python
83 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from PIL import Image, ImageDraw
|
|
|
|
|
|
MODULE_PATH = Path(__file__).with_name("verify_visual_fidelity.py")
|
|
SPEC = importlib.util.spec_from_file_location("verify_visual_fidelity", MODULE_PATH)
|
|
assert SPEC is not None and SPEC.loader is not None
|
|
VERIFY = importlib.util.module_from_spec(SPEC)
|
|
SPEC.loader.exec_module(VERIFY)
|
|
|
|
|
|
class VisualFidelityTests(unittest.TestCase):
|
|
def _image(self, box: tuple[int, int, int, int] | None = None) -> Image.Image:
|
|
image = Image.new("RGB", (200, 100), "white")
|
|
if box is not None:
|
|
ImageDraw.Draw(image).rectangle(box, fill="black")
|
|
return image
|
|
|
|
def _contract(self) -> dict:
|
|
return {
|
|
"approved_master": {"aspect": 2.0},
|
|
"runtime_canvas": {"bounds": "auto_centered"},
|
|
"defaults": {
|
|
"analysis_width": 200,
|
|
"aspect_ratio_delta": 0.01,
|
|
"anchor_delta": 0.02,
|
|
"focal_scale_delta": 0.02,
|
|
"occupancy_delta": 0.05,
|
|
"static_region_mean_error": 0.01,
|
|
"dynamic_detection": {
|
|
"difference_threshold": 0.1,
|
|
"minimum_component_area_px": 4,
|
|
},
|
|
},
|
|
"regions": [
|
|
{
|
|
"id": "subject",
|
|
"mode": "runtime_replacement",
|
|
"search_bounds": [0.0, 0.0, 1.0, 1.0],
|
|
"runtime_bounds": [0.2, 0.2, 0.2, 0.4],
|
|
}
|
|
],
|
|
}
|
|
|
|
def _run(self, runtime_box: tuple[int, int, int, int]) -> dict:
|
|
with tempfile.TemporaryDirectory() as directory:
|
|
return VERIFY.run_verification(
|
|
self._image((40, 20, 80, 60)),
|
|
self._image(runtime_box),
|
|
self._image(),
|
|
self._contract(),
|
|
Path(directory),
|
|
Path("approved.png"),
|
|
Path("runtime.png"),
|
|
Path("static.png"),
|
|
)
|
|
|
|
def test_matching_rendered_dynamic_bounds_pass(self) -> None:
|
|
report = self._run((40, 20, 80, 60))
|
|
subject = report["checks"][1]
|
|
self.assertEqual("PASS", report["result"])
|
|
self.assertEqual([0.2, 0.2, 0.205, 0.41], subject["runtime_measurement"]["bounds"])
|
|
self.assertIn("declared_runtime_bounds_ignored", subject)
|
|
|
|
def test_copied_runtime_bounds_cannot_hide_shifted_pixels(self) -> None:
|
|
report = self._run((110, 30, 180, 80))
|
|
subject = report["checks"][1]
|
|
self.assertEqual("FAIL_VISUAL_FIDELITY", report["result"])
|
|
self.assertEqual([0.55, 0.3, 0.355, 0.51], subject["runtime_measurement"]["bounds"])
|
|
self.assertGreater(subject["anchor_delta"], subject["anchor_tolerance"])
|
|
self.assertGreater(subject["size_delta"], subject["size_tolerance"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|