Update documentation and scripts for font addition process; introduce uv run add-font CLI command for streamlined font management. Enhance formula generation with improved class name formatting and validation steps. Remove outdated font formula files.

This commit is contained in:
Matt Troutman 2026-02-09 22:04:01 -06:00
parent 69d8156b09
commit 56b64d0b34
No known key found for this signature in database
266 changed files with 1187 additions and 8145 deletions

42
tests/conftest.py Normal file
View file

@ -0,0 +1,42 @@
"""Shared fixtures and repo paths for font tap tests."""
from pathlib import Path
import pytest
# Repo root: directory containing font_files/ and Formula/
REPO_ROOT = Path(__file__).resolve().parent.parent
FONT_FILES_DIR = REPO_ROOT / "font_files"
FORMULA_DIR = REPO_ROOT / "Formula"
REQUIRED_SUBDIRS = ("ttf", "otf", "web", "other_files")
WEB_EXTENSIONS = (".woff", ".woff2", ".eot", ".svg")
def get_font_dir_names():
"""Return sorted list of font-* directory names in font_files/ (single source of truth)."""
if not FONT_FILES_DIR.exists():
return []
return sorted(
d.name for d in FONT_FILES_DIR.iterdir() if d.is_dir() and d.name.startswith("font-")
)
@pytest.fixture(scope="session")
def repo_root():
return REPO_ROOT
@pytest.fixture(scope="session")
def font_dir_names():
"""All font folder names (font-<name>) from font_files/."""
names = get_font_dir_names()
assert names, "No font-* directories found in font_files/"
return names
@pytest.fixture(scope="session")
def formula_paths():
"""All Formula/font-*.rb paths that exist."""
if not FORMULA_DIR.exists():
return []
return sorted(FORMULA_DIR.glob("font-*.rb"))

View file

@ -0,0 +1,41 @@
"""Tests for font folder structure: required subdirs and at least one font file per font."""
import pytest
from tests.conftest import FONT_FILES_DIR, REQUIRED_SUBDIRS, WEB_EXTENSIONS, get_font_dir_names
# Top-level names to ignore (e.g. .DS_Store; cleanup script removes these)
IGNORED_TOPLEVEL = {".DS_Store"}
@pytest.mark.parametrize("font_name", get_font_dir_names())
def test_font_has_required_subdirs_only(font_name):
"""Each font folder has exactly ttf/, otf/, web/, other_files/ and no other top-level items (except ignored)."""
font_dir = FONT_FILES_DIR / font_name
assert font_dir.is_dir(), f"Font dir missing: {font_dir}"
names = [p.name for p in font_dir.iterdir() if p.name not in IGNORED_TOPLEVEL]
for required in REQUIRED_SUBDIRS:
assert required in names, f"{font_name}: missing subdir {required}/"
# All must be directories (the four subdirs)
for name in names:
assert (font_dir / name).is_dir(), f"{font_name}: unexpected file or non-dir at top level: {name}"
assert len(names) == 4, f"{font_name}: expected exactly 4 subdirs, got {names}"
@pytest.mark.parametrize("font_name", get_font_dir_names())
def test_font_has_at_least_one_font_file_or_other(font_name):
"""Each font folder has at least one font file (ttf/otf/web) or content in other_files."""
font_dir = FONT_FILES_DIR / font_name
has_ttf = any((font_dir / "ttf").glob("*.ttf"))
has_otf = any((font_dir / "otf").glob("*.otf"))
web_dir = font_dir / "web"
has_web = any(
f.suffix.lower() in WEB_EXTENSIONS
for f in web_dir.glob("*")
if f.is_file()
)
other_dir = font_dir / "other_files"
has_other = any(other_dir.iterdir()) if other_dir.exists() else False
assert has_ttf or has_otf or has_web or has_other, (
f"{font_name}: no font files in ttf/, otf/, or web/ and no content in other_files/"
)

View file

@ -0,0 +1,42 @@
"""Tests for formula content: correct paths and valid Ruby class name."""
import re
import pytest
from tests.conftest import FONT_FILES_DIR, FORMULA_DIR, get_font_dir_names
def formula_name_to_class(formula_name: str) -> str:
"""Same logic as generator: formula name to PascalCase (no hyphens)."""
parts = re.split(r"[-_]+", formula_name)
return "".join(p.capitalize() for p in parts if p)
@pytest.mark.parametrize("font_name", get_font_dir_names())
def test_formula_references_correct_font_path(font_name):
"""Generated formula contains the correct font_files/font-<name>/ path."""
formula_path = FORMULA_DIR / f"{font_name}.rb"
content = formula_path.read_text()
# Install block should reference this font path
assert f"font_files/{font_name}/" in content, (
f"{font_name}: formula does not reference font_files/{font_name}/"
)
@pytest.mark.parametrize("font_name", get_font_dir_names())
def test_formula_class_name_valid_and_matches(font_name):
"""Formula defines class Font<PascalCase> with no hyphens (valid Ruby)."""
formula_path = FORMULA_DIR / f"{font_name}.rb"
content = formula_path.read_text()
formula_name = font_name.replace("font-", "", 1)
expected_class = "Font" + formula_name_to_class(formula_name)
# Class line: class FontSomething < Formula
match = re.search(r"class\s+(Font\w+)\s+<\s+Formula", content)
assert match, f"{font_name}: no 'class Font... < Formula' found"
actual_class = match.group(1)
assert "-" not in actual_class, (
f"{font_name}: Ruby class name must not contain hyphens (got {actual_class})"
)
assert actual_class == expected_class, (
f"{font_name}: expected class {expected_class}, got {actual_class}"
)

View file

@ -0,0 +1,14 @@
"""Tests that a Formula file exists for every font."""
import pytest
from tests.conftest import FORMULA_DIR, get_font_dir_names
@pytest.mark.parametrize("font_name", get_font_dir_names())
def test_formula_file_exists(font_name):
"""Formula/font-<name>.rb exists for each font folder."""
# font_name is e.g. "font-acrylic-hand"; formula file is font-acrylic-hand.rb
formula_path = FORMULA_DIR / f"{font_name}.rb"
assert formula_path.is_file(), (
f"Missing formula for {font_name}: expected {formula_path}"
)

105
tests/test_install_works.py Normal file
View file

@ -0,0 +1,105 @@
"""Verify that each font's formula install logic would copy the right files (simulated install)."""
import shutil
import tempfile
from pathlib import Path
import pytest
from tests.conftest import (
FONT_FILES_DIR,
FORMULA_DIR,
WEB_EXTENSIONS,
get_font_dir_names,
)
def _run_install_simulation(font_name: str, font_dir: Path, prefix: Path, formula_name: str) -> None:
"""
Simulate the formula's install: copy ttf/otf/web/other_files to prefix
as the formula would (same layout as homebrew-fonts-main/font_files/<font_name>/).
"""
# Layout formula expects: homebrew-fonts-main/font_files/<font_name>/{ttf,otf,web,other_files}
# We use font_dir directly (same layout).
(prefix / "fonts").mkdir(parents=True)
(prefix / "fonts/truetype").mkdir(parents=True)
(prefix / "fonts/opentype").mkdir(parents=True)
(prefix / "fonts/webfonts").mkdir(parents=True)
(prefix / formula_name).mkdir(parents=True)
for f in (font_dir / "ttf").glob("*.ttf"):
shutil.copy2(f, prefix / "fonts/truetype" / f.name)
for f in (font_dir / "otf").glob("*.otf"):
shutil.copy2(f, prefix / "fonts/opentype" / f.name)
web_dir = font_dir / "web"
for f in web_dir.iterdir():
if f.is_file() and f.suffix.lower() in WEB_EXTENSIONS:
shutil.copy2(f, prefix / "fonts/webfonts" / f.name)
other_src = font_dir / "other_files"
if other_src.exists():
for f in other_src.iterdir():
dest = prefix / formula_name / f.name
if f.is_dir():
shutil.copytree(f, dest, dirs_exist_ok=True)
else:
shutil.copy2(f, dest)
@pytest.mark.parametrize("font_name", get_font_dir_names())
def test_install_simulation_places_files(font_name):
"""Simulate install for this font and assert expected files are present under prefix."""
font_dir = FONT_FILES_DIR / font_name
formula_name = font_name.replace("font-", "", 1)
with tempfile.TemporaryDirectory() as tmp:
prefix = Path(tmp) / "prefix"
prefix.mkdir()
_run_install_simulation(font_name, font_dir, prefix, formula_name)
# Same assertions as the formula's test block: at least one expected path has content
ttf_files = list((prefix / "fonts/truetype").glob("*.ttf"))
otf_files = list((prefix / "fonts/opentype").glob("*.otf"))
web_files = list((prefix / "fonts/webfonts").iterdir()) if (prefix / "fonts/webfonts").exists() else []
other_dir = prefix / formula_name
has_other = other_dir.exists() and any(other_dir.iterdir())
has_ttf = len(ttf_files) > 0
has_otf = len(otf_files) > 0
has_web = len(web_files) > 0
assert has_ttf or has_otf or has_web or has_other, (
f"{font_name}: after simulated install, no files in share/fonts/truetype, "
f"share/fonts/opentype, share/fonts/webfonts, or share/{formula_name}"
)
@pytest.mark.parametrize("font_name", get_font_dir_names())
def test_install_simulation_file_counts_match_source(font_name):
"""After simulated install, number of installed font files matches font_files/."""
font_dir = FONT_FILES_DIR / font_name
formula_name = font_name.replace("font-", "", 1)
with tempfile.TemporaryDirectory() as tmp:
prefix = Path(tmp) / "prefix"
prefix.mkdir()
_run_install_simulation(font_name, font_dir, prefix, formula_name)
ttf_src = len(list((font_dir / "ttf").glob("*.ttf")))
otf_src = len(list((font_dir / "otf").glob("*.otf")))
web_src = sum(
1 for f in (font_dir / "web").iterdir()
if f.is_file() and f.suffix.lower() in WEB_EXTENSIONS
)
ttf_installed = len(list((prefix / "fonts/truetype").glob("*.ttf")))
otf_installed = len(list((prefix / "fonts/opentype").glob("*.otf")))
web_installed = len(list((prefix / "fonts/webfonts").iterdir()))
assert ttf_src == ttf_installed, (
f"{font_name}: TTF count mismatch: source={ttf_src}, installed={ttf_installed}"
)
assert otf_src == otf_installed, (
f"{font_name}: OTF count mismatch: source={otf_src}, installed={otf_installed}"
)
assert web_src == web_installed, (
f"{font_name}: web font count mismatch: source={web_src}, installed={web_installed}"
)

View file

@ -0,0 +1,34 @@
"""Global tests: no orphan formulae, no duplicate formula names."""
import pytest
from tests.conftest import FONT_FILES_DIR, FORMULA_DIR, get_font_dir_names
def test_every_formula_has_matching_font_folder():
"""Every Formula/font-*.rb has a matching font_files/font-<name>/ directory."""
formula_files = sorted(FORMULA_DIR.glob("font-*.rb"))
for formula_path in formula_files:
name = formula_path.stem # e.g. font-acrylic-hand
font_dir = FONT_FILES_DIR / name
assert font_dir.is_dir(), (
f"Orphan formula: {formula_path.name} has no matching font folder {font_dir}"
)
def test_no_duplicate_formula_names():
"""Only one formula file per font-<name> (no duplicate basenames)."""
formula_files = list(FORMULA_DIR.glob("font-*.rb"))
names = [p.stem for p in formula_files]
seen = set()
for n in names:
assert n not in seen, f"Duplicate formula name: {n}.rb"
seen.add(n)
def test_formula_count_matches_font_count():
"""Number of font-*.rb formulae equals number of font-* directories."""
font_names = get_font_dir_names()
formula_count = len(list(FORMULA_DIR.glob("font-*.rb")))
assert formula_count == len(font_names), (
f"Formula count ({formula_count}) != font dir count ({len(font_names)})"
)