Add bundled bus fonts and shared font favorites
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
import json
|
||||
|
||||
import pytest
|
||||
from fastapi.testclient import TestClient
|
||||
|
||||
from app.fonts.store import FontCatalog, FontValidationError
|
||||
from app.main import create_app
|
||||
|
||||
|
||||
def test_api_validation_and_persistence(tmp_path):
|
||||
app = create_app(project_root=tmp_path, driver_kind="mock")
|
||||
client = TestClient(app)
|
||||
items = client.get("/api/fonts").json()["items"]
|
||||
assert client.get("/api/fonts").json()["favorite_ids"] == []
|
||||
ids = [item["id"] for item in items[:3]]
|
||||
for identifier in ids:
|
||||
assert client.put("/api/fonts/favorite", json={"id": identifier, "favorite": True}).status_code == 200
|
||||
path = app.state.font_catalog.root / "favorites.json"
|
||||
before = path.read_bytes()
|
||||
client.put("/api/fonts/favorite", json={"id": ids[0], "favorite": True})
|
||||
assert path.read_bytes() == before
|
||||
assert FontCatalog(path.parent.parent).document()["favorite_ids"] == ids
|
||||
for payload in ({"id": "default", "favorite": "true"}, {"id": "default", "favorite": 1}, {"id": "", "favorite": True}, {"id": "default", "favorite": True, "extra": 1}):
|
||||
assert client.put("/api/fonts/favorite", json=payload).status_code == 422
|
||||
assert client.put("/api/fonts/favorite", json={"id": "missing", "favorite": True}).status_code == 404
|
||||
assert client.put("/api/fonts/favorite", json={"id": "missing", "favorite": False}).status_code == 200
|
||||
client.put("/api/fonts/favorite", json={"id": ids[0], "favorite": False})
|
||||
assert client.get("/api/fonts").json()["favorite_ids"] == ids[1:]
|
||||
|
||||
|
||||
def test_concurrent_merge_and_write_failure(tmp_path, monkeypatch):
|
||||
catalog = FontCatalog(tmp_path)
|
||||
ids = [item["id"] for item in catalog.document()["items"][:3]]
|
||||
with ThreadPoolExecutor(max_workers=3) as pool:
|
||||
list(pool.map(lambda identifier: catalog.set_favorite(identifier, True), ids))
|
||||
assert set(catalog.document()["favorite_ids"]) == set(ids)
|
||||
before = (catalog.root / "favorites.json").read_bytes()
|
||||
def fail(*args):
|
||||
raise OSError("injected write failure")
|
||||
monkeypatch.setattr("app.fonts.store.atomic_write_bytes", fail)
|
||||
with pytest.raises(OSError):
|
||||
catalog.set_favorite(ids[0], False)
|
||||
assert set(catalog.document()["favorite_ids"]) == set(ids)
|
||||
assert (catalog.root / "favorites.json").read_bytes() == before
|
||||
|
||||
|
||||
@pytest.mark.parametrize("content", [b"broken", b'{"schema_version":2,"favorite_ids":[]}', b'{"schema_version":true,"favorite_ids":[]}', b'{"schema_version":1,"favorite_ids":["x","x"]}', b'{"schema_version":1,"favorite_ids":[],"extra":1}'])
|
||||
def test_invalid_file_preserved(tmp_path, content):
|
||||
(tmp_path / "fonts").mkdir()
|
||||
path = tmp_path / "fonts/favorites.json"
|
||||
path.write_bytes(content)
|
||||
with pytest.raises(FontValidationError):
|
||||
FontCatalog(tmp_path)
|
||||
assert path.read_bytes() == content
|
||||
|
||||
|
||||
def test_stale_ids_preserved_and_removable(tmp_path):
|
||||
catalog = FontCatalog(tmp_path)
|
||||
path = catalog.root / "favorites.json"
|
||||
path.write_text(json.dumps({"schema_version": 1, "favorite_ids": ["stale"]}), encoding="utf-8")
|
||||
catalog = FontCatalog(tmp_path)
|
||||
assert catalog.document()["favorite_ids"] == ["stale"]
|
||||
assert not any(item["id"] == "stale" for item in catalog.document()["items"])
|
||||
assert catalog.set_favorite("stale", False) == []
|
||||
|
||||
|
||||
def test_same_family_styles_are_independent(tmp_path):
|
||||
from test_fonts import build_test_font
|
||||
app = create_app(project_root=tmp_path, driver_kind="mock")
|
||||
client = TestClient(app)
|
||||
ids = []
|
||||
for style in ["Bold", "Italic"]:
|
||||
response = client.post("/api/fonts/import?filename=style.ttf", content=build_test_font("Same Family", style), headers={"Content-Type": "application/octet-stream"})
|
||||
assert response.status_code == 201
|
||||
ids.append(response.json()["fonts"][0]["id"])
|
||||
client.put("/api/fonts/favorite", json={"id": ids[0], "favorite": True})
|
||||
assert client.get("/api/fonts").json()["favorite_ids"] == [ids[0]]
|
||||
client.put("/api/fonts/favorite", json={"id": ids[1], "favorite": True})
|
||||
client.put("/api/fonts/favorite", json={"id": ids[0], "favorite": False})
|
||||
assert client.get("/api/fonts").json()["favorite_ids"] == [ids[1]]
|
||||
Reference in New Issue
Block a user