141 lines
4.3 KiB
Python
141 lines
4.3 KiB
Python
"""Tests for content_loader.py: schema validation (fail loud on a malformed
|
|
content/ file) and that the real glossary.yaml/pages.yaml load correctly.
|
|
Ported from backend/tests/web/test_content_loader.py (repo-split Stage 4) --
|
|
content_loader.py itself moved here in Stage 3."""
|
|
import pytest
|
|
|
|
import content_loader
|
|
|
|
|
|
def _write(tmp_path, name, text):
|
|
path = tmp_path / name
|
|
path.write_text(text, encoding="utf-8")
|
|
return str(path)
|
|
|
|
|
|
# --- load_glossary: schema validation --------------------------------------
|
|
|
|
def test_load_glossary_rejects_non_mapping_top_level(tmp_path):
|
|
path = _write(tmp_path, "g.yaml", "- just\n- a\n- list\n")
|
|
with pytest.raises(ValueError, match="top-level mapping"):
|
|
content_loader.load_glossary(path)
|
|
|
|
|
|
def test_load_glossary_rejects_missing_terms_key(tmp_path):
|
|
path = _write(tmp_path, "g.yaml", "not_terms: []\n")
|
|
with pytest.raises(ValueError, match="non-empty list"):
|
|
content_loader.load_glossary(path)
|
|
|
|
|
|
def test_load_glossary_rejects_empty_terms(tmp_path):
|
|
path = _write(tmp_path, "g.yaml", "terms: []\n")
|
|
with pytest.raises(ValueError, match="non-empty list"):
|
|
content_loader.load_glossary(path)
|
|
|
|
|
|
def test_load_glossary_rejects_missing_required_field(tmp_path):
|
|
path = _write(tmp_path, "g.yaml", """
|
|
terms:
|
|
- slug: foo
|
|
term: Foo
|
|
short: A short definition.
|
|
""")
|
|
with pytest.raises(ValueError, match="foo.*body"):
|
|
content_loader.load_glossary(path)
|
|
|
|
|
|
def test_load_glossary_rejects_blank_required_field(tmp_path):
|
|
path = _write(tmp_path, "g.yaml", """
|
|
terms:
|
|
- slug: foo
|
|
term: Foo
|
|
short: ""
|
|
body: Full body.
|
|
""")
|
|
with pytest.raises(ValueError, match="foo.*short"):
|
|
content_loader.load_glossary(path)
|
|
|
|
|
|
def test_load_glossary_rejects_duplicate_slug(tmp_path):
|
|
path = _write(tmp_path, "g.yaml", """
|
|
terms:
|
|
- slug: foo
|
|
term: Foo
|
|
short: s1
|
|
body: b1
|
|
- slug: foo
|
|
term: Foo Again
|
|
short: s2
|
|
body: b2
|
|
""")
|
|
with pytest.raises(ValueError, match="duplicate slug"):
|
|
content_loader.load_glossary(path)
|
|
|
|
|
|
def test_load_glossary_accepts_well_formed_content(tmp_path):
|
|
path = _write(tmp_path, "g.yaml", """
|
|
terms:
|
|
- slug: foo
|
|
term: Foo
|
|
short: A short definition.
|
|
body: A full body with <b>markup</b>.
|
|
- slug: bar
|
|
term: Bar
|
|
short: Another short definition.
|
|
body: Another full body.
|
|
""")
|
|
glossary = content_loader.load_glossary(path)
|
|
assert list(glossary) == ["foo", "bar"] # file order preserved
|
|
assert glossary["foo"] == {
|
|
"term": "Foo", "short": "A short definition.", "body": "A full body with <b>markup</b>.",
|
|
}
|
|
|
|
|
|
# --- load_pages: schema validation ------------------------------------------
|
|
|
|
def test_load_pages_rejects_missing_pages_key(tmp_path):
|
|
path = _write(tmp_path, "p.yaml", "not_pages: {}\n")
|
|
with pytest.raises(ValueError, match="non-empty mapping"):
|
|
content_loader.load_pages(path)
|
|
|
|
|
|
def test_load_pages_rejects_missing_required_field(tmp_path):
|
|
path = _write(tmp_path, "p.yaml", """
|
|
pages:
|
|
about:
|
|
title: About
|
|
""")
|
|
with pytest.raises(ValueError, match="about.*description"):
|
|
content_loader.load_pages(path)
|
|
|
|
|
|
def test_load_pages_accepts_well_formed_content(tmp_path):
|
|
path = _write(tmp_path, "p.yaml", """
|
|
pages:
|
|
about:
|
|
title: About Us
|
|
description: A description.
|
|
""")
|
|
pages = content_loader.load_pages(path)
|
|
assert pages == {"about": {"title": "About Us", "description": "A description."}}
|
|
|
|
|
|
# --- the real content/ files ------------------------------------------------
|
|
|
|
def test_real_glossary_loads_and_matches_the_rendered_site():
|
|
"""The module-level GLOSSARY content.py loads at import IS content_loader's
|
|
output — this just re-asserts the real file is well-formed and non-trivial,
|
|
since a broken content/glossary.yaml would already have failed every other
|
|
test at collection time (content.py loads it at import)."""
|
|
glossary = content_loader.load_glossary()
|
|
assert len(glossary) >= 8
|
|
assert "percentile" in glossary
|
|
for slug, entry in glossary.items():
|
|
assert entry["term"] and entry["short"] and entry["body"], slug
|
|
|
|
|
|
def test_real_pages_loads_the_four_static_pages():
|
|
pages = content_loader.load_pages()
|
|
assert set(pages) == {"about", "privacy", "hub", "glossary_index"}
|
|
for key, entry in pages.items():
|
|
assert entry["title"] and entry["description"], key
|