Icon generation reported errors but returned success. Aggregate target write and verification failures into exit 1, while processing later targets. Keep rendering dependencies in the isolated build group. A synchronous open error consumed a slot. Returning that slot alone still let a deferred throw suppress an earlier callback and stall the queue. Schedule queue draining outside completed callbacks and retain the original exception. Verified real clean-source generation and structural checks for all 35 targets, plus a real write failure through the Node/uv runner. Native Windows child tests cover immediate and deferred open errors. POSIX descriptor-limit cases are explicit skips here, not passes. No signed package or native macOS acceptance is claimed.
51 lines
2.0 KiB
Python
51 lines
2.0 KiB
Python
"""Icon generation reports per-target failures without hiding later targets."""
|
|
import importlib.util
|
|
import io
|
|
import sys
|
|
from pathlib import Path
|
|
from types import ModuleType
|
|
|
|
import pytest
|
|
from PIL import Image
|
|
|
|
|
|
@pytest.mark.parametrize("failure", [None, "render", "directory", "verify"])
|
|
def test_write_status_includes_every_target(tmp_path, monkeypatch, capsys, failure):
|
|
# The renderer is build-only. This test injects failures at its byte boundary.
|
|
monkeypatch.setitem(sys.modules, "resvg_py", ModuleType("resvg_py"))
|
|
script = Path(__file__).resolve().parents[2] / "scripts" / "generate_icons.py"
|
|
spec = importlib.util.spec_from_file_location("icon_generator_under_test", script)
|
|
module = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
monkeypatch.setattr(module, "ROOT", tmp_path)
|
|
monkeypatch.setattr(module, "ensure_masters", lambda: None)
|
|
monkeypatch.setattr(sys, "argv", [str(script)])
|
|
|
|
image = io.BytesIO()
|
|
Image.new("RGBA", (2, 2), (0, 0, 0, 0)).save(image, "PNG")
|
|
good_bytes = image.getvalue()
|
|
first = "blocked/icon.png" if failure == "directory" else "first.png"
|
|
if failure == "directory":
|
|
(tmp_path / "blocked").write_text("not a directory", encoding="utf-8")
|
|
monkeypatch.setattr(module, "TARGETS", [(first, "png", "first"), ("last.png", "png", "last")])
|
|
|
|
def target_bytes(kind, target):
|
|
if target == "first":
|
|
if failure == "render":
|
|
raise RuntimeError("injected render failure")
|
|
if failure == "verify":
|
|
return b"not an image"
|
|
return good_bytes
|
|
|
|
monkeypatch.setattr(module, "target_bytes", target_bytes)
|
|
code = 0
|
|
try:
|
|
module.main()
|
|
except SystemExit as stopped:
|
|
code = stopped.code
|
|
assert bool(code) is (failure is not None)
|
|
assert (tmp_path / "last.png").read_bytes() == good_bytes
|
|
output = capsys.readouterr().out
|
|
assert "last.png: PNG (2, 2)" in output
|
|
assert ("FAILED" in output) is (failure is not None)
|