Files
cleveragents-core/robot/helper_output_rendering.py

168 lines
5.6 KiB
Python

"""Robot Framework helper for output rendering end-to-end tests."""
from __future__ import annotations
import json
import re
import sys
from pathlib import Path
import yaml
# Ensure the local source tree is importable
_SRC = str(Path(__file__).resolve().parents[1] / "src")
if _SRC not in sys.path:
sys.path.insert(0, _SRC)
from cleveragents.cli.formatting import format_output # noqa: E402
from cleveragents.cli.output.materializers import ( # noqa: E402
ColorMaterializer,
JsonMaterializer,
PlainMaterializer,
RichMaterializer,
TableMaterializer,
YamlMaterializer,
)
from cleveragents.cli.output.selection import ( # noqa: E402
TerminalCapabilities,
select_materializer,
)
from cleveragents.cli.output.session import OutputSession # noqa: E402
ANSI_RE = re.compile(r"\033\[")
def test_plain_panel() -> None:
"""Plain format renders panel without ANSI codes."""
strategy = PlainMaterializer()
with OutputSession(format="plain", command="test", strategy=strategy) as session:
panel = session.panel("Project Info")
panel.set_entry("Name", "my-project")
panel.set_entry("Version", "1.0.0")
panel.close()
output = strategy.get_output()
assert "Project Info" in output
assert "Name: my-project" in output
assert not ANSI_RE.search(output), "Plain output should not contain ANSI codes"
print("output-rendering-plain-panel-ok")
def test_json_output() -> None:
"""JSON format produces valid JSON with elements."""
strategy = JsonMaterializer()
with OutputSession(format="json", command="test", strategy=strategy) as session:
panel = session.panel("Details")
panel.set_entry("Key", "Value")
panel.close()
table = session.table(columns=["Col1", "Col2"])
table.add_row({"Col1": "a", "Col2": "b"})
table.close()
output = strategy.get_output()
data = json.loads(output)
assert "elements" in data
assert len(data["elements"]) == 2
print("output-rendering-json-output-ok")
def test_yaml_output() -> None:
"""YAML format produces valid YAML with elements."""
strategy = YamlMaterializer()
with OutputSession(format="yaml", command="test", strategy=strategy) as session:
panel = session.panel("YAML Details")
panel.set_entry("Alpha", "Beta")
panel.close()
output = strategy.get_output()
data = yaml.safe_load(output)
assert "elements" in data
print("output-rendering-yaml-output-ok")
def test_table_boxdraw() -> None:
"""Table format uses ASCII box-drawing characters."""
strategy = TableMaterializer()
with OutputSession(format="table", command="test", strategy=strategy) as session:
table = session.table(columns=["Name", "Status"])
table.add_row({"Name": "svc", "Status": "up"})
table.close()
output = strategy.get_output()
assert "|" in output or "+" in output, "Table output should contain box chars"
assert "svc" in output
print("output-rendering-table-boxdraw-ok")
def test_color_ansi() -> None:
"""Color format includes ANSI escape codes."""
strategy = ColorMaterializer()
with OutputSession(format="color", command="test", strategy=strategy) as session:
panel = session.panel("Coloured Title")
panel.set_entry("Key", "val")
panel.close()
output = strategy.get_output()
assert ANSI_RE.search(output), "Color output should contain ANSI codes"
print("output-rendering-color-ansi-ok")
def test_json_error() -> None:
"""Error envelope in JSON mode has correct structure."""
mat = JsonMaterializer()
output = mat.get_error_output("NOT_FOUND", "Item not found", {"id": "123"})
data = json.loads(output)
assert "error" in data
assert data["error"]["code"] == "NOT_FOUND"
assert data["error"]["message"] == "Item not found"
assert data["error"]["details"]["id"] == "123"
print("output-rendering-json-error-ok")
def test_backward_compat() -> None:
"""format_output still works for all formats."""
data = {"Name": "test-proj", "Status": "active"}
for fmt in ("json", "yaml", "plain", "table", "rich"):
result = format_output(data, fmt)
assert result, f"format_output({fmt}) returned empty"
print("output-rendering-backward-compat-ok")
def test_selection_fallback() -> None:
"""Materializer selection with fallback logic."""
no_tty = TerminalCapabilities(
is_tty=False, supports_ansi=False, supports_cursor=False, term=""
)
# Rich falls back to plain when no TTY
mat = select_materializer("rich", capabilities=no_tty)
assert isinstance(mat, PlainMaterializer)
# JSON always works
mat = select_materializer("json", capabilities=no_tty)
assert isinstance(mat, JsonMaterializer)
# Explicit overrides fallback
mat = select_materializer("rich", capabilities=no_tty, explicit=True)
assert isinstance(mat, RichMaterializer)
print("output-rendering-selection-fallback-ok")
_DISPATCH = {
"plain-panel": test_plain_panel,
"json-output": test_json_output,
"yaml-output": test_yaml_output,
"table-boxdraw": test_table_boxdraw,
"color-ansi": test_color_ansi,
"json-error": test_json_error,
"backward-compat": test_backward_compat,
"selection-fallback": test_selection_fallback,
}
if __name__ == "__main__":
if len(sys.argv) < 2:
print(f"Usage: {sys.argv[0]} <test-name>", file=sys.stderr)
sys.exit(1)
test_name = sys.argv[1]
if test_name not in _DISPATCH:
print(f"Unknown test: {test_name}", file=sys.stderr)
sys.exit(1)
_DISPATCH[test_name]()