Zum Inhalt

pipeline/tests/test_doctor.py

# SPDX-License-Identifier: AGPL-3.0-or-later

"""Doctor: aggregation and required/optional handling."""

from __future__ import annotations

from pathlib import Path

from autosplat.config import load_config
from autosplat.doctor import CheckResult, _check_supersplat, all_required_passed, run_doctor

# ─── Helpers ─────────────────────────────────────────────────────────────────


def _make_minimal_config(tmp_path: Path, *, viewer_target: str = "supersplat"):
    """Return a minimal Config with the given viewer target and default dist path."""
    user = tmp_path / "config.toml"
    user.write_text(
        f'[viewer]\ntarget = "{viewer_target}"\n',
        encoding="utf-8",
    )
    return load_config(user_config_path=user, include_xdg=False)


def make_config_with_supersplat_local(*, dist_path: Path, tmp_path: Path):
    """Return a Config with target=supersplat-local and the given dist path."""
    user = tmp_path / "config.toml"
    user.write_text(
        f'[viewer]\ntarget = "supersplat-local"\nsupersplat_dist_path = "{dist_path}"\n',
        encoding="utf-8",
    )
    return load_config(user_config_path=user, include_xdg=False)


def test_all_required_passed_true() -> None:
    results = [
        CheckResult(name="a", ok=True, detail="x", required=True),
        CheckResult(name="b", ok=False, detail="y", required=False),
    ]
    assert all_required_passed(results) is True


def test_all_required_passed_false() -> None:
    results = [
        CheckResult(name="a", ok=True, detail="x", required=True),
        CheckResult(name="b", ok=False, detail="y", required=True),
    ]
    assert all_required_passed(results) is False


def test_status_emoji_ok() -> None:
    r = CheckResult(name="a", ok=True, detail="x")
    assert r.status_emoji == "OK"


def test_status_emoji_missing_required() -> None:
    r = CheckResult(name="a", ok=False, detail="x", required=True)
    assert r.status_emoji == "MISSING"


def test_status_emoji_missing_optional() -> None:
    r = CheckResult(name="a", ok=False, detail="x", required=False)
    assert r.status_emoji == "WARN"


# ─── _check_supersplat ────────────────────────────────────────────────────────


def test_check_supersplat_ok(tmp_path: Path) -> None:
    """dist/index.html exists → OK."""
    dist = tmp_path / "dist"
    dist.mkdir()
    (dist / "index.html").write_text("<html/>")
    cfg = make_config_with_supersplat_local(dist_path=dist, tmp_path=tmp_path)
    result = _check_supersplat(cfg)
    assert result is not None
    assert result.ok is True
    assert result.name == "supersplat"


def test_check_supersplat_warn_missing(tmp_path: Path) -> None:
    """dist/index.html missing → WARN (not required)."""
    dist = tmp_path / "dist"
    # don't create dist
    cfg = make_config_with_supersplat_local(dist_path=dist, tmp_path=tmp_path)
    result = _check_supersplat(cfg)
    assert result is not None
    assert result.ok is False
    assert result.required is False
    assert "setup_supersplat.sh" in result.detail


def test_check_supersplat_skipped_for_remote_target(tmp_path: Path) -> None:
    """target=supersplat (remote) → returns None (check skipped)."""
    cfg = _make_minimal_config(tmp_path, viewer_target="supersplat")
    result = _check_supersplat(cfg)
    assert result is None


# ─── _check_outputs_copy ──────────────────────────────────────────────────────


def test_doctor_warns_when_copy_to_outputs_enabled() -> None:
    cfg = load_config(include_xdg=False)
    cfg.export.copy_to_outputs = True

    entry = next(r for r in run_doctor(cfg) if r.name == "outputs-copy")

    assert not entry.ok
    assert not entry.required  # a deprecation must never block a run
    assert "deprecated" in entry.detail.lower()


def test_doctor_passes_when_copy_to_outputs_disabled() -> None:
    cfg = load_config(include_xdg=False)

    entry = next(r for r in run_doctor(cfg) if r.name == "outputs-copy")

    assert entry.ok