import re import unittest import xml.etree.ElementTree as ET from render_terminal import redact_line, render_svg class RenderTerminalTest(unittest.TestCase): def test_svg_is_valid_xml_and_escapes_output(self): svg = render_svg( "& value\nsecond", command="printf '& value'", cwd="/shared/codebase/demo", exit_code=0, executed_at="2026-08-28T06:00:00Z", ) ET.fromstring(svg) self.assertIn("<tag>& value", svg) self.assertNotIn("& value", svg) def test_metadata_is_rendered(self): svg = render_svg( "BUILD SUCCESSFUL", command="./gradlew test", cwd="/shared/codebase/demo", exit_code=0, executed_at="2026-08-28T06:00:00Z", ) self.assertIn("./gradlew test", svg) self.assertIn("/shared/codebase/demo", svg) self.assertIn("exit 0", svg) self.assertIn("2026-08-28T06:00:00Z", svg) def test_obvious_secrets_are_redacted(self): cases = { "Authorization: Bearer abc.def.ghi": "Authorization: Bearer [REDACTED]", "TOKEN=super-secret": "TOKEN=[REDACTED]", "PASSWORD=hunter2": "PASSWORD=[REDACTED]", "client_secret: abc123": "client_secret: [REDACTED]", "Cookie: SESSION=abcdef": "Cookie: [REDACTED]", } for raw, expected in cases.items(): with self.subTest(raw=raw): self.assertEqual(expected, redact_line(raw)) def test_normal_output_is_not_changed_by_redaction(self): line = "GET /api/me -> 200 in 14ms" self.assertEqual(line, redact_line(line)) def test_truncation_marker_is_rendered_without_fabricating_hidden_lines(self): output = "\n".join(f"line-{i}" for i in range(8)) svg = render_svg( output, command="demo", cwd="/tmp", exit_code=1, executed_at="2026-08-28T06:00:00Z", max_lines=3, ) self.assertIn("line-0", svg) self.assertIn("line-2", svg) self.assertNotIn("line-3", svg) self.assertIn("[5 more lines omitted]", svg) def test_terminal_chrome_and_monospace_are_present(self): svg = render_svg( "ok", command="echo ok", cwd="/tmp", exit_code=0, executed_at="2026-08-28T06:00:00Z", ) self.assertGreaterEqual(len(re.findall(r"