validator/ holds mewslint (lint, css, fetch, DTD/CSS data); directory/ holds the mews.page service (app, db, check, pages, cli) and depends on validator/; quickstart/ holds mews-quickstart and md2mews.py for third parties who want to create Mews content without cloning the repo; spec/ consolidates doc/ and dtd/ with the canonical mews-0.1.css; site/ becomes a Pelican project with the forward-facing pages as Markdown, the check form kept as a raw HTML snippet. Root pyproject.toml is now a virtual uv workspace over validator, directory and quickstart, with cross-cutting tests that span more than one of them staying at the repo root. Makefile and flake.nix updated to match.
78 lines
2.8 KiB
Python
78 lines
2.8 KiB
Python
"""The scaffold: it has to produce a project that builds conforming pages."""
|
|
|
|
import shutil
|
|
import subprocess
|
|
|
|
import pytest
|
|
|
|
from mews.lint import validate_file
|
|
from quickstart import main, scaffold
|
|
|
|
EXPECTED = [
|
|
"pyproject.toml",
|
|
"pelicanconf.py",
|
|
"content/first-post.md",
|
|
"theme/templates/base.html",
|
|
"theme/templates/index.html",
|
|
"theme/templates/article.html",
|
|
"theme/templates/page.html",
|
|
"README.md",
|
|
]
|
|
|
|
|
|
def test_it_writes_a_whole_project(tmp_path):
|
|
scaffold(tmp_path / "site", "Signal Bars", "Tobias")
|
|
for name in EXPECTED:
|
|
assert (tmp_path / "site" / name).is_file(), name
|
|
|
|
|
|
def test_the_settings_are_valid_python(tmp_path):
|
|
scaffold(tmp_path / "site", "Signal Bars", "Tobias")
|
|
settings: dict = {}
|
|
exec(
|
|
compile((tmp_path / "site" / "pelicanconf.py").read_text(), "c", "exec"),
|
|
settings,
|
|
)
|
|
assert settings["SITENAME"] == "Signal Bars"
|
|
assert settings["PLUGINS"] == ["pelican.plugins.mews"]
|
|
# A site that is Mews throughout writes plain .html: servers send that as
|
|
# text/html (section 7.1) and index.html is the directory index everywhere.
|
|
# The suffix the plugin acts on has to agree with where pages are saved.
|
|
assert settings["MEWS_SUFFIX"] == ".html"
|
|
assert settings["ARTICLE_SAVE_AS"].endswith(".html")
|
|
assert settings["PAGE_SAVE_AS"].endswith(".html")
|
|
# Pelican falls back to its own HTML for any direct template the theme
|
|
# lacks, and with .html the plugin would choke on it.
|
|
assert settings["DIRECT_TEMPLATES"] == ["index"]
|
|
assert settings["MARKDOWN"]["output_format"] == "xhtml"
|
|
|
|
|
|
def test_it_refuses_a_directory_with_something_in_it(tmp_path, capsys):
|
|
(tmp_path / "site").mkdir()
|
|
(tmp_path / "site" / "keep.txt").write_text("mine")
|
|
assert main([str(tmp_path / "site"), "--no-install"]) == 1
|
|
assert (tmp_path / "site" / "keep.txt").read_text() == "mine"
|
|
|
|
|
|
@pytest.mark.skipif(shutil.which("uv") is None, reason="uv is not installed")
|
|
@pytest.mark.slow
|
|
def test_the_scaffolded_site_builds_conforming_pages(tmp_path):
|
|
"""The whole point: pelican runs and what it writes passes the validator."""
|
|
site = tmp_path / "site"
|
|
assert main([str(site), "--title", "Signal Bars"]) == 0
|
|
built = subprocess.run(
|
|
[shutil.which("uv"), "run", "pelican", "content"],
|
|
cwd=site,
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
assert built.returncode == 0, built.stderr
|
|
pages = sorted((site / "output").glob("*.html"))
|
|
assert [p.name for p in pages] == ["first-post.html", "index.html"]
|
|
for page in pages:
|
|
report = validate_file(str(page))
|
|
assert report.conforms, "\n".join(str(f) for f in report.failures)
|
|
# Section 6.1: the index has to be subscribable.
|
|
index = (site / "output" / "index.html").read_text()
|
|
assert '<li><a href="first-post.html">' in index
|