ui-ux-pro-max-skill/cli/assets/scripts/tests/test_catalog_refresh.py
Viet Tran a38d04c3d5
feat(search): overhaul relevance and curated design data
Overhaul BM25 relevance, reasoning and data-quality contracts; refresh UI styles and framework guidance; add resilient text, chip, badge and micro-interaction guidance; strengthen release, provenance and catalog refresh gates; update bilingual documentation.
2026-08-14 00:08:23 +07:00

355 lines
19 KiB
Python

#!/usr/bin/env python3
"""Offline contract tests for deterministic upstream catalog refreshes."""
import csv
import json
import os
import subprocess
import sys
import tempfile
import unittest
from pathlib import Path
REPO = next(
parent for parent in Path(__file__).resolve().parents
if all((parent / "scripts" / script).is_file() for script in (
"refresh-google-fonts.py", "refresh-icon-catalog.py",
))
)
FIXTURES = Path(__file__).parent / "fixtures" / "catalogs"
FONT_SCRIPT = REPO / "scripts" / "refresh-google-fonts.py"
ICON_SCRIPT = REPO / "scripts" / "refresh-icon-catalog.py"
class CatalogRefreshTest(unittest.TestCase):
def run_command(self, *args, env=None):
return subprocess.run(
[sys.executable, *map(str, args)],
cwd=REPO,
env=env,
capture_output=True,
text=True,
check=False,
)
def font_args(self, directory, api=None, metadata=None, approve=True, existing=None, overrides=None):
args = [
FONT_SCRIPT,
"--api-input", api or FIXTURES / "google-api.json",
"--metadata-input", metadata or FIXTURES / "google-metadata.json",
"--existing-csv", existing or FIXTURES / "google-existing.csv",
"--overrides", overrides or FIXTURES / "google-overrides.json",
"--output-csv", directory / "google-fonts.csv",
"--license-output", directory / "google-font-licenses.json",
"--verified-at", "2026-08-13",
"--metadata-revision", "fixture-catalogs-v1",
"--expected-count", "2",
]
if approve:
args.append("--approve-changes")
return args
def icon_args(self, directory, source=None, curated=None, package=None, react_exports=None):
return [
ICON_SCRIPT,
"--input", source or FIXTURES / "phosphor-core.json",
"--package-json", package or FIXTURES / "phosphor-package.json",
"--react-package-json", FIXTURES / "phosphor-react-package.json",
"--react-exports-input", react_exports or FIXTURES / "phosphor-react-exports.json",
"--curated-csv", curated or FIXTURES / "icons-curated.csv",
"--output", directory / "phosphor-icons-upstream.json",
"--verified-at", "2026-08-13",
"--expected-count", "2",
]
def test_live_font_refresh_requires_environment_key(self):
with tempfile.TemporaryDirectory() as raw:
directory = Path(raw)
args = self.font_args(directory)
args[1:3] = ["--live"]
env = dict(os.environ)
env.pop("GOOGLE_FONTS_API_KEY", None)
result = self.run_command(*args, env=env)
self.assertEqual(2, result.returncode)
self.assertIn("GOOGLE_FONTS_API_KEY is required for --live", result.stderr)
self.assertIn("use --api-input for offline CI", result.stderr)
def test_font_refresh_is_deterministic_and_preserves_reviewed_fields(self):
with tempfile.TemporaryDirectory() as first, tempfile.TemporaryDirectory() as second:
first_path, second_path = Path(first), Path(second)
self.assertEqual(0, self.run_command(*self.font_args(first_path)).returncode)
self.assertEqual(0, self.run_command(*self.font_args(second_path)).returncode)
self.assertEqual(
(first_path / "google-fonts.csv").read_bytes(),
(second_path / "google-fonts.csv").read_bytes(),
)
self.assertEqual(
(first_path / "google-font-licenses.json").read_bytes(),
(second_path / "google-font-licenses.json").read_bytes(),
)
with (first_path / "google-fonts.csv").open(encoding="utf-8", newline="") as handle:
rows = list(csv.DictReader(handle))
csv_bytes = (first_path / "google-fonts.csv").read_bytes()
license_bytes = (first_path / "google-font-licenses.json").read_bytes()
licenses = json.loads(license_bytes)
self.assertEqual(["Alpha Sans", "Zeta Serif"], [row["Family"] for row in rows])
self.assertEqual("Sans Serif", rows[0]["Stroke"])
self.assertEqual("approved override keywords", rows[0]["Keywords"])
self.assertEqual("400 | 400i | 500", rows[0]["Styles"])
self.assertEqual("wght: 100..900", rows[0]["Variable Axes"])
self.assertEqual(["OFL", "APACHE2"], [item["license"] for item in licenses["families"]])
self.assertEqual(["Alpha Sans", "Zeta Serif"], [item["name"] for item in licenses["families"]])
self.assertEqual("fixture-catalogs-v1", licenses["source"]["revision"])
self.assertTrue(all(item["status"] == "active" for item in licenses["families"]))
self.assertTrue(all(item["verifiedAt"] == "2026-08-13" for item in licenses["families"]))
with tempfile.TemporaryDirectory() as raw:
reused = Path(raw)
metadata_path = reused / "metadata.json"
metadata_path.write_bytes(license_bytes)
result = self.run_command(*self.font_args(
reused, metadata=metadata_path
))
self.assertEqual(0, result.returncode, result.stderr)
self.assertEqual(
csv_bytes, (reused / "google-fonts.csv").read_bytes(),
)
def test_font_refresh_rejects_schema_size_dates_and_licenses(self):
with tempfile.TemporaryDirectory() as raw:
directory = Path(raw)
api = json.loads((FIXTURES / "google-api.json").read_text())
metadata = json.loads((FIXTURES / "google-metadata.json").read_text())
cases = []
wrong_schema = dict(api)
wrong_schema["kind"] = "unexpected"
cases.append((wrong_schema, metadata, "webfonts#webfontList"))
cases.append(({**api, "items": api["items"][:1]}, metadata, "expected 2 items"))
bad_url = json.loads(json.dumps(api))
bad_url["items"][0]["files"]["regular"] = "https://example.com/font.ttf"
cases.append((bad_url, metadata, "https://fonts.gstatic.com"))
bad_date = json.loads(json.dumps(api))
bad_date["items"][0]["lastModified"] = "1970-01-01"
cases.append((bad_date, metadata, "suspicious date"))
bad_license = json.loads(json.dumps(metadata))
bad_license["families"][0]["license"] = "UNKNOWN"
cases.append((api, bad_license, "invalid or missing official license"))
for index, (api_value, metadata_value, error) in enumerate(cases):
api_path, metadata_path = directory / f"api-{index}.json", directory / f"metadata-{index}.json"
api_path.write_text(json.dumps(api_value))
metadata_path.write_text(json.dumps(metadata_value))
result = self.run_command(*self.font_args(directory, api_path, metadata_path))
with self.subTest(error=error):
self.assertEqual(2, result.returncode)
self.assertIn(error, result.stderr)
def test_font_refresh_fails_closed_on_concurrency_or_interrupted_pair(self):
for sentinel, error in (
(".google-font-refresh.lock", "another refresh is already running"),
(".google-font-refresh.incomplete.json", "incomplete prior refresh"),
):
with self.subTest(sentinel=sentinel), tempfile.TemporaryDirectory() as raw:
directory = Path(raw)
(directory / sentinel).write_text("occupied\n", encoding="utf-8")
result = self.run_command(*self.font_args(directory))
self.assertEqual(2, result.returncode)
self.assertIn(error, result.stderr)
self.assertFalse((directory / "google-fonts.csv").exists())
self.assertFalse((directory / "google-font-licenses.json").exists())
def test_catalog_cross_check_uses_explicit_schema_without_font_file_urls(self):
with tempfile.TemporaryDirectory() as raw:
directory = Path(raw)
args = self.font_args(directory)
args[1:3] = ["--catalog-input", FIXTURES / "google-catalog.json"]
result = self.run_command(*args)
with (directory / "google-fonts.csv").open(encoding="utf-8", newline="") as handle:
rows = list(csv.DictReader(handle))
self.assertEqual(0, result.returncode, result.stderr)
self.assertEqual(["Alpha Sans", "Zeta Serif"], [row["Family"] for row in rows])
self.assertEqual("Geometric", rows[0]["Classifications"])
self.assertEqual("42", rows[0]["Popularity Rank"])
self.assertEqual("latin | vietnamese", rows[0]["Subsets"])
def test_official_metadata_checkout_is_strict_and_reusable(self):
with tempfile.TemporaryDirectory() as raw:
directory = Path(raw)
metadata_root = directory / "google-fonts"
family_dir = metadata_root / "ofl" / "alphasans"
family_dir.mkdir(parents=True)
(family_dir / "METADATA.pb").write_text(
'name: "Alpha Sans"\n'
'designer: "Alpha Designer"\n'
'license: "OFL"\n'
'date_added: "2024-01-02"\n',
encoding="utf-8",
)
args = self.font_args(directory)
metadata_index = args.index("--metadata-input")
args[metadata_index:metadata_index + 2] = ["--metadata-root", metadata_root]
result = self.run_command(*args)
self.assertEqual(2, result.returncode)
self.assertIn("fewer than 90%", result.stderr)
with tempfile.TemporaryDirectory() as raw:
directory = Path(raw)
metadata_root = directory / "google-fonts"
for slug, family, license_name in (
("alphasans", "Alpha Sans", "OFL"),
("zetaserif", "Zeta Serif", "APACHE2"),
):
family_dir = metadata_root / "ofl" / slug
family_dir.mkdir(parents=True)
(family_dir / "METADATA.pb").write_text(
f'name: "{family}"\n'
f'designer: "{family} Designer"\n'
f'license: "{license_name}"\n'
'date_added: "2024-01-02"\n',
encoding="utf-8",
)
args = self.font_args(directory)
metadata_index = args.index("--metadata-input")
args[metadata_index:metadata_index + 2] = ["--metadata-root", metadata_root]
result = self.run_command(*args)
licenses = json.loads((directory / "google-font-licenses.json").read_text())
self.assertEqual(0, result.returncode, result.stderr)
self.assertEqual(["Alpha Sans", "Zeta Serif"], [item["name"] for item in licenses["families"]])
def test_catalog_rejects_bool_rank_duplicate_axis_and_unreviewed_addition(self):
with tempfile.TemporaryDirectory() as raw:
directory = Path(raw)
catalog = json.loads((FIXTURES / "google-catalog.json").read_text())
invalid_rank = json.loads(json.dumps(catalog))
invalid_rank["familyMetadataList"][0]["popularity"] = True
rank_path = directory / "rank.json"
rank_path.write_text(json.dumps(invalid_rank))
rank_args = self.font_args(directory)
rank_args[1:3] = ["--catalog-input", rank_path]
rank_result = self.run_command(*rank_args)
invalid_axis = json.loads(json.dumps(catalog))
axis = invalid_axis["familyMetadataList"][1]["axes"][0]
invalid_axis["familyMetadataList"][1]["axes"].append(dict(axis))
axis_path = directory / "axis.json"
axis_path.write_text(json.dumps(invalid_axis))
axis_args = self.font_args(directory)
axis_args[1:3] = ["--catalog-input", axis_path]
axis_result = self.run_command(*axis_args)
existing = directory / "existing.csv"
lines = (FIXTURES / "google-existing.csv").read_text().splitlines()
existing.write_text("\n".join(lines[:2]) + "\n")
approval_result = self.run_command(*self.font_args(directory, approve=False, existing=existing))
bad_overrides = directory / "overrides.json"
bad_overrides.write_text('{"families":{"Unknown Font":{"Keywords":"bad"}}}')
override_result = self.run_command(*self.font_args(directory, overrides=bad_overrides))
self.assertIn("invalid popularity", rank_result.stderr)
self.assertIn("duplicate axis tags", axis_result.stderr)
self.assertIn("family-set changes require --approve-changes", approval_result.stderr)
self.assertIn("Zeta Serif", approval_result.stdout)
self.assertFalse((directory / "google-fonts.csv").exists())
self.assertIn("overrides target unknown families", override_result.stderr)
def test_explicit_license_exclusion_is_reported_and_not_promoted(self):
with tempfile.TemporaryDirectory() as raw:
directory = Path(raw)
metadata = json.loads((FIXTURES / "google-metadata.json").read_text())
metadata["families"] = metadata["families"][:1]
metadata["excludedFamilies"] = [{
"name": "Alpha Sans", "reason": "No matching official METADATA.pb",
"source": "https://github.com/google/fonts",
}]
metadata_path = directory / "metadata.json"
metadata_path.write_text(json.dumps(metadata))
result = self.run_command(*self.font_args(directory, metadata=metadata_path))
report = json.loads(result.stdout)
licenses = json.loads((directory / "google-font-licenses.json").read_text())
with (directory / "google-fonts.csv").open(encoding="utf-8", newline="") as handle:
rows = list(csv.DictReader(handle))
self.assertEqual(0, result.returncode, result.stderr)
self.assertEqual(["Zeta Serif"], [row["Family"] for row in rows])
self.assertEqual("needs-review", report["excludedFamilies"][0]["status"])
self.assertEqual("needs-review", licenses["excludedFamilies"][0]["status"])
def test_exclusion_sources_match_offline_validator_policy(self):
metadata = json.loads((FIXTURES / "google-metadata.json").read_text())
allowed = (
"https://fonts.google.com/specimen/Alpha+Sans",
"https://github.com/google/fonts",
"https://github.com/google/fonts/tree/main/ofl/alphasans",
)
rejected = (
"https://example.com/google/fonts",
"https://github.com/other/fonts",
"https://fonts.google.com:444/specimen/Alpha+Sans",
)
for index, source in enumerate((*allowed, *rejected)):
with self.subTest(source=source), tempfile.TemporaryDirectory() as raw:
directory = Path(raw)
candidate = json.loads(json.dumps(metadata))
candidate["families"] = candidate["families"][1:]
candidate["excludedFamilies"] = [{
"name": "Zeta Serif",
"reason": "No matching official METADATA.pb",
"source": source,
}]
metadata_path = directory / f"metadata-{index}.json"
metadata_path.write_text(json.dumps(candidate))
result = self.run_command(*self.font_args(directory, metadata=metadata_path))
self.assertEqual(source in allowed, result.returncode == 0, result.stderr)
def test_icon_manifest_normalizes_and_records_all_import_forms(self):
with tempfile.TemporaryDirectory() as first, tempfile.TemporaryDirectory() as second:
first_path, second_path = Path(first), Path(second)
self.assertEqual(0, self.run_command(*self.icon_args(first_path)).returncode)
self.assertEqual(0, self.run_command(*self.icon_args(second_path)).returncode)
output = first_path / "phosphor-icons-upstream.json"
self.assertEqual(output.read_bytes(), (second_path / output.name).read_bytes())
manifest = json.loads(output.read_text())
self.assertEqual("2.1.1", manifest["source"]["version"])
self.assertEqual(("active", "2026-08-13"), (manifest["status"], manifest["verifiedAt"]))
self.assertEqual(["thin", "light", "regular", "bold", "fill", "duotone"], manifest["weights"])
self.assertEqual(["acorn", "arrow-left"], [icon["name"] for icon in manifest["icons"]])
arrow = manifest["icons"][1]
self.assertEqual(["arrows", "navigation"], arrow["categories"])
self.assertIn('from "@phosphor-icons/react"', arrow["clientImport"])
self.assertIn('from "@phosphor-icons/react/ssr"', arrow["ssrImport"])
self.assertEqual(2, manifest["curatedValidatedCount"])
def test_icon_refresh_rejects_invalid_schema_size_and_curated_import(self):
with tempfile.TemporaryDirectory() as raw:
directory = Path(raw)
icons = json.loads((FIXTURES / "phosphor-core.json").read_text())
invalid = json.loads(json.dumps(icons))
del invalid[0]["pascal_name"]
source = directory / "invalid.json"
source.write_text(json.dumps(invalid))
schema_result = self.run_command(*self.icon_args(directory, source))
size_args = self.icon_args(directory)
size_args[-1] = "3"
size_result = self.run_command(*size_args)
curated = (FIXTURES / "icons-curated.csv").read_text().replace("{ Acorn }", "{ Horse }")
curated_path = directory / "icons.csv"
curated_path.write_text(curated)
import_result = self.run_command(*self.icon_args(directory, curated=curated_path))
package_path = directory / "package.json"
package_path.write_text('{"name":"@phosphor-icons/core","version":"2.2.0"}')
version_result = self.run_command(*self.icon_args(directory, package=package_path))
alias_collision = json.loads(json.dumps(icons))
alias_collision[1]["alias"] = {"name": "acorn", "pascal_name": "BackArrow"}
alias_path = directory / "alias.json"
alias_path.write_text(json.dumps(alias_collision))
alias_result = self.run_command(*self.icon_args(directory, source=alias_path))
exports = json.loads((FIXTURES / "phosphor-react-exports.json").read_text())
exports["ssr"].remove("Acorn")
exports_path = directory / "exports.json"
exports_path.write_text(json.dumps(exports))
exports_result = self.run_command(*self.icon_args(directory, react_exports=exports_path))
self.assertIn("invalid official IconEntry schema", schema_result.stderr)
self.assertIn("expected 3 icons", size_result.stderr)
self.assertIn("import component does not match", import_result.stderr)
self.assertIn("version must be 2.1.1", version_result.stderr)
self.assertIn("alias collides", alias_result.stderr)
self.assertIn("React exports missing", exports_result.stderr)
if __name__ == "__main__":
unittest.main()