import sys import tempfile import unittest from pathlib import Path from PIL import Image SCRIPTS = Path(__file__).resolve().parents[1] / "scripts" sys.path.insert(0, str(SCRIPTS)) from asset_quality import analyze_asset class AssetQualityTests(unittest.TestCase): def setUp(self): self.directory = tempfile.TemporaryDirectory() self.addCleanup(self.directory.cleanup) self.root = Path(self.directory.name) def spec(self): return { "id": "test-button", "outputPixels": {"width": 32, "height": 16}, "alpha": {"required": True, "transparentOuterPadding": 2, "cornerMaxAlpha": 0}, "edge": { "forbidChromaResidue": True, "forbidLightFringe": True, "premultipliedAlphaCheck": True, }, "quality": {"maxBytes": 10000, "colorSpace": "sRGB"}, } def clean_image(self): image = Image.new("RGBA", (32, 16), (0, 0, 0, 0)) for y in range(2, 14): for x in range(2, 30): image.putpixel((x, y), (150, 20, 12, 255)) return image def save(self, image, name="asset.png"): path = self.root / name image.save(path, format="PNG") return path def error_text(self, report): return " ".join(report["errors"]) def test_accepts_clean_rgba_asset(self): report = analyze_asset(self.save(self.clean_image()), self.spec()) self.assertEqual([], report["errors"]) self.assertEqual(32, report["width"]) self.assertEqual(16, report["height"]) def test_accepts_indexed_png_with_real_transparency(self): indexed = self.clean_image().quantize( colors=16, method=Image.Quantize.FASTOCTREE, dither=Image.Dither.NONE, ) report = analyze_asset(self.save(indexed), self.spec()) self.assertEqual([], report["errors"]) self.assertEqual("P", report["mode"]) def test_rejects_wrong_dimensions(self): report = analyze_asset(self.save(Image.new("RGBA", (31, 16), (0, 0, 0, 0))), self.spec()) self.assertIn("dimensions", self.error_text(report)) def test_rejects_opaque_outer_padding(self): image = self.clean_image() image.putpixel((0, 0), (120, 30, 20, 255)) report = analyze_asset(self.save(image), self.spec()) self.assertIn("outer padding", self.error_text(report)) def test_rejects_visible_green_residue(self): image = self.clean_image() image.putpixel((16, 8), (0, 255, 0, 255)) report = analyze_asset(self.save(image), self.spec()) self.assertIn("chroma residue", self.error_text(report)) def test_rejects_light_partially_transparent_fringe(self): image = self.clean_image() image.putpixel((2, 8), (250, 250, 250, 128)) report = analyze_asset(self.save(image), self.spec()) self.assertIn("light fringe", self.error_text(report)) def test_rejects_hidden_rgb_in_fully_transparent_pixels(self): image = self.clean_image() image.putpixel((0, 0), (255, 255, 255, 0)) report = analyze_asset(self.save(image), self.spec()) self.assertIn("transparent RGB", self.error_text(report)) def test_rejects_file_over_max_bytes(self): spec = self.spec() spec["quality"]["maxBytes"] = 8 report = analyze_asset(self.save(self.clean_image()), spec) self.assertIn("maxBytes", self.error_text(report)) if __name__ == "__main__": unittest.main()