"""muse#53 item 9 -- `muse symlog show "file.py::Symbol@{N}"`. Convenience alias for `muse code cat "addr@{N}"` with a human-focused header (operation, author, timestamp) printed before the full symbol body. """ from __future__ import annotations import json import os import pathlib import textwrap from tests.cli_test_helper import CliRunner runner = CliRunner() def _invoke(repo: pathlib.Path, args: list[str]): saved = os.getcwd() try: os.chdir(repo) return runner.invoke(None, args) finally: os.chdir(saved) def _init_repo(repo: pathlib.Path) -> None: repo.mkdir(parents=True, exist_ok=True) _invoke(repo, ["init"]) def _write_file(repo: pathlib.Path, rel: str, content: str) -> None: p = repo / rel p.parent.mkdir(parents=True, exist_ok=True) p.write_text(textwrap.dedent(content)) def _commit(repo: pathlib.Path, msg: str, author: str = "claude-code") -> str: _invoke(repo, ["code", "add", "."]) result = _invoke(repo, [ "commit", "-m", msg, "--agent-id", "claude-code", "--model-id", "claude-sonnet-4-6", "--author", author, "--json", ]) data = json.loads(result.stdout) return data["commit_id"] def _make_repo(tmp_path: pathlib.Path) -> pathlib.Path: _init_repo(tmp_path) return tmp_path def _symlog(repo: pathlib.Path, *args: str): return _invoke(repo, ["symlog", *args]) class TestSymlogShow: def test_show_returns_body_and_metadata(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) _write_file(repo, "src/billing.py", "def compute_total(items):\n return sum(items)\n") _commit(repo, "add compute_total") result = _symlog(repo, "show", "src/billing.py::compute_total@{0}", "--json") assert result.exit_code == 0, result.stdout data = json.loads(result.stdout) assert data["symbol"] == "src/billing.py::compute_total" assert data["index"] == 0 assert data["author"] == "claude-code" assert data["operation"].startswith("symbol-created") assert data["source"] is not None assert "def compute_total" in data["source"] def test_show_at_older_index_returns_older_body(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) _write_file(repo, "src/billing.py", "def compute_total(items):\n return sum(items)\n") _commit(repo, "add compute_total") _write_file(repo, "src/billing.py", "def compute_total(items):\n return sum(items) + 1\n") _commit(repo, "fix off-by-one") newest = json.loads(_symlog(repo, "show", "src/billing.py::compute_total@{0}", "--json").stdout) oldest = json.loads(_symlog(repo, "show", "src/billing.py::compute_total@{1}", "--json").stdout) assert "+ 1" in newest["source"] assert "+ 1" not in oldest["source"] def test_show_missing_symbol_errors(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) result = _symlog(repo, "show", "src/billing.py::nonexistent@{0}", "--json") assert result.exit_code == 1 def test_show_out_of_range_index_errors(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) _write_file(repo, "src/billing.py", "def compute_total(items):\n return sum(items)\n") _commit(repo, "add") result = _symlog(repo, "show", "src/billing.py::compute_total@{5}", "--json") assert result.exit_code == 1 def test_show_invalid_ref_form_errors(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) result = _symlog(repo, "show", "src/billing.py::compute_total", "--json") assert result.exit_code == 1 def test_show_text_mode_prints_header_and_body(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) _write_file(repo, "src/billing.py", "def compute_total(items):\n return sum(items)\n") _commit(repo, "add compute_total") result = _symlog(repo, "show", "src/billing.py::compute_total@{0}") assert result.exit_code == 0, result.stdout assert "author:" in result.stdout assert "def compute_total" in result.stdout