#!/usr/bin/env -S uv run --script
# /// script
# requires-python = ">=3.13"
# dependencies = ["pytest"]
# ///
"""
Tests for repo-web-view.py.
Each test drives the real CLI end-to-end via `uv run repo-web-view.py`, so the tool's
own inline dependencies are exercised exactly as a user would run them.
uv run tests/test_repo_web_view.py # self-contained (installs pytest via uv)
pytest tests/ # if pytest is already available
"""
import json, socket, subprocess, sys, time, urllib.request
from pathlib import Path
import pytest
SCRIPT = Path(__file__).resolve().parent.parent / "repo-web-view.py"
@pytest.fixture
def sample_repo(tmp_path):
src = tmp_path / "repo"
(src / "toolA").mkdir(parents=True)
(src / ".git").mkdir()
(src / "README.md").write_text("# Sample\n\nWelcome to **sample**. See [toolA](toolA/) and [notes](notes.txt).\n\n"
"Also [docs](docs.md#bit), [nested](toolA/README.md), [gone](missing.md) and "
"[remote](https://example.com/x.md).\n", encoding="utf-8")
(src / "docs.md").write_text("# Docs\n\nA standalone page, not a README.\n\n"
"## Deep\n\n" + "filler " * 60 + "needle-far-down\n", encoding="utf-8")
(src / "notes.txt").write_text("plain file\n", encoding="utf-8")
(src / "hook.php").write_text('\n', encoding="utf-8")
(src / ".git" / "config").write_text("secret\n", encoding="utf-8")
(src / "toolA" / "README.md").write_text("# toolA\n\n```python\nprint('hi')\n```\n", encoding="utf-8")
(src / "toolA" / "toolA.py").write_text("print('hi')\n", encoding="utf-8")
(src / "toolA" / "toolA.html").write_text("
toolA runs
", encoding="utf-8")
return src
def build(src, out, *extra):
return subprocess.run(["uv", "run", str(SCRIPT), str(src), str(out), "--force", *extra],
capture_output=True, text=True)
def footer_of(page):
return page.split("", 1)[0]
def listing_of(page):
return page.split('class="listing"', 1)[1].split("", 1)[0]
def search_index(out):
raw = (out / "search-index.js").read_text(encoding="utf-8")
assert raw.startswith("window.__rwvSearch = ")
return json.loads(raw[len("window.__rwvSearch = "):].rstrip().removesuffix(";"))
def test_generates_index_per_dir(sample_repo, tmp_path):
out = tmp_path / "site"
assert build(sample_repo, out).returncode == 0
assert (out / "index.html").is_file()
assert (out / "toolA" / "index.html").is_file()
def test_root_renders_readme_and_lists(sample_repo, tmp_path):
out = tmp_path / "site"
build(sample_repo, out)
page = (out / "index.html").read_text(encoding="utf-8")
assert " renders
assert 'href="notes.txt"' in page # file link (no slash) -> downloads
def test_dotfiles_excluded(sample_repo, tmp_path):
out = tmp_path / "site"
build(sample_repo, out)
assert not (out / ".git").exists()
assert ".git" not in (out / "index.html").read_text(encoding="utf-8")
def test_extra_exclude_glob(sample_repo, tmp_path):
out = tmp_path / "site"
build(sample_repo, out, "--exclude", "*.txt")
assert not (out / "notes.txt").exists()
def test_code_block_highlighted(sample_repo, tmp_path):
out = tmp_path / "site"
build(sample_repo, out)
assert 'class="hl' in (out / "toolA" / "index.html").read_text(encoding="utf-8")
def test_footer_note_stamped_on_every_page(sample_repo, tmp_path):
out = tmp_path / "site"
build(sample_repo, out, "--footer-note", "a95daf6", "--footer-note-url", "https://example.com/commit/a95daf6")
for page in (out / "index.html", out / "toolA" / "index.html"):
footer = footer_of(page.read_text(encoding="utf-8"))
assert 'a95daf6' in footer
def test_footer_note_without_url_is_plain_text(sample_repo, tmp_path):
out = tmp_path / "site"
build(sample_repo, out, "--footer-note", "a95daf6")
footer = footer_of((out / "index.html").read_text(encoding="utf-8"))
assert "a95daf6" in footer and "x", "--footer-note-url", 'https://e.com/"onx')
footer = footer_of((out / "index.html").read_text(encoding="utf-8"))
assert " and bold.\n", encoding="utf-8")
out = tmp_path / "site"
build(sample_repo, out, "--render-markdown")
evil = next(rec for rec in search_index(out)["pages"] if rec[0].startswith("evil.md.html"))
assert "