gabriel / muse public
test_cmd_symlog_grep.py python
124 lines 4.5 KB
Raw
sha256:ce542c4d0f6dacc9520c02d0e3378bf96bc377d118a7402f2bbc8af1749b08e0 feat(code-test): audit cache internals, add cache_hit/--cac… Sonnet 5 minor ⚠ breaking 6 hours ago
1 """muse#53 item 8 -- `muse symlog grep PATTERN [--file path] [--json]`.
2
3 Searches symbol bodies across their full symlog history for PATTERN,
4 answering "when did this symbol last contain string X?"
5 """
6
7 from __future__ import annotations
8
9 import json
10 import os
11 import pathlib
12 import textwrap
13
14 from tests.cli_test_helper import CliRunner
15
16 runner = CliRunner()
17
18
19 def _invoke(repo: pathlib.Path, args: list[str]):
20 saved = os.getcwd()
21 try:
22 os.chdir(repo)
23 return runner.invoke(None, args)
24 finally:
25 os.chdir(saved)
26
27
28 def _init_repo(repo: pathlib.Path) -> None:
29 repo.mkdir(parents=True, exist_ok=True)
30 _invoke(repo, ["init"])
31
32
33 def _write_file(repo: pathlib.Path, rel: str, content: str) -> None:
34 p = repo / rel
35 p.parent.mkdir(parents=True, exist_ok=True)
36 p.write_text(textwrap.dedent(content))
37
38
39 def _commit(repo: pathlib.Path, msg: str) -> str:
40 _invoke(repo, ["code", "add", "."])
41 result = _invoke(repo, [
42 "commit", "-m", msg,
43 "--agent-id", "claude-code",
44 "--model-id", "claude-sonnet-4-6",
45 "--author", "claude-code",
46 "--json",
47 ])
48 data = json.loads(result.stdout)
49 return data["commit_id"]
50
51
52 def _make_repo(tmp_path: pathlib.Path) -> pathlib.Path:
53 _init_repo(tmp_path)
54 return tmp_path
55
56
57 def _symlog(repo: pathlib.Path, *args: str):
58 return _invoke(repo, ["symlog", *args])
59
60
61 class TestSymlogGrep:
62 def test_finds_pattern_in_current_body(self, tmp_path: pathlib.Path) -> None:
63 repo = _make_repo(tmp_path)
64 _write_file(repo, "src/billing.py", "def compute_total(items):\n # deprecated: use v2\n return sum(items)\n")
65 _commit(repo, "add compute_total")
66
67 result = _symlog(repo, "grep", "deprecated", "--json")
68 assert result.exit_code == 0, result.stdout
69 data = json.loads(result.stdout)
70 assert data["pattern"] == "deprecated"
71 assert data["count"] == 1
72 assert data["matches"][0]["symbol"] == "src/billing.py::compute_total"
73 assert data["matches"][0]["index"] == 0
74
75 def test_finds_pattern_only_in_older_version(self, tmp_path: pathlib.Path) -> None:
76 repo = _make_repo(tmp_path)
77 # A comment-only diff doesn't change the symbol's AST content_id (no
78 # new symlog entry is written), so use a real statement to ensure two
79 # distinct entries exist.
80 _write_file(repo, "src/billing.py", "def compute_total(items):\n marker = 'deprecated_v1'\n return sum(items)\n")
81 _commit(repo, "add compute_total")
82 _write_file(repo, "src/billing.py", "def compute_total(items):\n return sum(items)\n")
83 _commit(repo, "remove deprecated marker")
84
85 result = _symlog(repo, "grep", "deprecated", "--json")
86 data = json.loads(result.stdout)
87 assert data["count"] == 1
88 # @{1} is the older entry (newest-first indexing).
89 assert data["matches"][0]["index"] == 1
90
91 def test_no_match_returns_empty(self, tmp_path: pathlib.Path) -> None:
92 repo = _make_repo(tmp_path)
93 _write_file(repo, "src/billing.py", "def compute_total(items):\n return sum(items)\n")
94 _commit(repo, "add compute_total")
95
96 result = _symlog(repo, "grep", "nonexistent_token_xyz", "--json")
97 data = json.loads(result.stdout)
98 assert data["count"] == 0
99 assert data["matches"] == []
100
101 def test_case_insensitive_match(self, tmp_path: pathlib.Path) -> None:
102 repo = _make_repo(tmp_path)
103 _write_file(repo, "src/billing.py", "def compute_total(items):\n # DEPRECATED\n return sum(items)\n")
104 _commit(repo, "add compute_total")
105
106 result = _symlog(repo, "grep", "deprecated", "--json")
107 data = json.loads(result.stdout)
108 assert data["count"] == 1
109
110 def test_scoped_to_file(self, tmp_path: pathlib.Path) -> None:
111 repo = _make_repo(tmp_path)
112 _write_file(repo, "src/billing.py", "def compute_total(items):\n # TODO: refactor\n return sum(items)\n")
113 _write_file(repo, "src/other.py", "def unrelated():\n # TODO: refactor\n pass\n")
114 _commit(repo, "add two files")
115
116 result = _symlog(repo, "grep", "TODO", "--file", "src/billing.py", "--json")
117 data = json.loads(result.stdout)
118 assert data["count"] == 1
119 assert data["matches"][0]["symbol"] == "src/billing.py::compute_total"
120
121 def test_missing_pattern_errors(self, tmp_path: pathlib.Path) -> None:
122 repo = _make_repo(tmp_path)
123 result = _symlog(repo, "grep", "--json")
124 assert result.exit_code == 1
File History 1 commit
sha256:ce542c4d0f6dacc9520c02d0e3378bf96bc377d118a7402f2bbc8af1749b08e0 feat(code-test): audit cache internals, add cache_hit/--cac… Sonnet 5 minor ⚠ 6 hours ago