nexa / tests /test_presentation.py
DBax127's picture
Claude Opus 5
tests: pytest suite seeded from the fixed defects
c1f3d83
Raw History Blame Contribute Delete
3.9 kB
"""present(): the boundary where a bin/ tool's plain output gets the house style.
The tools print flush-left ASCII so they stay greppable and pipe-friendly when
run directly; presentation belongs to the CLI. That split is only safe if the
boundary is exact, which is what these assert.
Colour constants are empty unless stdout is a terminal, so each test that cares
about colour substitutes sentinels for them.
"""
import pytest
import nexa
@pytest.fixture()
def tint(monkeypatch):
"""Sentinel colours, so a test can assert which one was chosen."""
for name, value in (("GREEN", "<G>"), ("RED", "<R>"), ("AMBER", "<A>"),
("GREY", "<g>"), ("WHITE", "<W>"), ("DIM", "<D>"),
("RESET", "<0>")):
monkeypatch.setattr(nexa, name, value)
monkeypatch.setattr(nexa, "HBAR", "-")
monkeypatch.setattr(nexa, "TICK", "+")
monkeypatch.setattr(nexa, "CROSS", "x")
monkeypatch.setattr(nexa, "BANG", "!")
def test_blank_lines_collapse_to_empty():
assert nexa.present("") == ""
assert nexa.present(" \t ") == ""
def test_body_is_indented_under_the_banner():
assert nexa.present("32 rules").startswith(" ")
def test_relative_indentation_is_preserved():
"""A tool's own nesting still has to read as nesting after the shift."""
outer = nexa.present("Decided by an AST pass:")
inner = nexa.present(" [critical] odoo.prefer-sql-constraint")
assert len(inner) - len(inner.lstrip()) > len(outer) - len(outer.lstrip())
def test_a_line_that_already_has_escapes_is_untouched():
"""Otherwise the CLI would restyle its own already-styled output."""
line = "\033[38;5;51mstyled by the tool itself\033[0m"
assert nexa.present(line) == line
def test_ascii_separator_becomes_the_house_rule(tint):
out = nexa.present("----------------------------------------")
assert out == " <D>" + "-" * 66 + "<0>"
def test_short_dashes_are_not_a_separator(tint):
"""A hyphenated word is not a horizontal rule."""
assert "-" * 66 not in nexa.present("a - b")
@pytest.mark.parametrize("line,expected", [
("PASS: 32 rules valid", "<G>"),
("OK everything", "<G>"),
("FAIL: 2 problems", "<R>"),
("ERROR: broken", "<R>"),
("WARN: something", "<A>"),
("Rules retrieved:", "<A>"),
("Findings", "<A>"),
(" 0.586 [high] odoo.prefer-sql-constraint", "<g>"),
])
def test_colour_selection(tint, line, expected):
assert nexa.present(line).startswith(" " + expected)
def test_severity_tags_are_tinted_inside_a_grey_line(tint):
out = nexa.present(" [critical] odoo.prefer-sql-constraint")
assert "<R>[critical]<0>" in out
# ------------------------------------------------------------- code fences
def test_fence_markers_are_dimmed(tint):
assert nexa.present("```python").startswith(" <D>")
def test_code_inside_a_fence_is_white(tint):
assert nexa.present(" rec.qty = 1", in_code=True).startswith(" <W>")
def test_a_def_inside_a_fence_is_not_a_heading(tint):
"""It ends with a colon at the margin, which is the prose heading rule.
Inside a fence that rule must not apply, or every function signature in
every answer turns amber."""
assert nexa.present("def _check_quantity(self):", in_code=True).startswith(" <W>")
def test_a_def_outside_a_fence_is_not_treated_as_a_heading_either(tint):
"""The heading rule requires no colon anywhere, or a trailing colon on a
short line; a signature has parentheses and is long."""
out = nexa.present("def _check_quantity(self):")
assert out.startswith(" <A>") or out.startswith(" <g>")
def test_severity_tags_are_left_alone_inside_code(tint):
"""Code is code. Rewriting a bracketed word inside a fenced block would
corrupt the answer being displayed."""
out = nexa.present("x = data['[critical]']", in_code=True)
assert "<R>" not in out