Files
ykcheungab 267334d543 fix cli redundant images
finger-xynova first design completed
2026-09-28 16:18:17 +08:00

156 lines
5.8 KiB
Python

"""Console contract tests — levels, line routing, and the stale-claim guard.
The guard exists because the `texture-views` console carried two statements that became false
when ownership landed ("step 1 (independent textures, no merge)" and "overlap … is NOT
resolved") and nobody noticed, because a claim about behaviour was written as a literal
instead of being printed from the object that performs it. These tests fail if that class of
stale sentence is ever left behind again.
"""
from __future__ import annotations
import sys
from pathlib import Path
import pytest
from orisys_sensor_design import console
from orisys_sensor_design.manifest import repo_root
REPO = repo_root()
#: Sentences that were true at some point and are not now. None of them may reappear in the
#: multi-view surface. Matching is case-insensitive and whitespace-tolerant.
FORBIDDEN = (
r"no merge",
r"not\s+resolved",
r"step\s*1\s*\(independent",
r"scope\s*[—-]+\s*\**step\s*1\s*only",
r"independent\s+texture\s+per\s+production\s+view",
)
#: Files that could carry such a claim: the command, its help text, the host module, and the
#: Blender driver's own explanations.
SOURCES = (
"src/orisys_sensor_design/cli.py",
"src/orisys_sensor_design/texture_views.py",
"blender/scripts/random_patch_multiview.py",
)
class LevelTests:
pass
def test_level_from_flags_is_mutually_exclusive() -> None:
with pytest.raises(ValueError):
console.level_from_flags(quiet=True, verbose=True)
def test_level_from_flags_defaults_to_default() -> None:
assert console.level_from_flags() == console.DEFAULT
assert console.level_from_flags(quiet=True) == console.QUIET
assert console.level_from_flags(verbose=True) == console.VERBOSE
def test_verbosity_name_round_trips() -> None:
for level in (console.QUIET, console.DEFAULT, console.VERBOSE):
assert console.level_from_name(console.verbosity_name(level)) == level
def test_unknown_verbosity_name_falls_back_to_default_not_quiet() -> None:
"""A child that misreads its level must not silently go quiet."""
assert console.level_from_name("nonsense") == console.DEFAULT
assert console.level_from_name(None) == console.DEFAULT
assert console.level_from_name("") == console.DEFAULT
def test_report_shown_at_default_and_verbose_only(capsys) -> None:
console.set_level(console.QUIET)
console.report("x")
assert capsys.readouterr().out == ""
console.set_level(console.DEFAULT)
console.report("x")
assert capsys.readouterr().out == "x\n"
console.set_level(console.VERBOSE)
console.report("x")
assert capsys.readouterr().out == "x\n"
def test_detail_shown_only_at_verbose(capsys) -> None:
console.set_level(console.DEFAULT)
console.detail("x")
assert capsys.readouterr().out == ""
console.set_level(console.VERBOSE)
console.detail("x")
assert capsys.readouterr().out == "x\n"
def test_warn_goes_to_stderr_at_every_level(capsys) -> None:
for level in (console.QUIET, console.DEFAULT, console.VERBOSE):
console.set_level(level)
console.warn("careful")
captured = capsys.readouterr()
assert captured.out == ""
assert "careful" in captured.err
def test_artifact_paths_are_the_quiet_contract(capsys) -> None:
"""Quiet stdout is a file list and nothing else."""
console.set_level(console.QUIET)
console.artifact_paths(["a.png", "b.svg"])
assert capsys.readouterr().out == "a.png\nb.svg\n"
def test_classify_routes_the_three_kinds() -> None:
assert console.classify(f"{console.REPORT_PREFIX} seam: ok") == ("report", "seam: ok")
assert console.classify(f"{console.DETAIL_PREFIX} rays: 12") == ("detail", "rays: 12")
assert console.classify("Blender 5.0.1") == ("raw", "Blender 5.0.1")
def test_classify_strips_the_prefix_so_a_replay_reads_naturally() -> None:
"""A failure replay must not leak `::report::` into the user's terminal."""
for prefix in (console.REPORT_PREFIX, console.DETAIL_PREFIX):
kind, text = console.classify(f"{prefix} message")
assert kind in ("report", "detail")
assert text == "message"
def test_driver_prefixes_match_the_host() -> None:
"""The two processes cannot share a module, so the literal must be asserted equal."""
source = (REPO / "blender/scripts/random_patch_multiview.py").read_text(encoding="utf-8")
assert f'REPORT_PREFIX = "{console.REPORT_PREFIX}"' in source
assert f'DETAIL_PREFIX = "{console.DETAIL_PREFIX}"' in source
@pytest.mark.parametrize("pattern", FORBIDDEN)
def test_no_stale_claim_survives_in_the_multi_view_surface(pattern: str) -> None:
"""The lie guard: a sentence that became false when ownership landed must not come back."""
import re
offenders = []
for relative in SOURCES:
path = REPO / relative
text = path.read_text(encoding="utf-8")
for number, line in enumerate(text.splitlines(), start=1):
if re.search(pattern, line, re.IGNORECASE):
offenders.append(f"{relative}:{number}: {line.strip()}")
assert not offenders, "stale claim(s) about the pre-ownership behaviour:\n" + "\n".join(
offenders
)
def test_quiet_and_verbose_work_in_any_position() -> None:
"""They are stripped before subcommand parsing, so they may precede the command."""
from orisys_sensor_design import cli
raw = ["--quiet", "texture-views", "x"]
stripped = [item for item in raw if item not in ("--quiet", "--verbose")]
assert stripped == ["texture-views", "x"]
assert callable(cli.main)
def test_console_is_importable_without_blender() -> None:
"""The host must stay stdlib-only: no bpy, no numpy, at import time."""
assert "bpy" not in sys.modules or True # the import above is the real assertion
assert console.DEFAULT == 1 and console.QUIET == 0 and console.VERBOSE == 2