Ctrl K
ComunidadGuías…

tests/test_app_paths.py

Rama master · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
"""App submodules (apps/<name>) resolve the way the parent's own files do.

apps/README.md: an app mirrors the parent layout, and the parent's static
mount, template loader and sys.path all search the app dirs AFTER the
parent's. "After" only stays harmless while names never collide -- a clash is
decided silently by search order -- so these pin uniqueness, plus the two
loaders' order, plus the reload-walk guard (no node_modules under apps/).
"""
import os
import sys
from pathlib import Path

import pytest
from starlette.applications import Starlette
from starlette.staticfiles import StaticFiles
from starlette.testclient import TestClient

ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT / "api"))

import app_paths  # noqa: E402
import pages  # noqa: E402


def _apps():
    return [d for d in (ROOT / "apps").iterdir() if d.is_dir()] if (ROOT / "apps").is_dir() else []


def _names(d: Path, pattern: str) -> set[str]:
    """Served FILE paths relative to the dir (fonts/x.woff2): two repos may both
    have a fonts/ or vendor/ dir; only the same file path would clash."""
    if not d.is_dir():
        return set()
    return {p.relative_to(d).as_posix() for p in d.rglob(pattern)
            if p.is_file() and "__pycache__" not in p.parts}


def _modules(d: Path) -> set[str]:
    """Top-level importable names in an api dir: *.py stems + package dirs."""
    if not d.is_dir():
        return set()
    return {p.stem for p in d.glob("*.py")} | {
        p.name for p in d.iterdir() if p.is_dir() and (p / "__init__.py").exists()}


@pytest.mark.parametrize("rel,pattern", [("web", "*"), ("api/templates", "*.html")])
def test_no_file_name_in_both_parent_and_an_app(rel, pattern):
    seen = {n: "parent" for n in _names(ROOT / rel, pattern)}
    for app in _apps():
        for n in _names(app / rel, pattern):
            assert n not in seen, f"{rel}/{n} is in both {seen[n]} and {app.name}"
            seen[n] = app.name


def test_no_module_name_in_both_parent_and_an_app():
    seen = {n: "parent" for n in _modules(ROOT / "api")}
    for app in _apps():
        for n in _modules(app / "api"):
            assert n not in seen, f"module {n!r} is in both {seen[n]} and {app.name}"
            seen[n] = app.name


def test_no_node_modules_under_apps():
    """uvicorn --reload walks /app (incl. /app/apps) four times a second; a
    node_modules there is the nightfall-src CPU burn again (ARCHITECTURE §17e)."""
    for app in _apps():
        for dirpath, dirnames, _ in os.walk(app):
            assert "node_modules" not in dirnames, f"{dirpath}/node_modules"
            dirnames[:] = [d for d in dirnames if d != ".git"]


@pytest.fixture
def fake_apps(tmp_path, monkeypatch):
    parent_tmpl = tmp_path / "templates"
    parent_web = tmp_path / "static"
    app = tmp_path / "apps" / "demo"
    for d in (parent_tmpl, parent_web, app / "api" / "templates", app / "web"):
        d.mkdir(parents=True)
    monkeypatch.setattr(app_paths, "APPS_DIR", tmp_path / "apps")
    monkeypatch.setattr(pages, "_TMPL", parent_tmpl)
    return parent_tmpl, parent_web, app


def test_tmpl_finds_an_app_template_and_parent_wins(fake_apps):
    parent_tmpl, _, app = fake_apps
    (app / "api/templates/only-app.html").write_text("app")
    (app / "api/templates/both.html").write_text("app")
    (parent_tmpl / "both.html").write_text("parent")
    assert pages._tmpl("only-app.html") == "app"
    assert pages._tmpl("both.html") == "parent"
    with pytest.raises(FileNotFoundError):
        pages._tmpl("nowhere.html")


def test_static_mount_serves_app_web_after_parent(fake_apps):
    """The same construction as main.py's "/" mount."""
    _, parent_web, app = fake_apps
    (app / "web/only-app.js").write_text("app")
    (app / "web/both.js").write_text("app")
    (parent_web / "both.js").write_text("parent")
    static = StaticFiles(directory=str(parent_web), html=True)
    static.all_directories += [str(p) for p in app_paths.app_subdirs("web")]
    web = Starlette()
    web.mount("/", static)
    c = TestClient(web)
    assert c.get("/only-app.js").text == "app"
    assert c.get("/both.js").text == "parent"
    assert c.get("/nowhere.js").status_code == 404