"""Supercharge tests for ``muse read-commit``. Coverage tiers -------------- - Unit: _short_id helper — prefix preservation, hex length - Integration: duration_ms + exit_code in JSON; text short-ID format - Data integrity: sha256: prefix on all ID fields; valid JSON output - Edge cases: --fields empty/duplicate; HEAD~N beyond depth; unknown branch - Merge: parent2_commit_id in output - Performance: single read under threshold """ from __future__ import annotations import datetime import json import pathlib import re import time import pytest from muse.core.errors import ExitCode from muse.core.ids import hash_commit as compute_commit_id, hash_snapshot as compute_snapshot_id from muse.core.commits import ( CommitRecord, write_commit, ) from muse.core.snapshots import ( SnapshotRecord, write_snapshot, ) from tests.cli_test_helper import CliRunner, InvokeResult from muse.core.types import fake_id, long_id, split_id from muse.core.paths import heads_dir, muse_dir runner = CliRunner() _SNAP_ID: str = compute_snapshot_id({}) _COMMITTED_AT: datetime.datetime = datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc) _SHA256_FULL = re.compile(r"^sha256:[0-9a-f]{64}$") _SHA256_SHORT_19 = re.compile(r"^sha256:[0-9a-f]{12}$") # "sha256:" (7) + 12 hex = 19 chars # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- def _make_repo(tmp_path: pathlib.Path) -> pathlib.Path: repo = tmp_path / "repo" dot_muse = muse_dir(repo) for sub in ("objects", "commits", "snapshots", "refs/heads"): (dot_muse / sub).mkdir(parents=True) (dot_muse / "HEAD").write_text("ref: refs/heads/main") (dot_muse / "repo.json").write_text(json.dumps({"repo_id": "test-repo", "domain": "code"})) return repo def _commit( repo: pathlib.Path, *, branch: str = "main", message: str = "test commit", author: str = "tester", parent: str | None = None, parent2: str | None = None, agent_id: str = "", model_id: str = "", snap_id: str | None = None, committed_at: datetime.datetime | None = None, ) -> str: """Write a commit with a real content-addressed ID; return the commit_id.""" sid = snap_id or _SNAP_ID ts = committed_at or _COMMITTED_AT parent_ids: list[str] = [p for p in (parent, parent2) if p] commit_id = compute_commit_id( parent_ids=parent_ids, snapshot_id=sid, message=message, committed_at_iso=ts.isoformat(), author=author, ) write_snapshot(repo, SnapshotRecord( snapshot_id=sid, manifest={}, created_at=ts, )) rec = CommitRecord( commit_id=commit_id, branch=branch, snapshot_id=sid, message=message, committed_at=ts, author=author, parent_commit_id=parent, parent2_commit_id=parent2, agent_id=agent_id, model_id=model_id, ) write_commit(repo, rec) return commit_id def _rc(repo: pathlib.Path, *args: str) -> InvokeResult: from muse.cli.app import main as cli return runner.invoke( cli, ["read-commit", *args], env={"MUSE_REPO_ROOT": str(repo)}, ) def _rcj(repo: pathlib.Path, *args: str) -> InvokeResult: """Like _rc but always passes --json.""" return _rc(repo, "--json", *args) # --------------------------------------------------------------------------- # Unit — _short_id # --------------------------------------------------------------------------- class TestCommitIdFormat: """Text output must emit the full sha256:<64-hex> commit ID.""" def test_commit_id_keeps_sha256_prefix(self) -> None: cid = long_id("a" * 64) assert cid.startswith("sha256:") def test_commit_id_total_length_is_71(self) -> None: cid = long_id("c0ffee" * 11) assert len(cid[:71]) == 71 # sha256: (7) + 64 hex def test_full_id_matches_regex(self) -> None: cid = long_id("abcdef01" * 8) assert _SHA256_FULL.match(cid) # --------------------------------------------------------------------------- # Integration — duration_ms and exit_code in JSON output # --------------------------------------------------------------------------- class TestDurationAndExitCode: def test_duration_ms_present_on_success(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) cid = _commit(repo, message="timing test") data = json.loads(_rcj(repo, cid).output) assert "duration_ms" in data, "duration_ms must be present in JSON success output" def test_exit_code_zero_on_success(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) cid = _commit(repo, message="exit code test") data = json.loads(_rcj(repo, cid).output) assert data["exit_code"] == 0 def test_duration_ms_is_float(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) cid = _commit(repo, message="float timing") data = json.loads(_rcj(repo, cid).output) assert isinstance(data["duration_ms"], float) def test_duration_ms_non_negative(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) cid = _commit(repo, message="positive timing") data = json.loads(_rcj(repo, cid).output) assert data["duration_ms"] >= 0.0 def test_fields_filter_preserves_duration_ms(self, tmp_path: pathlib.Path) -> None: """duration_ms is command metadata, not a commit field — --fields must not drop it.""" repo = _make_repo(tmp_path) cid = _commit(repo, message="fields + duration") data = json.loads(_rcj(repo, "--fields", "commit_id,message", cid).output) assert "duration_ms" in data, "--fields must not filter out duration_ms" def test_fields_filter_preserves_exit_code(self, tmp_path: pathlib.Path) -> None: """exit_code is command metadata — --fields must not drop it.""" repo = _make_repo(tmp_path) cid = _commit(repo, message="fields + exit_code") data = json.loads(_rcj(repo, "--fields", "commit_id", cid).output) assert "exit_code" in data, "--fields must not filter out exit_code" def test_duration_ms_3dp_precision(self, tmp_path: pathlib.Path) -> None: """duration_ms must be rounded to 3 decimal places (millisecond precision).""" repo = _make_repo(tmp_path) cid = _commit(repo, message="precision test") data = json.loads(_rcj(repo, cid).output) ms = data["duration_ms"] # round-trips through json.dumps — check at most 3 decimal places assert round(ms, 3) == ms # --------------------------------------------------------------------------- # Integration — text format short ID # --------------------------------------------------------------------------- class TestTextFormatFullId: """Text format must emit the full sha256:<64-hex> (71 chars) commit ID.""" def _full_token(self, line: str) -> str | None: for tok in line.split(): if _SHA256_FULL.match(tok): return tok return None def test_text_full_id_has_sha256_prefix(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) cid = _commit(repo, message="full id prefix test") result = _rc(repo, cid) assert result.exit_code == 0 line = result.output.strip() tok = self._full_token(line) assert tok is not None, f"no sha256:<64-hex> token in text output: {line!r}" assert tok.startswith("sha256:") def test_text_full_id_has_64_hex_chars(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) cid = _commit(repo, message="full id hex length test") result = _rc(repo, cid) line = result.output.strip() tok = self._full_token(line) assert tok is not None, f"no sha256:<64-hex> token in text output: {line!r}" hex_part = tok[len("sha256:"):] assert len(hex_part) == 64, f"expected 64 hex chars after prefix, got {len(hex_part)}: {tok!r}" def test_text_full_id_total_length_is_71(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) cid = _commit(repo, message="full id length test") result = _rc(repo, cid) line = result.output.strip() tok = self._full_token(line) assert tok is not None assert len(tok) == 71, f"commit ID must be exactly 71 chars, got {len(tok)}: {tok!r}" def test_text_full_id_matches_commit_id(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) cid = _commit(repo, message="full id matches test") result = _rc(repo, cid) line = result.output.strip() tok = self._full_token(line) assert tok is not None assert tok == cid, f"text output ID {tok!r} does not match commit_id {cid!r}" # --------------------------------------------------------------------------- # Data integrity # --------------------------------------------------------------------------- class TestDataIntegrity: def test_commit_id_has_sha256_prefix(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) cid = _commit(repo, message="id prefix test") data = json.loads(_rcj(repo, cid).output) assert _SHA256_FULL.match(data["commit_id"]), \ f"commit_id must be sha256:<64hex>, got {data['commit_id']!r}" def test_snapshot_id_has_sha256_prefix(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) cid = _commit(repo, message="snapshot id test") data = json.loads(_rcj(repo, cid).output) assert _SHA256_FULL.match(data["snapshot_id"]), \ f"snapshot_id must be sha256:<64hex>, got {data['snapshot_id']!r}" def test_parent_commit_id_has_sha256_prefix(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) parent = _commit(repo, message="parent") child = _commit(repo, message="child", parent=parent) data = json.loads(_rcj(repo, child).output) assert _SHA256_FULL.match(data["parent_commit_id"]), \ f"parent_commit_id must be sha256:<64hex>, got {data['parent_commit_id']!r}" def test_json_output_is_valid_json(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) cid = _commit(repo, message="valid json test") result = _rcj(repo, cid) assert result.exit_code == 0 # Must not raise data = json.loads(result.output) assert isinstance(data, dict) def test_message_with_special_chars_in_json(self, tmp_path: pathlib.Path) -> None: """Control chars and quotes in message must not break JSON output.""" repo = _make_repo(tmp_path) # tab, backslash, double-quote — all must be escaped in JSON msg = 'feat: say "hello"\twith backslash \\' cid = _commit(repo, message=msg) result = _rcj(repo, cid) assert result.exit_code == 0 data = json.loads(result.output) assert data["message"] == msg def test_message_with_unicode_in_json(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) msg = "feat: 音楽 🎵 café naïve" cid = _commit(repo, message=msg) result = _rcj(repo, cid) assert result.exit_code == 0 data = json.loads(result.output) assert data["message"] == msg # --------------------------------------------------------------------------- # Edge cases — --fields # --------------------------------------------------------------------------- class TestFieldsEdgeCases: def test_fields_empty_string_errors(self, tmp_path: pathlib.Path) -> None: """--fields '' with no real field names should error (empty requested set).""" repo = _make_repo(tmp_path) cid = _commit(repo, message="empty fields test") result = _rc(repo, "--fields", "", cid) # Empty --fields is ambiguous — should either error or return only metadata. # At minimum the output must be valid JSON. assert result.exit_code == 0 or result.exit_code == ExitCode.USER_ERROR def test_fields_duplicate_deduplicated(self, tmp_path: pathlib.Path) -> None: """Duplicate field names in --fields must not crash and produce one key.""" repo = _make_repo(tmp_path) cid = _commit(repo, message="duplicate fields test") result = _rcj(repo, "--fields", "commit_id,commit_id,message", cid) assert result.exit_code == 0 data = json.loads(result.output) # Only one commit_id key, one message key assert "commit_id" in data assert "message" in data def test_fields_whitespace_only_errors(self, tmp_path: pathlib.Path) -> None: """--fields ' , ' (only whitespace/commas) should error.""" repo = _make_repo(tmp_path) cid = _commit(repo, message="whitespace fields test") result = _rc(repo, "--fields", " , ", cid) # Parts after strip are empty — should error assert result.exit_code == 0 or result.exit_code == ExitCode.USER_ERROR # --------------------------------------------------------------------------- # Edge cases — symbolic refs # --------------------------------------------------------------------------- class TestSymbolicRefEdgeCases: def test_head_tilde_exceeds_chain_depth_errors(self, tmp_path: pathlib.Path) -> None: """HEAD~99 on a 1-commit repo must exit with USER_ERROR, not crash.""" repo = _make_repo(tmp_path) cid = _commit(repo, branch="main", message="only commit") (heads_dir(repo) / "main").write_text(cid) result = _rc(repo, "HEAD~99") assert result.exit_code == ExitCode.USER_ERROR assert "Traceback" not in result.output def test_unknown_branch_name_errors(self, tmp_path: pathlib.Path) -> None: """A branch name that doesn't exist must exit USER_ERROR cleanly.""" repo = _make_repo(tmp_path) _commit(repo, message="root") result = _rc(repo, "nonexistent-branch-xyz") assert result.exit_code == ExitCode.USER_ERROR assert "Traceback" not in result.output # --------------------------------------------------------------------------- # Merge commit # --------------------------------------------------------------------------- class TestMergeCommit: def test_parent2_commit_id_in_json_output(self, tmp_path: pathlib.Path) -> None: """Merge commits must expose parent2_commit_id in JSON output.""" repo = _make_repo(tmp_path) p1 = _commit(repo, message="parent one") p2 = _commit(repo, message="parent two", committed_at=datetime.datetime(2026, 1, 2, tzinfo=datetime.timezone.utc)) merge = _commit(repo, message="merge commit", parent=p1, parent2=p2, committed_at=datetime.datetime(2026, 1, 3, tzinfo=datetime.timezone.utc)) data = json.loads(_rcj(repo, merge).output) assert data["parent_commit_id"] == p1 assert data["parent2_commit_id"] == p2 def test_parent2_has_sha256_prefix(self, tmp_path: pathlib.Path) -> None: repo = _make_repo(tmp_path) p1 = _commit(repo, message="p1") p2 = _commit(repo, message="p2", committed_at=datetime.datetime(2026, 1, 2, tzinfo=datetime.timezone.utc)) merge = _commit(repo, message="merge", parent=p1, parent2=p2, committed_at=datetime.datetime(2026, 1, 3, tzinfo=datetime.timezone.utc)) data = json.loads(_rcj(repo, merge).output) assert _SHA256_FULL.match(data["parent2_commit_id"]), \ f"parent2_commit_id must be sha256:<64hex>, got {data['parent2_commit_id']!r}" # --------------------------------------------------------------------------- # Performance # --------------------------------------------------------------------------- class TestPerformance: def test_single_read_under_500ms(self, tmp_path: pathlib.Path) -> None: """A single read-commit invocation must complete in under 500ms.""" repo = _make_repo(tmp_path) cid = _commit(repo, message="perf test") t0 = time.monotonic() result = _rc(repo, cid) duration_ms = (time.monotonic() - t0) * 1000 assert result.exit_code == 0 assert duration_ms < 500, f"read-commit took {duration_ms:.1f}ms — over 500ms threshold" def test_duration_ms_in_output_plausible(self, tmp_path: pathlib.Path) -> None: """duration_ms in the JSON output must be less than 500ms for a warm read.""" repo = _make_repo(tmp_path) cid = _commit(repo, message="plausible timing") data = json.loads(_rcj(repo, cid).output) assert data["duration_ms"] < 500, \ f"duration_ms={data['duration_ms']} — suspiciously slow or not measuring correctly" class TestRegisterFlags: def _parse(self, *args: str) -> "argparse.Namespace": import argparse from muse.cli.commands.read_commit import register p = argparse.ArgumentParser() subs = p.add_subparsers() register(subs) return p.parse_args(["read-commit", fake_id("a"), *args]) def test_json_short_flag(self) -> None: args = self._parse("-j") assert args.json_out is True def test_json_long_flag(self) -> None: args = self._parse("--json") assert args.json_out is True def test_default_no_json(self) -> None: args = self._parse() assert args.json_out is False