110 lines
4.0 KiB
Python
110 lines
4.0 KiB
Python
import sys
|
|
import tempfile
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
from PIL import Image, PngImagePlugin
|
|
|
|
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", include_srgb=True):
|
|
path = self.root / name
|
|
png_info = PngImagePlugin.PngInfo()
|
|
if include_srgb:
|
|
png_info.add(b"sRGB", b"\x00")
|
|
image.save(path, format="PNG", pnginfo=png_info)
|
|
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.root)
|
|
self.assertEqual([], report["errors"])
|
|
self.assertEqual(32, report["width"])
|
|
self.assertEqual(16, report["height"])
|
|
self.assertEqual("asset.png", report["path"])
|
|
|
|
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.root)
|
|
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.root)
|
|
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.root)
|
|
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.root)
|
|
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.root)
|
|
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.root)
|
|
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.root)
|
|
self.assertIn("maxBytes", self.error_text(report))
|
|
|
|
def test_rejects_missing_declared_srgb_metadata(self):
|
|
path = self.save(self.clean_image(), include_srgb=False)
|
|
report = analyze_asset(path, self.spec(), self.root)
|
|
self.assertIn("sRGB", self.error_text(report))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|