"""Supercharge tests for ``muse merge-base``. Coverage tiers -------------- - JSON envelope: exit_code and duration_ms present on found and not-found outcomes - Error payload: errors go to stdout as JSON in --json mode, no dual stderr prose - Data integrity: symmetry (A,B)==(B,A); merge-commit as input; deep DAG - TypedDicts: _MergeBaseFoundJson and _MergeBaseErrorJson with required annotations - Docstring: module docstring covers exit_code and duration_ms - No-prose pollution: no emoji / prose leaks into JSON stdout - Stress: 100-commit linear chain resolves correctly """ from __future__ import annotations from collections.abc import Mapping import argparse import datetime import json import pathlib from typing import get_type_hints from muse.core.types import fake_id 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 muse.core.paths import head_path, muse_dir, ref_path from tests.cli_test_helper import CliRunner, InvokeResult runner = CliRunner() _DT = datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc) # --------------------------------------------------------------------------- # Helpers # --------------------------------------------------------------------------- def _init_repo(tmp_path: pathlib.Path) -> pathlib.Path: muse = muse_dir(tmp_path) for sub in ("objects", "commits", "snapshots", "refs/heads"): (muse / sub).mkdir(parents=True) (muse / "HEAD").write_text("ref: refs/heads/main", encoding="utf-8") (muse / "repo.json").write_text( json.dumps({"repo_id": "supercharge-test", "domain": "code"}), encoding="utf-8", ) return tmp_path def _env(root: pathlib.Path) -> Mapping[str, str]: return {"MUSE_REPO_ROOT": str(root)} def _snap(root: pathlib.Path) -> str: sid = compute_snapshot_id({}) write_snapshot(root, SnapshotRecord(snapshot_id=sid, manifest={}, created_at=_DT)) return sid def _commit( root: pathlib.Path, msg: str, *, parent: str | None = None, parent2: str | None = None, branch: str = "main", ) -> str: sid = _snap(root) parent_ids = [p for p in [parent, parent2] if p is not None] cid = compute_commit_id( parent_ids=parent_ids, snapshot_id=sid, message=msg, committed_at_iso=_DT.isoformat(), ) write_commit(root, CommitRecord( commit_id=cid, branch=branch, snapshot_id=sid, message=msg, committed_at=_DT, parent_commit_id=parent, parent2_commit_id=parent2, )) return cid def _set_branch(root: pathlib.Path, branch: str, cid: str) -> None: ref = ref_path(root, branch) ref.parent.mkdir(parents=True, exist_ok=True) ref.write_text(cid, encoding="utf-8") (head_path(root)).write_text(f"ref: refs/heads/{branch}", encoding="utf-8") def _mb(root: pathlib.Path, *args: str) -> InvokeResult: from muse.cli.app import main as cli return runner.invoke(cli, ["merge-base", *args], env=_env(root)) def _mbj(root: pathlib.Path, *args: str) -> InvokeResult: """Like _mb but always passes --json.""" return _mb(root, "--json", *args) def _diverged_repo(root: pathlib.Path) -> tuple[str, str, str]: """Create base → left and base → right. Returns (base, left, right).""" base = _commit(root, "base") left = _commit(root, "left", parent=base, branch="left") right = _commit(root, "right", parent=base, branch="right") _set_branch(root, "left", left) _set_branch(root, "right", right) return base, left, right def _unrelated_repo(root: pathlib.Path) -> tuple[str, str]: """Two commits with no shared history.""" c1 = _commit(root, "unrelated-c1") c2 = _commit(root, "unrelated-c2") return c1, c2 # --------------------------------------------------------------------------- # JSON envelope — exit_code # --------------------------------------------------------------------------- class TestJsonEnvelopeExitCode: """exit_code is present and correct on all merge-base outcomes.""" def test_found_has_exit_code(self, tmp_path: pathlib.Path) -> None: root = _init_repo(tmp_path) base, left, right = _diverged_repo(root) r = _mbj(root, left, right) assert r.exit_code == 0 d = json.loads(r.output) assert "exit_code" in d, "exit_code missing when merge base is found" assert d["exit_code"] == 0 def test_not_found_has_exit_code(self, tmp_path: pathlib.Path) -> None: root = _init_repo(tmp_path) c1, c2 = _unrelated_repo(root) r = _mbj(root, c1, c2) assert r.exit_code == 0 d = json.loads(r.output) assert "exit_code" in d, "exit_code missing when no common ancestor" assert d["exit_code"] == 0 def test_same_commit_has_exit_code(self, tmp_path: pathlib.Path) -> None: root = _init_repo(tmp_path) cid = _commit(root, "solo") r = _mbj(root, cid, cid) d = json.loads(r.output) assert "exit_code" in d assert d["exit_code"] == 0 # --------------------------------------------------------------------------- # JSON envelope — duration_ms # --------------------------------------------------------------------------- class TestJsonEnvelopeDurationMs: """duration_ms is present and non-negative on all merge-base outcomes.""" def test_found_has_duration_ms(self, tmp_path: pathlib.Path) -> None: root = _init_repo(tmp_path) base, left, right = _diverged_repo(root) r = _mbj(root, left, right) d = json.loads(r.output) assert "duration_ms" in d, "duration_ms missing when merge base is found" assert isinstance(d["duration_ms"], float) assert d["duration_ms"] >= 0.0 def test_not_found_has_duration_ms(self, tmp_path: pathlib.Path) -> None: root = _init_repo(tmp_path) c1, c2 = _unrelated_repo(root) r = _mbj(root, c1, c2) d = json.loads(r.output) assert "duration_ms" in d, "duration_ms missing when no common ancestor" assert isinstance(d["duration_ms"], float) def test_same_commit_has_duration_ms(self, tmp_path: pathlib.Path) -> None: root = _init_repo(tmp_path) cid = _commit(root, "dur-solo") r = _mbj(root, cid, cid) d = json.loads(r.output) assert "duration_ms" in d assert isinstance(d["duration_ms"], float) # --------------------------------------------------------------------------- # Error payload — errors route to stdout as JSON in --json mode # --------------------------------------------------------------------------- class TestErrorPayload: """In --json mode, all errors appear on stdout as JSON — no stderr prose.""" def test_bad_ref_error_is_json_on_stdout(self, tmp_path: pathlib.Path) -> None: root = _init_repo(tmp_path) r = _mbj(root, "no-such-branch", "also-missing") assert r.exit_code != 0 # Error JSON must go to stdout: stderr should be empty. assert not r.stderr.strip(), f"unexpected stderr: {r.stderr!r}" d = json.loads(r.output) assert d["status"] == "error" def test_bad_ref_error_has_status_error(self, tmp_path: pathlib.Path) -> None: root = _init_repo(tmp_path) r = _mbj(root, "ghost", "phantom") d = json.loads(r.output) assert d["status"] == "error" def test_bad_ref_error_has_exit_code(self, tmp_path: pathlib.Path) -> None: root = _init_repo(tmp_path) r = _mbj(root, "ghost", "phantom") d = json.loads(r.output) assert "exit_code" in d assert d["exit_code"] != 0 def test_bad_ref_error_has_error_field(self, tmp_path: pathlib.Path) -> None: root = _init_repo(tmp_path) r = _mbj(root, "ghost", "phantom") d = json.loads(r.output) assert "error" in d assert d["error"] # non-empty message def test_no_duplicate_stderr_prose(self, tmp_path: pathlib.Path) -> None: """In --json mode, errors must not also print ❌ prose to stderr.""" root = _init_repo(tmp_path) r = _mbj(root, "no-such", "branch") assert "❌" not in r.stderr def test_second_bad_ref_error_is_json_on_stdout(self, tmp_path: pathlib.Path) -> None: """Error on second ref (commit_b) also goes to stdout, not stderr.""" root = _init_repo(tmp_path) cid = _commit(root, "real-commit") r = _mbj(root, cid, "nonexistent") assert r.exit_code != 0 assert not r.stderr.strip(), f"unexpected stderr: {r.stderr!r}" d = json.loads(r.output) assert d["status"] == "error" # --------------------------------------------------------------------------- # Data integrity # --------------------------------------------------------------------------- class TestDataIntegrity: """Correctness properties that must hold across all inputs.""" def test_symmetry(self, tmp_path: pathlib.Path) -> None: """merge-base(A, B) == merge-base(B, A).""" root = _init_repo(tmp_path) base, left, right = _diverged_repo(root) r_ab = json.loads(_mbj(root, left, right).output) r_ba = json.loads(_mbj(root, right, left).output) assert r_ab["merge_base"] == r_ba["merge_base"] def test_merge_commit_as_input(self, tmp_path: pathlib.Path) -> None: """A merge commit (two parents) is handled correctly as input.""" root = _init_repo(tmp_path) base, left, right = _diverged_repo(root) # Simulate a merge commit that has both left and right as parents merge_commit = _commit(root, "merge", parent=left, parent2=right, branch="main") _set_branch(root, "main", merge_commit) # merge-base of the merge commit with right should be right (right is ancestor of merge) r = _mbj(root, merge_commit, right) assert r.exit_code == 0 d = json.loads(r.output) assert d["merge_base"] == right def test_found_merge_base_is_correct(self, tmp_path: pathlib.Path) -> None: """merge_base field equals the actual LCA commit ID.""" root = _init_repo(tmp_path) base, left, right = _diverged_repo(root) d = json.loads(_mbj(root, left, right).output) assert d["merge_base"] == base def test_commit_a_and_b_echoed_correctly(self, tmp_path: pathlib.Path) -> None: """commit_a and commit_b in the response match what was requested.""" root = _init_repo(tmp_path) base, left, right = _diverged_repo(root) d = json.loads(_mbj(root, left, right).output) assert d["commit_a"] == left assert d["commit_b"] == right def test_not_found_merge_base_is_null(self, tmp_path: pathlib.Path) -> None: """merge_base is null (not absent) when no common ancestor.""" root = _init_repo(tmp_path) c1, c2 = _unrelated_repo(root) d = json.loads(_mbj(root, c1, c2).output) assert "merge_base" in d assert d["merge_base"] is None # --------------------------------------------------------------------------- # No-prose pollution # --------------------------------------------------------------------------- class TestNoProsePollution: """JSON stdout must be valid, parseable JSON on all non-error paths.""" def test_found_stdout_is_valid_json(self, tmp_path: pathlib.Path) -> None: root = _init_repo(tmp_path) base, left, right = _diverged_repo(root) r = _mbj(root, left, right) json.loads(r.output) # must not raise def test_not_found_stdout_is_valid_json(self, tmp_path: pathlib.Path) -> None: root = _init_repo(tmp_path) c1, c2 = _unrelated_repo(root) json.loads(_mbj(root, c1, c2).output) # must not raise def test_no_emoji_in_found_json(self, tmp_path: pathlib.Path) -> None: root = _init_repo(tmp_path) base, left, right = _diverged_repo(root) r = _mbj(root, left, right) assert "✅" not in r.output assert "❌" not in r.output # --------------------------------------------------------------------------- # TypedDicts # --------------------------------------------------------------------------- class TestTypedDicts: def test_merge_base_found_json_typeddict_exists(self) -> None: from muse.cli.commands.merge_base import _MergeBaseFoundJson assert _MergeBaseFoundJson is not None def test_merge_base_error_json_typeddict_exists(self) -> None: from muse.cli.commands.merge_base import _MergeBaseErrorJson assert _MergeBaseErrorJson is not None def test_merge_base_found_json_has_exit_code_annotation(self) -> None: from muse.cli.commands.merge_base import _MergeBaseFoundJson hints = get_type_hints(_MergeBaseFoundJson) assert "exit_code" in hints def test_merge_base_found_json_has_duration_ms_annotation(self) -> None: from muse.cli.commands.merge_base import _MergeBaseFoundJson hints = get_type_hints(_MergeBaseFoundJson) assert "duration_ms" in hints def test_merge_base_error_json_has_required_fields(self) -> None: from muse.cli.commands.merge_base import _MergeBaseErrorJson hints = get_type_hints(_MergeBaseErrorJson) for field in ("status", "error", "exit_code"): assert field in hints, f"Missing annotation: {field!r}" # --------------------------------------------------------------------------- # Docstring coverage # --------------------------------------------------------------------------- class TestDocstring: def _doc(self) -> str: import muse.cli.commands.merge_base as mod return mod.__doc__ or "" def test_docstring_documents_exit_code(self) -> None: assert "exit_code" in self._doc() def test_docstring_documents_duration_ms(self) -> None: assert "duration_ms" in self._doc() # --------------------------------------------------------------------------- # Stress # --------------------------------------------------------------------------- class TestStress: def test_100_commit_linear_chain(self, tmp_path: pathlib.Path) -> None: """100-commit chain: merge-base of tip and midpoint is the midpoint.""" root = _init_repo(tmp_path) commits: list[str] = [] for i in range(100): parent = commits[-1] if commits else None cid = _commit(root, f"chain-{i:03d}", parent=parent) commits.append(cid) mid = commits[49] tip = commits[-1] r = _mbj(root, tip, mid) assert r.exit_code == 0 d = json.loads(r.output) assert d["merge_base"] == mid assert "duration_ms" in d assert "exit_code" in d class TestRegisterFlags: def _parse(self, *args: str) -> "argparse.Namespace": import argparse from muse.cli.commands.merge_base import register p = argparse.ArgumentParser() subs = p.add_subparsers() register(subs) return p.parse_args(["merge-base", fake_id("a"), fake_id("b"), *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