"""Categorieën: indeling, kleuren en hoe ze door de API komen.""" import json import sys from pathlib import Path import pytest WORTEL = Path(__file__).resolve().parent.parent sys.path.insert(0, str(WORTEL / "server-up")) from core import boilerplates as bp from core import categories as cat from conftest import login APPS = sorted(d for d in (WORTEL / "apps").iterdir() if d.is_dir()) def test_elke_categorie_heeft_naam_en_kleur(): for cid, c in cat.CATEGORIES.items(): assert c["nl"] and c["en"], cid assert c["color"].startswith("#") and len(c["color"]) == 7, cid assert c["icon"].startswith("mdi-"), cid def test_kleuren_zijn_uniek(): """Twee categorieën met dezelfde kleur zijn niet uit elkaar te houden.""" kleuren = [c["color"] for c in cat.CATEGORIES.values()] assert len(kleuren) == len(set(kleuren)) @pytest.mark.parametrize("app", APPS, ids=[d.name for d in APPS]) def test_elke_app_heeft_geldige_categorieen(app): cats = bp.metadata(app)["categories"] assert cats, "geen categorie" for c in cats: assert c in cat.CATEGORIES, f"onbekende categorie '{c}'" assert len(cats) == len(set(cats)), "dubbele categorie" def test_apps_mogen_in_meerdere_categorieen(): meervoudig = [d.name for d in APPS if len(bp.metadata(d)["categories"]) > 1] assert len(meervoudig) >= 20, "vrijwel niemand valt onder meerdere categorieën" def test_elke_categorie_wordt_gebruikt(): """Een categorie die nergens voorkomt, is alleen maar ruis in het filter.""" gebruikt = {c for d in APPS for c in bp.metadata(d)["categories"]} ongebruikt = set(cat.CATEGORIES) - gebruikt - {"overig"} assert not ongebruikt, f"categorieën zonder apps: {sorted(ongebruikt)}" def test_afleiden_uit_tags_voor_externe_repos(): """Apps uit een externe repo geven geen categorieën op; dan leiden we ze af.""" assert "media" in cat.derive(["films", "series"]) assert "domotica" in cat.derive(["zigbee", "mqtt"]) assert "beveiliging" in cat.derive(["wachtwoorden"]) assert cat.derive([]) == ["overig"] assert cat.derive(["iets-heel-onbekends"]) == ["overig"] def test_afleiden_geeft_hoogstens_drie(): veel = ["films", "zigbee", "wachtwoorden", "backup", "wiki", "taken", "ai"] assert len(cat.derive(veel)) <= 3 def test_normalize_gooit_onbekende_weg(): assert cat.normalize(["media", "bestaatniet", "media"]) == ["media"] def test_normalize_valt_terug_op_tags(): assert cat.normalize([], ["films"]) == ["media"] def test_endpoint_geeft_kleuren(client): login(client) d = client.get("/api/categories").get_json() ids = {c["id"] for c in d["categories"]} assert "media" in ids and "domotica" in ids media = next(c for c in d["categories"] if c["id"] == "media") assert media["color"].startswith("#") and media["name"] def test_endpoint_in_het_engels(client): login(client) d = client.get("/api/categories?lang=en").get_json() media = next(c for c in d["categories"] if c["id"] == "media") assert media["name"] == "Media" fam = next(c for c in d["categories"] if c["id"] == "gezin") assert fam["name"] == "Family & home" def test_stacklijst_geeft_categorieen(client, env): login(client) stack = env["lib"] / "jellyfin" stack.mkdir(parents=True) (stack / "docker-compose.yml").write_text("services:\n a:\n image: x\n") (stack / ".serverup.json").write_text(json.dumps( {"source": "jellyfin", "name": "Jellyfin", "categories": ["media"]})) d = client.get("/api/stacks").get_json() assert d[0]["categories"] == ["media"] def test_oude_installatie_zonder_categorieen(client, env): """Een stack van vóór deze versie heeft geen categorieën opgeslagen; die mogen niet leeg blijven, anders valt de kleurmarkering weg.""" login(client) stack = env["lib"] / "oud" stack.mkdir(parents=True) (stack / "docker-compose.yml").write_text("services:\n a:\n image: x\n") (stack / ".serverup.json").write_text(json.dumps({"source": "oud", "name": "Oud"})) d = client.get("/api/stacks").get_json() assert d[0]["categories"] == ["overig"]