gabriel / muse public
test_cmd_commit_tree.py python
660 lines 24.1 KB
Raw
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 132 days ago
1 """Comprehensive tests for ``muse commit-tree``.
2
3 Coverage tiers
4 --------------
5 - Unit: _FORMAT_CHOICES
6 - Integration: basic creation, --parent chain, merge commit, text format,
7 --agent-id/--model-id/--toolchain-id provenance, --branch override
8 - Security: >2 parents silently rejected, errors to stderr, no traceback
9 - Stress: 200 sequential commit-tree calls
10 """
11 from __future__ import annotations
12
13 import datetime
14 import json
15 import pathlib
16
17 from muse.core.errors import ExitCode
18 from muse.core.snapshot import compute_commit_id, compute_snapshot_id
19 from muse.core.store import CommitRecord, SnapshotRecord, read_commit, write_commit, write_snapshot
20 from muse.core._types import Manifest, fake_id
21 from tests.cli_test_helper import CliRunner, InvokeResult
22
23 runner = CliRunner()
24
25
26 # ---------------------------------------------------------------------------
27 # Helpers
28 # ---------------------------------------------------------------------------
29
30 def _make_repo(tmp_path: pathlib.Path) -> pathlib.Path:
31 repo = tmp_path / "repo"
32 muse = repo / ".muse"
33 for sub in ("objects", "commits", "snapshots", "refs/heads"):
34 (muse / sub).mkdir(parents=True)
35 (muse / "HEAD").write_text("ref: refs/heads/main")
36 (muse / "repo.json").write_text(json.dumps({"repo_id": "test-repo", "domain": "code"}))
37 return repo
38
39
40 def _snap(repo: pathlib.Path) -> str:
41 manifest: Manifest = {}
42 sid = compute_snapshot_id(manifest)
43 write_snapshot(repo, SnapshotRecord(
44 snapshot_id=sid,
45 manifest=manifest,
46 created_at=datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc),
47 ))
48 return sid
49
50
51 def _commit(
52 repo: pathlib.Path,
53 snap_id: str,
54 parent: str | None = None,
55 message: str = "parent",
56 ) -> str:
57 committed_at = datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc)
58 parent_ids: list[str] = [parent] if parent else []
59 commit_id = compute_commit_id(
60 repo_id="test-repo",
61 parent_ids=parent_ids,
62 snapshot_id=snap_id,
63 message=message,
64 committed_at_iso=committed_at.isoformat(),
65 )
66 write_commit(repo, CommitRecord(
67 commit_id=commit_id,
68 repo_id="test-repo",
69 created_on_branch="main",
70 snapshot_id=snap_id,
71 message=message,
72 committed_at=committed_at,
73 parent_commit_id=parent,
74 ))
75 return commit_id
76
77
78 def _ct(repo: pathlib.Path, *args: str) -> InvokeResult:
79 from muse.cli.app import main as cli
80 return runner.invoke(
81 cli,
82 ["commit-tree", "--json", *args],
83 env={"MUSE_REPO_ROOT": str(repo)},
84 )
85
86
87 # ---------------------------------------------------------------------------
88 # Unit
89 # ---------------------------------------------------------------------------
90
91
92 class TestUnit:
93 def test_json_flag_registered(self) -> None:
94 from muse.cli.commands.commit_tree import register
95 import argparse
96 p = argparse.ArgumentParser()
97 subs = p.add_subparsers()
98 register(subs)
99 ns = p.parse_args(["commit-tree", "--snapshot", fake_id("a"), "--json"])
100 assert ns.json_out is True
101
102
103 # ---------------------------------------------------------------------------
104 # Integration — basic creation
105 # ---------------------------------------------------------------------------
106
107
108 class TestBasicCreation:
109 def test_creates_commit(self, tmp_path: pathlib.Path) -> None:
110 repo = _make_repo(tmp_path)
111 sid = _snap(repo)
112 result = _ct(repo, "--snapshot", sid, "--message", "first commit")
113 assert result.exit_code == 0
114 data = json.loads(result.output)
115 assert "commit_id" in data
116 assert data["commit_id"].startswith("sha256:")
117 assert len(data["commit_id"]) == 71
118
119 def test_commit_persisted_in_store(self, tmp_path: pathlib.Path) -> None:
120 repo = _make_repo(tmp_path)
121 sid = _snap(repo)
122 data = json.loads(_ct(repo, "--snapshot", sid).output)
123 cid = data["commit_id"]
124 rec = read_commit(repo, cid)
125 assert rec is not None
126 assert rec.snapshot_id == sid
127
128 def test_json_flag_shorthand(self, tmp_path: pathlib.Path) -> None:
129 repo = _make_repo(tmp_path)
130 sid = _snap(repo)
131 result = _ct(repo, "--json", "--snapshot", sid)
132 assert result.exit_code == 0
133 assert "commit_id" in json.loads(result.output)
134
135 def test_text_format_bare_commit_id(self, tmp_path: pathlib.Path) -> None:
136 from muse.cli.app import main as cli
137 repo = _make_repo(tmp_path)
138 sid = _snap(repo)
139 result = runner.invoke(
140 cli,
141 ["commit-tree", "--snapshot", sid],
142 env={"MUSE_REPO_ROOT": str(repo)},
143 )
144 assert result.exit_code == 0
145 line = result.output.strip()
146 assert line.startswith("sha256:")
147 assert len(line) == 71
148
149 def test_message_stored(self, tmp_path: pathlib.Path) -> None:
150 repo = _make_repo(tmp_path)
151 sid = _snap(repo)
152 data = json.loads(_ct(repo, "--snapshot", sid, "--message", "my msg").output)
153 rec = read_commit(repo, data["commit_id"])
154 assert rec is not None
155 assert rec.message == "my msg"
156
157 def test_author_stored(self, tmp_path: pathlib.Path) -> None:
158 repo = _make_repo(tmp_path)
159 sid = _snap(repo)
160 data = json.loads(_ct(repo, "--snapshot", sid, "--author", "gabriel").output)
161 rec = read_commit(repo, data["commit_id"])
162 assert rec is not None
163 assert rec.author == "gabriel"
164
165
166 # ---------------------------------------------------------------------------
167 # Integration — parent chain
168 # ---------------------------------------------------------------------------
169
170
171 class TestParentChain:
172 def test_single_parent_stored(self, tmp_path: pathlib.Path) -> None:
173 repo = _make_repo(tmp_path)
174 sid = _snap(repo)
175 p1_id = _commit(repo, sid)
176 data = json.loads(_ct(repo, "--snapshot", sid, "--parent", p1_id).output)
177 rec = read_commit(repo, data["commit_id"])
178 assert rec is not None
179 assert rec.parent_commit_id == p1_id
180 assert rec.parent2_commit_id is None
181
182 def test_merge_commit_two_parents(self, tmp_path: pathlib.Path) -> None:
183 repo = _make_repo(tmp_path)
184 sid = _snap(repo)
185 p1 = _commit(repo, sid, message="parent1")
186 p2 = _commit(repo, sid, message="parent2")
187 data = json.loads(
188 _ct(repo, "--snapshot", sid, "--parent", p1, "--parent", p2).output
189 )
190 rec = read_commit(repo, data["commit_id"])
191 assert rec is not None
192 assert rec.parent_commit_id == p1
193 assert rec.parent2_commit_id == p2
194
195 def test_three_parents_rejected(self, tmp_path: pathlib.Path) -> None:
196 repo = _make_repo(tmp_path)
197 sid = _snap(repo)
198 p = _commit(repo, sid)
199 result = _ct(
200 repo, "--snapshot", sid,
201 "--parent", p, "--parent", p, "--parent", p,
202 )
203 assert result.exit_code == ExitCode.USER_ERROR
204
205 def test_missing_parent_errors(self, tmp_path: pathlib.Path) -> None:
206 repo = _make_repo(tmp_path)
207 sid = _snap(repo)
208 result = _ct(repo, "--snapshot", sid, "--parent", "dead" + "beef" * 15)
209 assert result.exit_code == ExitCode.USER_ERROR
210
211
212 # ---------------------------------------------------------------------------
213 # Integration — agent provenance flags
214 # ---------------------------------------------------------------------------
215
216
217 class TestAgentProvenance:
218 def test_agent_id_stored(self, tmp_path: pathlib.Path) -> None:
219 repo = _make_repo(tmp_path)
220 sid = _snap(repo)
221 data = json.loads(
222 _ct(repo, "--snapshot", sid, "--agent-id", "my-bot").output
223 )
224 rec = read_commit(repo, data["commit_id"])
225 assert rec is not None
226 assert rec.agent_id == "my-bot"
227
228 def test_model_id_stored(self, tmp_path: pathlib.Path) -> None:
229 repo = _make_repo(tmp_path)
230 sid = _snap(repo)
231 data = json.loads(
232 _ct(repo, "--snapshot", sid, "--model-id", "claude-opus-4").output
233 )
234 rec = read_commit(repo, data["commit_id"])
235 assert rec is not None
236 assert rec.model_id == "claude-opus-4"
237
238 def test_toolchain_id_stored(self, tmp_path: pathlib.Path) -> None:
239 repo = _make_repo(tmp_path)
240 sid = _snap(repo)
241 data = json.loads(
242 _ct(repo, "--snapshot", sid, "--toolchain-id", "cursor-agent-v2").output
243 )
244 rec = read_commit(repo, data["commit_id"])
245 assert rec is not None
246 assert rec.toolchain_id == "cursor-agent-v2"
247
248 def test_full_provenance_round_trip(self, tmp_path: pathlib.Path) -> None:
249 repo = _make_repo(tmp_path)
250 sid = _snap(repo)
251 data = json.loads(_ct(
252 repo,
253 "--snapshot", sid,
254 "--agent-id", "audit-bot",
255 "--model-id", "claude-4",
256 "--toolchain-id", "muse-agent-v1",
257 ).output)
258 rec = read_commit(repo, data["commit_id"])
259 assert rec is not None
260 assert rec.agent_id == "audit-bot"
261 assert rec.model_id == "claude-4"
262 assert rec.toolchain_id == "muse-agent-v1"
263
264 def test_defaults_to_empty_strings(self, tmp_path: pathlib.Path) -> None:
265 repo = _make_repo(tmp_path)
266 sid = _snap(repo)
267 data = json.loads(_ct(repo, "--snapshot", sid).output)
268 rec = read_commit(repo, data["commit_id"])
269 assert rec is not None
270 assert rec.agent_id == ""
271 assert rec.model_id == ""
272 assert rec.toolchain_id == ""
273
274
275 # ---------------------------------------------------------------------------
276 # Integration — --branch override
277 # ---------------------------------------------------------------------------
278
279
280 class TestBranchOverride:
281 def test_branch_override_stored(self, tmp_path: pathlib.Path) -> None:
282 repo = _make_repo(tmp_path)
283 sid = _snap(repo)
284 data = json.loads(_ct(repo, "--snapshot", sid, "--branch", "feat/x").output)
285 rec = read_commit(repo, data["commit_id"])
286 assert rec is not None
287 assert rec.created_on_branch == "feat/x"
288
289
290 # ---------------------------------------------------------------------------
291 # Error cases
292 # ---------------------------------------------------------------------------
293
294
295 class TestErrors:
296 def test_missing_snapshot_errors(self, tmp_path: pathlib.Path) -> None:
297 repo = _make_repo(tmp_path)
298 result = _ct(repo, "--snapshot", "dead" + "beef" * 15)
299 assert result.exit_code == ExitCode.USER_ERROR
300
301 def test_invalid_snapshot_id_errors(self, tmp_path: pathlib.Path) -> None:
302 repo = _make_repo(tmp_path)
303 result = _ct(repo, "--snapshot", "not-hex")
304 assert result.exit_code == ExitCode.USER_ERROR
305
306 def test_invalid_parent_id_errors(self, tmp_path: pathlib.Path) -> None:
307 repo = _make_repo(tmp_path)
308 sid = _snap(repo)
309 result = _ct(repo, "--snapshot", sid, "--parent", "bad-hex")
310 assert result.exit_code == ExitCode.USER_ERROR
311
312 def test_missing_snapshot_arg_errors(self, tmp_path: pathlib.Path) -> None:
313 from muse.cli.app import main as cli
314 repo = _make_repo(tmp_path)
315 result = runner.invoke(
316 cli,
317 ["commit-tree"],
318 env={"MUSE_REPO_ROOT": str(repo)},
319 )
320 assert result.exit_code != 0
321
322
323 # ---------------------------------------------------------------------------
324 # Security
325 # ---------------------------------------------------------------------------
326
327
328 class TestSecurity:
329 def test_no_traceback_on_bad_snapshot(self, tmp_path: pathlib.Path) -> None:
330 repo = _make_repo(tmp_path)
331 result = _ct(repo, "--snapshot", "bad")
332 assert "Traceback" not in result.output
333
334 def test_no_traceback_on_too_many_parents(self, tmp_path: pathlib.Path) -> None:
335 repo = _make_repo(tmp_path)
336 sid = _snap(repo)
337 p = _commit(repo, sid)
338 result = _ct(repo, "--snapshot", sid, "--parent", p, "--parent", p, "--parent", p)
339 assert "Traceback" not in result.output
340
341
342 # ---------------------------------------------------------------------------
343 # Stress
344 # ---------------------------------------------------------------------------
345
346
347 class TestStress:
348 def test_200_sequential_commits(self, tmp_path: pathlib.Path) -> None:
349 repo = _make_repo(tmp_path)
350 sid = _snap(repo)
351 for i in range(200):
352 result = _ct(repo, "--snapshot", sid, "--message", f"commit {i}")
353 assert result.exit_code == 0, f"failed at iteration {i}"
354 data = json.loads(result.output)
355 assert data["commit_id"].startswith("sha256:")
356 assert len(data["commit_id"]) == 71
357
358
359 # ---------------------------------------------------------------------------
360 # Supercharge — full JSON schema
361 # ---------------------------------------------------------------------------
362
363 _FULL_KEYS = frozenset({
364 "commit_id",
365 "snapshot_id",
366 "branch",
367 "message",
368 "committed_at",
369 "author",
370 "agent_id",
371 "model_id",
372 "toolchain_id",
373 "parent_commit_id",
374 "parent2_commit_id",
375 "duration_ms",
376 "exit_code",
377 })
378
379
380 class TestJsonSchemaComplete:
381 """JSON output must carry the full commit record so agents need no follow-up read."""
382
383 def test_all_keys_present_on_success(self, tmp_path: pathlib.Path) -> None:
384 repo = _make_repo(tmp_path)
385 sid = _snap(repo)
386 data = json.loads(_ct(repo, "--snapshot", sid, "--message", "m").output)
387 assert _FULL_KEYS <= set(data.keys()), (
388 f"Missing keys: {_FULL_KEYS - set(data.keys())}"
389 )
390
391 def test_snapshot_id_echoed(self, tmp_path: pathlib.Path) -> None:
392 repo = _make_repo(tmp_path)
393 sid = _snap(repo)
394 data = json.loads(_ct(repo, "--snapshot", sid).output)
395 assert data["snapshot_id"] == sid
396
397 def test_branch_echoed(self, tmp_path: pathlib.Path) -> None:
398 repo = _make_repo(tmp_path)
399 sid = _snap(repo)
400 data = json.loads(_ct(repo, "--snapshot", sid, "--branch", "feat/x").output)
401 assert data["branch"] == "feat/x"
402
403 def test_message_echoed(self, tmp_path: pathlib.Path) -> None:
404 repo = _make_repo(tmp_path)
405 sid = _snap(repo)
406 data = json.loads(_ct(repo, "--snapshot", sid, "--message", "hello world").output)
407 assert data["message"] == "hello world"
408
409 def test_author_echoed(self, tmp_path: pathlib.Path) -> None:
410 repo = _make_repo(tmp_path)
411 sid = _snap(repo)
412 data = json.loads(_ct(repo, "--snapshot", sid, "--author", "gabriel").output)
413 assert data["author"] == "gabriel"
414
415 def test_agent_id_echoed(self, tmp_path: pathlib.Path) -> None:
416 repo = _make_repo(tmp_path)
417 sid = _snap(repo)
418 data = json.loads(_ct(repo, "--snapshot", sid, "--agent-id", "bot-x").output)
419 assert data["agent_id"] == "bot-x"
420
421 def test_model_id_echoed(self, tmp_path: pathlib.Path) -> None:
422 repo = _make_repo(tmp_path)
423 sid = _snap(repo)
424 data = json.loads(_ct(repo, "--snapshot", sid, "--model-id", "claude-opus-4").output)
425 assert data["model_id"] == "claude-opus-4"
426
427 def test_toolchain_id_echoed(self, tmp_path: pathlib.Path) -> None:
428 repo = _make_repo(tmp_path)
429 sid = _snap(repo)
430 data = json.loads(_ct(repo, "--snapshot", sid, "--toolchain-id", "v2").output)
431 assert data["toolchain_id"] == "v2"
432
433 def test_parent_commit_id_null_when_no_parent(self, tmp_path: pathlib.Path) -> None:
434 repo = _make_repo(tmp_path)
435 sid = _snap(repo)
436 data = json.loads(_ct(repo, "--snapshot", sid).output)
437 assert data["parent_commit_id"] is None
438
439 def test_parent_commit_id_present(self, tmp_path: pathlib.Path) -> None:
440 repo = _make_repo(tmp_path)
441 sid = _snap(repo)
442 p1 = _commit(repo, sid)
443 data = json.loads(_ct(repo, "--snapshot", sid, "--parent", p1).output)
444 assert data["parent_commit_id"] == p1
445
446 def test_parent2_commit_id_null_when_no_second_parent(self, tmp_path: pathlib.Path) -> None:
447 repo = _make_repo(tmp_path)
448 sid = _snap(repo)
449 data = json.loads(_ct(repo, "--snapshot", sid).output)
450 assert data["parent2_commit_id"] is None
451
452 def test_parent2_commit_id_present_for_merge(self, tmp_path: pathlib.Path) -> None:
453 repo = _make_repo(tmp_path)
454 sid = _snap(repo)
455 p1 = _commit(repo, sid, message="p1")
456 p2 = _commit(repo, sid, message="p2")
457 data = json.loads(_ct(repo, "--snapshot", sid, "--parent", p1, "--parent", p2).output)
458 assert data["parent2_commit_id"] == p2
459
460 def test_committed_at_is_iso_string(self, tmp_path: pathlib.Path) -> None:
461 repo = _make_repo(tmp_path)
462 sid = _snap(repo)
463 data = json.loads(_ct(repo, "--snapshot", sid).output)
464 ts = data["committed_at"]
465 assert isinstance(ts, str)
466 # Must parse as ISO datetime
467 datetime.datetime.fromisoformat(ts)
468
469 def test_exit_code_zero(self, tmp_path: pathlib.Path) -> None:
470 repo = _make_repo(tmp_path)
471 sid = _snap(repo)
472 data = json.loads(_ct(repo, "--snapshot", sid).output)
473 assert data["exit_code"] == 0
474
475
476 # ---------------------------------------------------------------------------
477 # Supercharge — duration_ms
478 # ---------------------------------------------------------------------------
479
480
481 class TestElapsed:
482 def test_elapsed_present(self, tmp_path: pathlib.Path) -> None:
483 repo = _make_repo(tmp_path)
484 sid = _snap(repo)
485 data = json.loads(_ct(repo, "--snapshot", sid).output)
486 assert "duration_ms" in data
487
488 def test_elapsed_is_float(self, tmp_path: pathlib.Path) -> None:
489 repo = _make_repo(tmp_path)
490 sid = _snap(repo)
491 data = json.loads(_ct(repo, "--snapshot", sid).output)
492 assert isinstance(data["duration_ms"], float)
493
494 def test_elapsed_non_negative(self, tmp_path: pathlib.Path) -> None:
495 repo = _make_repo(tmp_path)
496 sid = _snap(repo)
497 data = json.loads(_ct(repo, "--snapshot", sid).output)
498 assert data["duration_ms"] >= 0.0
499
500
501 # ---------------------------------------------------------------------------
502 # Supercharge — exit_code
503 # ---------------------------------------------------------------------------
504
505
506 class TestExitCode:
507 def test_exit_code_zero_on_success(self, tmp_path: pathlib.Path) -> None:
508 repo = _make_repo(tmp_path)
509 sid = _snap(repo)
510 data = json.loads(_ct(repo, "--snapshot", sid).output)
511 assert data["exit_code"] == 0
512
513 def test_process_exit_zero_on_success(self, tmp_path: pathlib.Path) -> None:
514 repo = _make_repo(tmp_path)
515 sid = _snap(repo)
516 result = _ct(repo, "--snapshot", sid)
517 assert result.exit_code == 0
518
519
520 # ---------------------------------------------------------------------------
521 # Supercharge — data integrity
522 # ---------------------------------------------------------------------------
523
524
525 class TestDataIntegrity:
526 def test_commit_id_roundtrips_via_store(self, tmp_path: pathlib.Path) -> None:
527 """commit_id in JSON matches what was actually written to the store."""
528 repo = _make_repo(tmp_path)
529 sid = _snap(repo)
530 data = json.loads(_ct(repo, "--snapshot", sid, "--message", "integrity check").output)
531 rec = read_commit(repo, data["commit_id"])
532 assert rec is not None
533 assert rec.commit_id == data["commit_id"]
534 assert rec.snapshot_id == data["snapshot_id"]
535 assert rec.message == data["message"]
536
537 def test_snapshot_id_matches_store(self, tmp_path: pathlib.Path) -> None:
538 repo = _make_repo(tmp_path)
539 sid = _snap(repo)
540 data = json.loads(_ct(repo, "--snapshot", sid).output)
541 rec = read_commit(repo, data["commit_id"])
542 assert rec is not None
543 assert rec.snapshot_id == sid
544
545 def test_parent_id_matches_store(self, tmp_path: pathlib.Path) -> None:
546 repo = _make_repo(tmp_path)
547 sid = _snap(repo)
548 p1 = _commit(repo, sid)
549 data = json.loads(_ct(repo, "--snapshot", sid, "--parent", p1).output)
550 rec = read_commit(repo, data["commit_id"])
551 assert rec is not None
552 assert rec.parent_commit_id == data["parent_commit_id"] == p1
553
554 def test_provenance_matches_store(self, tmp_path: pathlib.Path) -> None:
555 repo = _make_repo(tmp_path)
556 sid = _snap(repo)
557 data = json.loads(_ct(
558 repo, "--snapshot", sid,
559 "--agent-id", "integrity-bot",
560 "--model-id", "claude-sonnet-4-6",
561 "--toolchain-id", "test-chain",
562 ).output)
563 rec = read_commit(repo, data["commit_id"])
564 assert rec is not None
565 assert rec.agent_id == data["agent_id"] == "integrity-bot"
566 assert rec.model_id == data["model_id"] == "claude-sonnet-4-6"
567 assert rec.toolchain_id == data["toolchain_id"] == "test-chain"
568
569
570 # ---------------------------------------------------------------------------
571 # Supercharge — security (ANSI injection)
572 # ---------------------------------------------------------------------------
573
574
575 class TestSecurityAnsi:
576 def test_ansi_in_message_does_not_corrupt_json(self, tmp_path: pathlib.Path) -> None:
577 repo = _make_repo(tmp_path)
578 sid = _snap(repo)
579 evil_message = "feat: \x1b[31mred\x1b[0m alert"
580 result = _ct(repo, "--snapshot", sid, "--message", evil_message)
581 assert result.exit_code == 0
582 data = json.loads(result.output)
583 assert data["message"] == evil_message
584
585 def test_ansi_in_author_does_not_corrupt_json(self, tmp_path: pathlib.Path) -> None:
586 repo = _make_repo(tmp_path)
587 sid = _snap(repo)
588 evil_author = "\x1b[32mgabriel\x1b[0m"
589 result = _ct(repo, "--snapshot", sid, "--author", evil_author)
590 assert result.exit_code == 0
591 data = json.loads(result.output)
592 assert data["author"] == evil_author
593
594 def test_long_message_handled(self, tmp_path: pathlib.Path) -> None:
595 repo = _make_repo(tmp_path)
596 sid = _snap(repo)
597 long_msg = "x" * 10_000
598 data = json.loads(_ct(repo, "--snapshot", sid, "--message", long_msg).output)
599 rec = read_commit(repo, data["commit_id"])
600 assert rec is not None
601 assert rec.message == long_msg
602
603
604 # ---------------------------------------------------------------------------
605 # Supercharge — performance
606 # ---------------------------------------------------------------------------
607
608
609 class TestPerformance:
610 def test_single_commit_under_500ms(self, tmp_path: pathlib.Path) -> None:
611 import time
612 repo = _make_repo(tmp_path)
613 sid = _snap(repo)
614 t0 = time.monotonic()
615 result = _ct(repo, "--snapshot", sid)
616 elapsed = time.monotonic() - t0
617 assert result.exit_code == 0
618 assert elapsed < 0.5, f"commit-tree took {elapsed:.3f}s — too slow"
619
620 def test_duration_ms_reasonable(self, tmp_path: pathlib.Path) -> None:
621 repo = _make_repo(tmp_path)
622 sid = _snap(repo)
623 data = json.loads(_ct(repo, "--snapshot", sid).output)
624 assert data["duration_ms"] < 50.0, (
625 f"reported elapsed {data['duration_ms']}ms — implausibly slow"
626 )
627
628
629 # ---------------------------------------------------------------------------
630 # Flag registration tests
631 # ---------------------------------------------------------------------------
632
633 import argparse as _argparse
634 from muse.cli.commands.commit_tree import register as _register_commit_tree
635
636
637 def _parse_ct(*args: str) -> _argparse.Namespace:
638 root_p = _argparse.ArgumentParser()
639 subs = root_p.add_subparsers(dest="cmd")
640 _register_commit_tree(subs)
641 return root_p.parse_args(["commit-tree", *args])
642
643
644 class TestRegisterFlags:
645 def test_default_json_out_is_false(self) -> None:
646 ns = _parse_ct("--snapshot", fake_id("a"))
647 assert ns.json_out is False
648
649 def test_json_flag_sets_json_out(self) -> None:
650 ns = _parse_ct("--snapshot", fake_id("a"), "--json")
651 assert ns.json_out is True
652
653 def test_j_shorthand_sets_json_out(self) -> None:
654 ns = _parse_ct("--snapshot", fake_id("a"), "-j")
655 assert ns.json_out is True
656
657 def test_format_flag_no_longer_exists(self) -> None:
658 import pytest
659 with pytest.raises(SystemExit):
660 _parse_ct("--snapshot", fake_id("a"), "--format", "json")
File History 3 commits
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 132 days ago
sha256:7f9e2ef5286aedad9c1e6011b4c46ca27f39dbdad6e3409357e36b26e46b3b7c docs: docstring sprint for-each-ref→hotspots — idiomatic ru… Sonnet 4.6 patch 138 days ago
sha256:a09b1b4f6838754495547f200aa0ce88e2f56ffc5b20b900f6f0cff2c3cdede9 fix(cursorignore): remove git-ism (.git/worktrees) Human minor 141 days ago