Newer
Older
navi-1 / tests / clients / test_code_theme.py
"""Single-point-of-assignment guard for the TUI syntax-highlighting scheme.

All code rendered in the Navi Code TUI — markdown fenced blocks, code
artifacts, and the filesystem ``read`` tool output — must resolve its
Pygments style from one place: ``Theme.code_theme``. These tests pin that
contract so a future renderer cannot silently re-introduce a hard-coded
``dracula``/``github-light`` copy.
"""

from __future__ import annotations

from pygments.styles import get_style_by_name
from rich.syntax import Syntax

from clients.terminal.tui.renderers.artifact import ArtifactRenderer
from clients.terminal.tui.renderers.filesystem import FilesystemToolResultRenderer
from clients.terminal.tui.renderers.markdown_content import _theme_aware_code_theme
from clients.terminal.tui.renderers.syntax import highlight_code
from clients.terminal.tui.themes import (
    GNEXUS_DARK,
    GNEXUS_LIGHT,
    ThemeRegistry,
    get_active_theme,
    set_active_theme,
)


def _pygments_style_name(syntax: Syntax) -> str:
    """The Pygments style class name backing a rich Syntax renderable."""
    return syntax._theme._pygments_style_class.__name__  # type: ignore[attr-defined]


def test_theme_code_theme_is_a_real_pygments_style() -> None:
    for theme in (GNEXUS_DARK, GNEXUS_LIGHT):
        # The configured name resolves to a real Pygments style (no raise),
        # and dark/light pick distinct schemes.
        get_style_by_name(theme.code_theme)
    assert GNEXUS_DARK.code_theme != GNEXUS_LIGHT.code_theme


def test_markdown_code_theme_resolver_reads_from_theme() -> None:
    for name in ("gnexus-dark", "gnexus-light"):
        assert _theme_aware_code_theme(name) == ThemeRegistry.get(name).code_theme


def test_highlight_code_uses_theme_code_theme() -> None:
    set_active_theme("gnexus-dark")
    theme = get_active_theme()
    syntax = highlight_code("x = 1\n", "python", theme=theme, line_numbers=True)
    assert _pygments_style_name(syntax) == get_style_by_name(theme.code_theme).__name__


def test_artifact_renderer_uses_theme_code_theme() -> None:
    set_active_theme("gnexus-dark")
    theme = get_active_theme()
    panel = ArtifactRenderer().render(
        {
            "type": "artifact",
            "path": "a.py",
            "language": "python",
            "content": "x = 1\n",
        }
    )
    syntax = panel.renderable
    assert isinstance(syntax, Syntax)
    assert _pygments_style_name(syntax) == get_style_by_name(theme.code_theme).__name__


def test_filesystem_read_uses_theme_code_theme() -> None:
    set_active_theme("gnexus-dark")
    theme = get_active_theme()
    panel = FilesystemToolResultRenderer().render(
        {
            "type": "tool_call",
            "tool": "filesystem",
            "args": {"action": "read", "path": "a.py"},
            "result": "[a.py  |  1 lines  |  7B]\n1: x = 1\n",
            "success": True,
        }
    )
    group = panel.renderable
    syntax = next(r for r in group.renderables if isinstance(r, Syntax))
    assert _pygments_style_name(syntax) == get_style_by_name(theme.code_theme).__name__


def test_light_theme_uses_light_code_scheme() -> None:
    set_active_theme("gnexus-light")
    theme = get_active_theme()
    dark = highlight_code("x = 1\n", "python", theme=GNEXUS_DARK, line_numbers=True)
    light = highlight_code("x = 1\n", "python", theme=theme, line_numbers=True)
    # Same code, different theme field -> different Pygments style class.
    assert _pygments_style_name(dark) != _pygments_style_name(light)
    assert _pygments_style_name(light) == get_style_by_name(GNEXUS_LIGHT.code_theme).__name__
    set_active_theme("gnexus-dark")