tests/test_brand_marks.py
Rama master · réplica de lectura del repositorio original.
"""随仓库分发的实体标识:收录判据与运行时回退(ADR-0026)。
这里守两件事。一是**收进来的东西必须是可以收的**:ADR-0026 那五条判据逐条检查,越界
的不是调高上限而是不收。二是**收进来的东西必须真的被用上**:取图和「这个厂牌有没有图」
两处判据必须同时认得内置资源,只改一处的后果不是报错,是页面安静地少显示一批图。
"""
import hashlib
import json
import pathlib
import subprocess
import sys
import tempfile
import unittest
import peach
from peach import brand_marks
from peach.previews import LOGO_VARIANTS, PreviewService
REPO = pathlib.Path(peach.__file__).resolve().parents[2]
class ManifestTests(unittest.TestCase):
"""清单与目录内容必须互为真相,谁也不能单方面漂移。"""
@classmethod
def setUpClass(cls):
cls.marks = brand_marks.manifest()["marks"]
def test_every_mark_has_a_source_url(self):
"""判据 1。没有来源证据的不收,不靠文件名推断归属。"""
missing = [row["file"] for row in self.marks if not row.get("source_url")]
self.assertEqual([], missing)
def test_variants_are_mark_shaped(self):
"""判据 3。作品封面、剧照不是标识;变体只有 icon、logo 和裸文件三种。"""
allowed = set(LOGO_VARIANTS) | {""}
unexpected = sorted({row.get("variant", "") for row in self.marks} - allowed)
self.assertEqual([], unexpected)
def test_each_file_within_budget(self):
"""判据 4。超过 256 KB 的多半不是小图标。"""
oversize = [(row["file"], row["bytes"]) for row in self.marks
if row["bytes"] > brand_marks.MAX_FILE_BYTES]
self.assertEqual([], oversize)
def test_total_within_budget(self):
"""判据 5。越过上限说明混进了别的东西,不是把上限调高。"""
total = sum(row["bytes"] for row in self.marks)
self.assertLessEqual(total, brand_marks.MAX_TOTAL_BYTES)
def test_manifest_and_directory_agree(self):
"""清单登记的和目录里的必须一一对应,两边都不许有对方没有的。"""
listed = {row["file"] for row in self.marks}
on_disk = {path.name for path in brand_marks.STUDIOS_DIR.iterdir()
if path.is_file()}
self.assertEqual(listed, on_disk)
def test_bytes_match_recorded_digest(self):
"""摘要对不上说明字节被改过——`.gitattributes` 的换行改写就是一种改法。"""
wrong = []
for row in self.marks:
data = (brand_marks.STUDIOS_DIR / row["file"]).read_bytes()
if hashlib.sha256(data).hexdigest() != row["sha256"] or len(data) != row["bytes"]:
wrong.append(row["file"])
self.assertEqual([], wrong)
def test_extensions_are_resolvable(self):
"""认不出扩展名的文件运行时会以 octet-stream 发出去,浏览器不显示。"""
unknown = [row["file"] for row in self.marks
if pathlib.Path(row["file"]).suffix.lower()
not in brand_marks.CONTENT_TYPES]
self.assertEqual([], unknown)
def test_no_person_marks(self):
"""判据 2。自然人肖像不进仓库,`avatars/` 那套命名不该出现在这里。"""
person = [row["file"] for row in self.marks
if row["file"].startswith(("performer-", "creator-"))]
self.assertEqual([], person)
def test_browser_catalog_contains_original_identifiers_with_sources_and_matching_bytes(self):
from peach.browser_icons import catalog, ROOT
icons = catalog()
supported = {'firefox','zen','chrome','aside','edge','brave','vivaldi','opera','opera-gx',
'115','qq','360chrome','360chromex','360se','sogou','2345','maxthon','chromium','safari'}
self.assertLessEqual(supported, icons.keys())
listed = set()
for key, row in icons.items():
self.assertTrue(row['source_url'].startswith('https://'), key)
self.assertEqual(pathlib.Path(row['file']).name, row['file'])
body = (ROOT / row['file']).read_bytes()
self.assertLessEqual(len(body), brand_marks.MAX_FILE_BYTES)
self.assertEqual(len(body), row['bytes'])
self.assertEqual(hashlib.sha256(body).hexdigest(), row['sha256'])
listed.add(row['file'])
self.assertEqual(listed, {path.name for path in ROOT.iterdir() if path.name != 'manifest.json'})
self.assertLessEqual(sum((ROOT / name).stat().st_size for name in listed), brand_marks.MAX_TOTAL_BYTES)
class LookupTests(unittest.TestCase):
"""内置资源要被找得到,但不能盖住用户自己那份。"""
def test_find_matches_cache_stem(self):
"""缓存名去掉 `.img` 就该命中内置文件,两边命名规则同源。"""
sample = brand_marks.manifest()["marks"][0]
stem = pathlib.Path(sample["file"]).stem
self.assertEqual(brand_marks.STUDIOS_DIR / sample["file"],
brand_marks.find(stem))
def test_find_is_case_insensitive(self):
sample = brand_marks.manifest()["marks"][0]
stem = pathlib.Path(sample["file"]).stem
self.assertIsNotNone(brand_marks.find(stem.upper()))
self.assertIsNotNone(brand_marks.find(stem.lower()))
def test_unknown_stem_is_none(self):
self.assertIsNone(brand_marks.find("no-such-studio-4f2a"))
self.assertIsNone(brand_marks.find(""))
def test_installed_stems_drop_variant_suffix(self):
"""变体后缀要剥掉,否则 `X.icon` 会被当成另一个厂牌,页面判 X 没有图。"""
stems = brand_marks.installed_stems(LOGO_VARIANTS)
self.assertTrue(stems)
for variant in LOGO_VARIANTS:
self.assertFalse([stem for stem in stems if stem.endswith(f".{variant}")])
def test_local_cache_wins_over_bundled(self):
"""用户复核批准装下的那份更新;顺序反了,每次发版都会盖掉他的批准结果。"""
sample = brand_marks.manifest()["marks"][0]
stem = pathlib.Path(sample["file"]).stem
with tempfile.TemporaryDirectory() as raw:
logo_root = pathlib.Path(raw)
local = logo_root / f"{stem}.img"
local.write_bytes(b"\x89PNG\r\n\x1a\n local")
service = PreviewService.__new__(PreviewService)
service.logo_root = logo_root.resolve()
# 这两个用例要的正是「内置资源真的接上了」,所以给真实的 `STUDIOS_DIR`。
service.marks_root = brand_marks.STUDIOS_DIR
found = service._logo_file(list(logo_root.iterdir()), f"{stem}.img")
self.assertEqual(local.resolve(), found.resolve())
def test_bundled_used_when_cache_empty(self):
"""干净数据目录正是内置资源要顶上的场景。"""
sample = brand_marks.manifest()["marks"][0]
stem = pathlib.Path(sample["file"]).stem
with tempfile.TemporaryDirectory() as raw:
logo_root = pathlib.Path(raw)
service = PreviewService.__new__(PreviewService)
service.logo_root = logo_root.resolve()
# 这两个用例要的正是「内置资源真的接上了」,所以给真实的 `STUDIOS_DIR`。
service.marks_root = brand_marks.STUDIOS_DIR
found = service._logo_file([], f"{stem}.img")
self.assertEqual(brand_marks.STUDIOS_DIR / sample["file"], found)
self.assertEqual(sample["content_type"], service._logo_content_type(found))
class SyncScriptTests(unittest.TestCase):
"""采集脚本:判据落选要能解释,重复执行不能产生改动。"""
def _run(self, source, target, *extra):
script = REPO / "scripts" / "sync_brand_marks.py"
proc = subprocess.run(
[sys.executable, "-X", "utf8", str(script),
"--source", str(source), "--target", str(target), *extra],
capture_output=True, text=True, encoding="utf-8")
self.assertEqual(0, proc.returncode, proc.stderr)
return json.loads(proc.stdout.strip().splitlines()[-1])
def _fixture(self, root, name, data, meta):
(root / f"{name}.img").write_bytes(data)
if meta is not None:
(root / f"{name}.img.provenance.json").write_text(
json.dumps(meta), encoding="utf-8")
def test_filters_and_repeats_cleanly(self):
png = b"\x89PNG\r\n\x1a\n" + b"0" * 64
with tempfile.TemporaryDirectory() as raw:
base = pathlib.Path(raw)
source, target = base / "logos", base / "marks"
source.mkdir()
self._fixture(source, "Good", png, {"source_url": "https://x.test/a.png"})
self._fixture(source, "Good.icon", png + b"1", {"source_url": "https://x.test/b.png"})
self._fixture(source, "NoSource", png, None)
self._fixture(source, "Oversize", png + b"0" * brand_marks.MAX_FILE_BYTES,
{"source_url": "https://x.test/c.png"})
self._fixture(source, "NotAnImage", b"<html>nope</html>",
{"source_url": "https://x.test/d.png"})
first = self._run(source, target, "--apply")
self.assertEqual(2, first["taken"])
self.assertEqual(3, first["skipped"])
self.assertEqual(["no_source_url", "too_large", "unknown_format"],
first["reasons"])
self.assertEqual(2, first["written"])
self.assertEqual({"Good.png", "Good.icon.png"},
{p.name for p in (target / "studios").iterdir()})
second = self._run(source, target, "--apply")
self.assertEqual(0, second["written"], "重复执行不该重写任何文件")
self.assertEqual([], second["removed"])
def test_drops_files_outside_the_manifest(self):
"""目录里只留清单登记的那些:厂牌改名后旧名字那份不清掉就会永远留在仓库里。"""
png = b"\x89PNG\r\n\x1a\n" + b"0" * 64
with tempfile.TemporaryDirectory() as raw:
base = pathlib.Path(raw)
source, target = base / "logos", base / "marks"
source.mkdir()
self._fixture(source, "OldName", png, {"source_url": "https://x.test/a.png"})
self._run(source, target, "--apply")
(source / "OldName.img").unlink()
self._fixture(source, "NewName", png, {"source_url": "https://x.test/a.png"})
result = self._run(source, target, "--apply")
self.assertEqual(["OldName.png"], result["removed"])
self.assertEqual({"NewName.png"},
{p.name for p in (target / "studios").iterdir()})
def test_a_variant_with_the_bare_files_bytes_is_not_shipped_twice(self):
png = b"\x89PNG\r\n\x1a\n" + b"0" * 64
with tempfile.TemporaryDirectory() as raw:
base = pathlib.Path(raw)
source, target = base / "logos", base / "marks"
source.mkdir()
for name in ("Baked", "Baked.icon", "Baked.logo"):
self._fixture(source, name, png, {"source_url": "https://x.test/a.png"})
result = self._run(source, target, "--apply")
self.assertEqual(["same_as_base"], result["reasons"])
self.assertEqual({"Baked.png"}, {p.name for p in (target / "studios").iterdir()})
service = PreviewService.__new__(PreviewService)
service.logo_root = base / "empty"
service.marks_root = target / "studios"
for variant in LOGO_VARIANTS:
found, _type = service.logo("Baked", variant)
self.assertEqual(target / "studios" / "Baked.png", found)
def test_dry_run_writes_nothing(self):
png = b"\x89PNG\r\n\x1a\n" + b"0" * 64
with tempfile.TemporaryDirectory() as raw:
base = pathlib.Path(raw)
source, target = base / "logos", base / "marks"
source.mkdir()
self._fixture(source, "Good", png, {"source_url": "https://x.test/a.png"})
result = self._run(source, target)
self.assertEqual(1, result["taken"])
self.assertFalse(target.exists())
if __name__ == "__main__":
unittest.main()