gabriel / muse public
test_cmd_for_each_ref.py python
620 lines 22.4 KB
Raw
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 131 days ago
1 """Tests for muse for-each-ref.
2
3 Coverage tiers
4 --------------
5 Unit — _list_all_refs (flat, hierarchical, symlink skip, bad commit ID),
6 _RefDetail + _ForEachRefResult schemas, _SORT_FIELDS completeness
7 Integration — empty repo, flat branches, hierarchical branches, pattern filter,
8 sort (all fields, asc/desc), --count limit, --no-commits fast-path,
9 text output (full / no-commits), --json shorthand
10 Security — symlinks skipped, ANSI in branch/commit/author sanitized,
11 error output to stderr (format, sort, negative count),
12 no traceback on bad format/corrupted ref, no-commits+commit-sort rejected
13 Stress — 100-branch repo, 50-hierarchical-branch repo, 200 sequential reads
14 """
15
16 from __future__ import annotations
17
18 import argparse
19 import datetime
20 import json
21 import os
22 import pathlib
23
24 import pytest
25 from tests.cli_test_helper import CliRunner, InvokeResult
26
27 from muse.cli.commands.for_each_ref import (
28 _ForEachRefResult,
29 _RefDetail,
30 _SORT_FIELDS,
31 _list_all_refs,
32 )
33 from muse.core.snapshot import compute_commit_id, compute_snapshot_id
34 from muse.core.store import CommitRecord, SnapshotRecord, write_commit, write_snapshot
35 from muse.core._types import Manifest
36
37 cli = None # argparse-based CLI; CliRunner ignores this arg
38 runner = CliRunner()
39
40
41 # ---------------------------------------------------------------------------
42 # Helpers
43 # ---------------------------------------------------------------------------
44
45
46
47 def _init_repo(path: pathlib.Path) -> pathlib.Path:
48 muse = path / ".muse"
49 (muse / "commits").mkdir(parents=True)
50 (muse / "snapshots").mkdir(parents=True)
51 (muse / "objects").mkdir(parents=True)
52 (muse / "refs" / "heads").mkdir(parents=True)
53 (muse / "HEAD").write_text("ref: refs/heads/main\n", encoding="utf-8")
54 (muse / "repo.json").write_text(
55 json.dumps({"repo_id": "test-repo", "domain": "midi"}), encoding="utf-8"
56 )
57 return path
58
59
60 def _env(repo: pathlib.Path) -> Manifest:
61 return {"MUSE_REPO_ROOT": str(repo)}
62
63
64 def _snap(repo: pathlib.Path, tag: str = "snap") -> str:
65 sid = compute_snapshot_id({})
66 write_snapshot(
67 repo,
68 SnapshotRecord(
69 snapshot_id=sid,
70 manifest={},
71 created_at=datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc),
72 ),
73 )
74 return sid
75
76
77 def _commit(
78 repo: pathlib.Path,
79 tag: str,
80 branch: str = "main",
81 parent: str | None = None,
82 ts: datetime.datetime | None = None,
83 author: str = "tester",
84 ) -> str:
85 sid = _snap(repo, tag)
86 ts_actual = ts or datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc)
87 parent_ids: list[str] = [parent] if parent else []
88 cid = compute_commit_id(
89 repo_id="test-repo",
90 parent_ids=parent_ids,
91 snapshot_id=sid,
92 message=tag,
93 committed_at_iso=ts_actual.isoformat(),
94 author=author,
95 )
96 write_commit(
97 repo,
98 CommitRecord(
99 commit_id=cid,
100 repo_id="test-repo",
101 created_on_branch=branch,
102 snapshot_id=sid,
103 message=tag,
104 committed_at=ts_actual,
105 author=author,
106 parent_commit_id=parent,
107 parent2_commit_id=None,
108 ),
109 )
110 ref_path = repo / ".muse" / "refs" / "heads" / branch
111 ref_path.parent.mkdir(parents=True, exist_ok=True)
112 ref_path.write_text(cid, encoding="utf-8")
113 return cid
114
115
116 def _fer(repo: pathlib.Path, *args: str) -> InvokeResult:
117 return runner.invoke(cli, ["for-each-ref", "--json", *args], env=_env(repo))
118
119
120 def _fer_text(repo: pathlib.Path, *args: str) -> InvokeResult:
121 return runner.invoke(cli, ["for-each-ref", *args], env=_env(repo))
122
123
124 # ---------------------------------------------------------------------------
125 # Unit — flag registration
126 # ---------------------------------------------------------------------------
127
128
129 class TestRegisterFlags:
130 def _parse(self, *args: str) -> "argparse.Namespace":
131 import argparse
132 from muse.cli.commands.for_each_ref import register
133 p = argparse.ArgumentParser()
134 sub = p.add_subparsers()
135 register(sub)
136 return p.parse_args(["for-each-ref", *args])
137
138 def test_default_json_out_is_false(self) -> None:
139 ns = self._parse()
140 assert ns.json_out is False
141
142 def test_json_flag_sets_json_out(self) -> None:
143 ns = self._parse("--json")
144 assert ns.json_out is True
145
146 def test_j_shorthand_sets_json_out(self) -> None:
147 ns = self._parse("-j")
148 assert ns.json_out is True
149
150
151 # ---------------------------------------------------------------------------
152 # Unit — schema
153 # ---------------------------------------------------------------------------
154
155
156 class TestSchemas:
157 def test_sort_fields_includes_snapshot_id(self) -> None:
158 assert "snapshot_id" in _SORT_FIELDS
159
160 def test_sort_fields_includes_all_expected(self) -> None:
161 for f in ("ref", "branch", "commit_id", "author", "committed_at", "message"):
162 assert f in _SORT_FIELDS
163
164 def test_for_each_ref_result_fields(self) -> None:
165 keys = _ForEachRefResult.__annotations__
166 assert "refs" in keys
167 assert "count" in keys
168
169 def test_ref_detail_is_total_false(self) -> None:
170 # total=False allows partial dicts for --no-commits mode.
171 # __required_keys__ is empty when total=False.
172 assert len(_RefDetail.__required_keys__) == 0
173
174
175 # ---------------------------------------------------------------------------
176 # Unit — _list_all_refs
177 # ---------------------------------------------------------------------------
178
179
180 class TestListAllRefs:
181 def test_empty_heads_dir(self, tmp_path: pathlib.Path) -> None:
182 _init_repo(tmp_path)
183 assert _list_all_refs(tmp_path) == []
184
185 def test_flat_branch(self, tmp_path: pathlib.Path) -> None:
186 _init_repo(tmp_path)
187 _commit(tmp_path, "c", "main")
188 pairs = _list_all_refs(tmp_path)
189 assert len(pairs) == 1
190 assert pairs[0][0] == "main"
191
192 def test_hierarchical_branch_discovered(self, tmp_path: pathlib.Path) -> None:
193 """feat/my-thing must be found — requires rglob, not iterdir."""
194 _init_repo(tmp_path)
195 _commit(tmp_path, "c-main", "main")
196 _commit(tmp_path, "c-feat", "feat/my-thing")
197 pairs = _list_all_refs(tmp_path)
198 branch_names = [b for b, _ in pairs]
199 assert "feat/my-thing" in branch_names
200 assert "main" in branch_names
201
202 def test_symlink_ref_skipped(self, tmp_path: pathlib.Path) -> None:
203 _init_repo(tmp_path)
204 _commit(tmp_path, "c", "main")
205 real = tmp_path / ".muse" / "refs" / "heads" / "main"
206 link = tmp_path / ".muse" / "refs" / "heads" / "sym"
207 link.symlink_to(real)
208 pairs = _list_all_refs(tmp_path)
209 names = [b for b, _ in pairs]
210 assert "sym" not in names
211 assert "main" in names
212
213 def test_invalid_commit_id_skipped(self, tmp_path: pathlib.Path) -> None:
214 _init_repo(tmp_path)
215 _commit(tmp_path, "c", "main")
216 # Write a ref file with garbage content
217 bad = tmp_path / ".muse" / "refs" / "heads" / "bad-ref"
218 bad.write_text("not-a-sha256\n", encoding="utf-8")
219 pairs = _list_all_refs(tmp_path)
220 names = [b for b, _ in pairs]
221 assert "bad-ref" not in names
222 assert "main" in names
223
224 def test_missing_heads_dir_returns_empty(self, tmp_path: pathlib.Path) -> None:
225 _init_repo(tmp_path)
226 import shutil
227 shutil.rmtree(tmp_path / ".muse" / "refs" / "heads")
228 assert _list_all_refs(tmp_path) == []
229
230 def test_sorted_output(self, tmp_path: pathlib.Path) -> None:
231 _init_repo(tmp_path)
232 for b in ["zzz", "aaa", "mmm"]:
233 _commit(tmp_path, f"c-{b}", b)
234 pairs = _list_all_refs(tmp_path)
235 names = [b for b, _ in pairs]
236 assert names == sorted(names)
237
238
239 # ---------------------------------------------------------------------------
240 # Integration — basic JSON output
241 # ---------------------------------------------------------------------------
242
243
244 class TestJsonOutput:
245 def test_empty_repo(self, tmp_path: pathlib.Path) -> None:
246 _init_repo(tmp_path)
247 r = _fer(tmp_path)
248 assert r.exit_code == 0
249 data = json.loads(r.output)
250 assert data["count"] == 0
251 assert data["refs"] == []
252
253 def test_single_branch(self, tmp_path: pathlib.Path) -> None:
254 _init_repo(tmp_path)
255 cid = _commit(tmp_path, "c1")
256 r = _fer(tmp_path)
257 assert r.exit_code == 0
258 data = json.loads(r.output)
259 assert data["count"] == 1
260 ref = data["refs"][0]
261 assert ref["commit_id"] == cid
262 assert ref["branch"] == "main"
263 assert ref["ref"] == "refs/heads/main"
264
265 def test_all_fields_present(self, tmp_path: pathlib.Path) -> None:
266 _init_repo(tmp_path)
267 _commit(tmp_path, "c1")
268 r = _fer(tmp_path)
269 ref = json.loads(r.output)["refs"][0]
270 for key in ("ref", "branch", "commit_id", "author", "message", "committed_at", "snapshot_id"):
271 assert key in ref, f"missing field: {key}"
272
273 def test_json_shorthand_alias(self, tmp_path: pathlib.Path) -> None:
274 _init_repo(tmp_path)
275 _commit(tmp_path, "c1")
276 r = _fer(tmp_path, "--json")
277 assert r.exit_code == 0
278 data = json.loads(r.output)
279 assert "refs" in data
280
281 def test_hierarchical_branch_in_output(self, tmp_path: pathlib.Path) -> None:
282 """Branches with slashes in name must appear in the output."""
283 _init_repo(tmp_path)
284 _commit(tmp_path, "c-main", "main")
285 _commit(tmp_path, "c-feat", "feat/my-thing")
286 r = _fer(tmp_path)
287 assert r.exit_code == 0
288 data = json.loads(r.output)
289 branches = [ref["branch"] for ref in data["refs"]]
290 assert "feat/my-thing" in branches
291 assert data["count"] == 2
292
293 def test_multiple_branches_counted(self, tmp_path: pathlib.Path) -> None:
294 _init_repo(tmp_path)
295 for b in ["main", "dev", "feat/x", "feat/y"]:
296 _commit(tmp_path, f"c-{b}", b)
297 r = _fer(tmp_path)
298 assert r.exit_code == 0
299 data = json.loads(r.output)
300 assert data["count"] == 4
301
302
303 # ---------------------------------------------------------------------------
304 # Integration — --no-commits fast path
305 # ---------------------------------------------------------------------------
306
307
308 class TestNoCommits:
309 def test_no_commits_omits_commit_fields(self, tmp_path: pathlib.Path) -> None:
310 _init_repo(tmp_path)
311 _commit(tmp_path, "c1")
312 r = _fer(tmp_path, "--no-commits")
313 assert r.exit_code == 0
314 data = json.loads(r.output)
315 ref = data["refs"][0]
316 assert "ref" in ref
317 assert "branch" in ref
318 assert "commit_id" in ref
319 # These must be absent in --no-commits mode
320 assert "author" not in ref
321 assert "message" not in ref
322 assert "committed_at" not in ref
323
324 def test_no_commits_count_correct(self, tmp_path: pathlib.Path) -> None:
325 _init_repo(tmp_path)
326 for b in ["main", "dev", "feat/x"]:
327 _commit(tmp_path, f"c-{b}", b)
328 r = _fer(tmp_path, "--no-commits")
329 assert r.exit_code == 0
330 data = json.loads(r.output)
331 assert data["count"] == 3
332
333 def test_no_commits_text_format(self, tmp_path: pathlib.Path) -> None:
334 _init_repo(tmp_path)
335 cid = _commit(tmp_path, "c1")
336 r = _fer_text(tmp_path, "--no-commits")
337 assert r.exit_code == 0
338 line = r.output.strip()
339 assert cid in line
340 assert "refs/heads/main" in line
341 # Should NOT have 4 columns (no author column)
342 parts = line.split(" ")
343 assert len(parts) == 2
344
345 def test_no_commits_rejected_with_commit_sort_field(self, tmp_path: pathlib.Path) -> None:
346 _init_repo(tmp_path)
347 _commit(tmp_path, "c1")
348 for field in ("author", "message", "committed_at", "snapshot_id"):
349 r = _fer(tmp_path, "--no-commits", "--sort", field)
350 assert r.exit_code != 0
351 assert r.stdout_bytes == b""
352 assert "error" in r.stderr.lower()
353
354 def test_no_commits_allows_ref_level_sort(self, tmp_path: pathlib.Path) -> None:
355 _init_repo(tmp_path)
356 for b in ["zzz", "aaa"]:
357 _commit(tmp_path, f"c-{b}", b)
358 for field in ("ref", "branch", "commit_id"):
359 r = _fer(tmp_path, "--no-commits", "--sort", field)
360 assert r.exit_code == 0
361
362
363 # ---------------------------------------------------------------------------
364 # Integration — sorting
365 # ---------------------------------------------------------------------------
366
367
368 class TestSorting:
369 def test_sort_by_ref_ascending(self, tmp_path: pathlib.Path) -> None:
370 _init_repo(tmp_path)
371 for b in ["zzz", "aaa", "mmm"]:
372 _commit(tmp_path, f"c-{b}", b)
373 r = _fer(tmp_path, "--sort", "ref")
374 data = json.loads(r.output)
375 refs = [d["ref"] for d in data["refs"]]
376 assert refs == sorted(refs)
377
378 def test_sort_by_ref_descending(self, tmp_path: pathlib.Path) -> None:
379 _init_repo(tmp_path)
380 for b in ["zzz", "aaa", "mmm"]:
381 _commit(tmp_path, f"c-{b}", b)
382 r = _fer(tmp_path, "--sort", "ref", "--desc")
383 data = json.loads(r.output)
384 refs = [d["ref"] for d in data["refs"]]
385 assert refs == sorted(refs, reverse=True)
386
387 def test_sort_by_committed_at(self, tmp_path: pathlib.Path) -> None:
388 _init_repo(tmp_path)
389 base = datetime.datetime(2026, 1, 1, tzinfo=datetime.timezone.utc)
390 _commit(tmp_path, "c-b", "bbb", ts=base + datetime.timedelta(hours=2))
391 _commit(tmp_path, "c-a", "aaa", ts=base + datetime.timedelta(hours=1))
392 r = _fer(tmp_path, "--sort", "committed_at")
393 data = json.loads(r.output)
394 timestamps = [d["committed_at"] for d in data["refs"]]
395 assert timestamps == sorted(timestamps)
396
397 def test_sort_by_author(self, tmp_path: pathlib.Path) -> None:
398 _init_repo(tmp_path)
399 _commit(tmp_path, "c-main", "main", author="zara")
400 _commit(tmp_path, "c-dev", "dev", author="alice")
401 r = _fer(tmp_path, "--sort", "author")
402 data = json.loads(r.output)
403 authors = [d["author"] for d in data["refs"]]
404 assert authors == sorted(authors)
405
406 def test_sort_by_snapshot_id(self, tmp_path: pathlib.Path) -> None:
407 _init_repo(tmp_path)
408 for b in ["a", "b", "c"]:
409 _commit(tmp_path, f"snap-{b}", b)
410 r = _fer(tmp_path, "--sort", "snapshot_id")
411 assert r.exit_code == 0
412 data = json.loads(r.output)
413 sids = [d["snapshot_id"] for d in data["refs"]]
414 assert sids == sorted(sids)
415
416
417 # ---------------------------------------------------------------------------
418 # Integration — --count and --pattern
419 # ---------------------------------------------------------------------------
420
421
422 class TestCountAndPattern:
423 def test_count_limits_output(self, tmp_path: pathlib.Path) -> None:
424 _init_repo(tmp_path)
425 for b in ["aaa", "bbb", "ccc", "ddd"]:
426 _commit(tmp_path, f"c-{b}", b)
427 r = _fer(tmp_path, "--count", "2")
428 data = json.loads(r.output)
429 assert data["count"] == 2
430 assert len(data["refs"]) == 2
431
432 def test_count_zero_is_unlimited(self, tmp_path: pathlib.Path) -> None:
433 _init_repo(tmp_path)
434 for b in ["a", "b", "c"]:
435 _commit(tmp_path, f"c-{b}", b)
436 r = _fer(tmp_path, "--count", "0")
437 data = json.loads(r.output)
438 assert data["count"] == 3
439
440 def test_negative_count_errors(self, tmp_path: pathlib.Path) -> None:
441 _init_repo(tmp_path)
442 r = _fer(tmp_path, "--count", "-1")
443 assert r.exit_code != 0
444 assert r.stdout_bytes == b""
445 assert "error" in r.stderr.lower()
446
447 def test_pattern_filter_flat(self, tmp_path: pathlib.Path) -> None:
448 _init_repo(tmp_path)
449 _commit(tmp_path, "c-main", "main")
450 _commit(tmp_path, "c-dev", "dev")
451 r = _fer(tmp_path, "--pattern", "refs/heads/main")
452 data = json.loads(r.output)
453 assert data["count"] == 1
454 assert data["refs"][0]["branch"] == "main"
455
456 def test_pattern_filter_hierarchical(self, tmp_path: pathlib.Path) -> None:
457 _init_repo(tmp_path)
458 _commit(tmp_path, "c-main", "main")
459 _commit(tmp_path, "c-feat1", "feat/one")
460 _commit(tmp_path, "c-feat2", "feat/two")
461 r = _fer(tmp_path, "--pattern", "refs/heads/feat/*")
462 data = json.loads(r.output)
463 assert data["count"] == 2
464 for ref in data["refs"]:
465 assert ref["branch"].startswith("feat/")
466
467 def test_pattern_no_match_returns_empty(self, tmp_path: pathlib.Path) -> None:
468 _init_repo(tmp_path)
469 _commit(tmp_path, "c-main", "main")
470 r = _fer(tmp_path, "--pattern", "refs/heads/nonexistent/*")
471 data = json.loads(r.output)
472 assert data["count"] == 0
473
474
475 # ---------------------------------------------------------------------------
476 # Integration — text output
477 # ---------------------------------------------------------------------------
478
479
480 class TestTextOutput:
481 def test_text_format_four_columns(self, tmp_path: pathlib.Path) -> None:
482 _init_repo(tmp_path)
483 cid = _commit(tmp_path, "c1", author="alice")
484 r = _fer_text(tmp_path)
485 assert r.exit_code == 0
486 line = r.output.strip()
487 assert cid in line
488 assert "refs/heads/main" in line
489 assert "alice" in line
490
491 def test_text_multiple_lines(self, tmp_path: pathlib.Path) -> None:
492 _init_repo(tmp_path)
493 for b in ["aaa", "bbb"]:
494 _commit(tmp_path, f"c-{b}", b)
495 r = _fer_text(tmp_path)
496 lines = [l for l in r.output.strip().splitlines() if l]
497 assert len(lines) == 2
498
499
500 # ---------------------------------------------------------------------------
501 # Security
502 # ---------------------------------------------------------------------------
503
504
505 class TestSecurity:
506 def test_ansi_in_branch_name_sanitized_text(self, tmp_path: pathlib.Path) -> None:
507 """Branch names with ANSI must not appear raw in text output."""
508 _init_repo(tmp_path)
509 cid = _commit(tmp_path, "c1", "main")
510 # Directly write a ref file with ANSI in its name (via the raw FS)
511 ansi_branch_dir = tmp_path / ".muse" / "refs" / "heads" / "safe"
512 ansi_branch_dir.mkdir(parents=True, exist_ok=True)
513 # Can't create filename with ANSI; instead verify author field sanitized
514 _commit(tmp_path, "c-dev", "dev", author="\x1b[31mred\x1b[0m")
515 r = _fer_text(tmp_path)
516 assert "\x1b" not in r.output
517
518 def test_unknown_flag_exits_nonzero(self, tmp_path: pathlib.Path) -> None:
519 _init_repo(tmp_path)
520 r = _fer_text(tmp_path, "--format", "xml")
521 assert r.exit_code != 0
522
523 def test_error_sort_goes_to_stderr(self, tmp_path: pathlib.Path) -> None:
524 _init_repo(tmp_path)
525 r = _fer(tmp_path, "--sort", "invalid_field")
526 assert r.exit_code != 0
527 assert r.stdout_bytes == b""
528 assert "error" in r.stderr.lower()
529
530 def test_negative_count_error_to_stderr(self, tmp_path: pathlib.Path) -> None:
531 _init_repo(tmp_path)
532 r = _fer(tmp_path, "--count", "-5")
533 assert r.exit_code != 0
534 assert r.stdout_bytes == b""
535
536 def test_no_traceback_on_unknown_flag(self, tmp_path: pathlib.Path) -> None:
537 _init_repo(tmp_path)
538 r = _fer_text(tmp_path, "--format", "bad")
539 assert "Traceback" not in r.output
540 assert "Traceback" not in r.stderr
541
542 def test_symlink_ref_skipped_in_output(self, tmp_path: pathlib.Path) -> None:
543 _init_repo(tmp_path)
544 _commit(tmp_path, "c", "main")
545 real = tmp_path / ".muse" / "refs" / "heads" / "main"
546 link = tmp_path / ".muse" / "refs" / "heads" / "linked"
547 link.symlink_to(real)
548 r = _fer(tmp_path)
549 data = json.loads(r.output)
550 branches = [ref["branch"] for ref in data["refs"]]
551 assert "linked" not in branches
552
553 def test_corrupted_ref_skipped_in_output(self, tmp_path: pathlib.Path) -> None:
554 _init_repo(tmp_path)
555 _commit(tmp_path, "c", "main")
556 bad = tmp_path / ".muse" / "refs" / "heads" / "corrupted"
557 bad.write_text("not-a-sha\n", encoding="utf-8")
558 r = _fer(tmp_path)
559 data = json.loads(r.output)
560 branches = [ref["branch"] for ref in data["refs"]]
561 assert "corrupted" not in branches
562
563 def test_no_repo_exits_cleanly(self, tmp_path: pathlib.Path) -> None:
564 r = runner.invoke(
565 cli,
566 ["for-each-ref"],
567 env={"MUSE_REPO_ROOT": str(tmp_path / "norepo")},
568 )
569 assert r.exit_code != 0
570 assert "Traceback" not in r.output
571 assert "Traceback" not in r.stderr
572
573
574 # ---------------------------------------------------------------------------
575 # Stress
576 # ---------------------------------------------------------------------------
577
578
579 class TestStress:
580 def test_100_flat_branches(self, tmp_path: pathlib.Path) -> None:
581 _init_repo(tmp_path)
582 for i in range(100):
583 _commit(tmp_path, f"c-{i:03d}", f"branch-{i:03d}")
584 r = _fer(tmp_path)
585 assert r.exit_code == 0
586 data = json.loads(r.output)
587 assert data["count"] == 100
588
589 def test_50_hierarchical_branches(self, tmp_path: pathlib.Path) -> None:
590 """All 50 branches with slashes must be discovered via rglob."""
591 _init_repo(tmp_path)
592 for i in range(50):
593 _commit(tmp_path, f"c-{i}", f"feat/task-{i:03d}")
594 r = _fer(tmp_path)
595 assert r.exit_code == 0
596 data = json.loads(r.output)
597 assert data["count"] == 50
598 for ref in data["refs"]:
599 assert ref["branch"].startswith("feat/")
600
601 def test_no_commits_100_branches_fast(self, tmp_path: pathlib.Path) -> None:
602 _init_repo(tmp_path)
603 for i in range(100):
604 _commit(tmp_path, f"c-{i}", f"b-{i:03d}")
605 r = _fer(tmp_path, "--no-commits")
606 assert r.exit_code == 0
607 data = json.loads(r.output)
608 assert data["count"] == 100
609 # Confirm no commit metadata fields
610 for ref in data["refs"]:
611 assert "author" not in ref
612
613 def test_200_sequential_reads(self, tmp_path: pathlib.Path) -> None:
614 _init_repo(tmp_path)
615 for b in ["main", "dev"]:
616 _commit(tmp_path, f"c-{b}", b)
617 for _ in range(200):
618 r = _fer(tmp_path)
619 assert r.exit_code == 0
620 assert json.loads(r.output)["count"] == 2
File History 3 commits
sha256:b636f72dcba9e190afb980bece906fa5b717fbde014b76ef023df8cb96e01eb9 docs: expand cache plan with all seven testing tiers and do… Sonnet 4.6 131 days ago
sha256:7f9e2ef5286aedad9c1e6011b4c46ca27f39dbdad6e3409357e36b26e46b3b7c docs: docstring sprint for-each-ref→hotspots — idiomatic ru… Sonnet 4.6 patch 137 days ago
sha256:a09b1b4f6838754495547f200aa0ce88e2f56ffc5b20b900f6f0cff2c3cdede9 fix(cursorignore): remove git-ism (.git/worktrees) Human minor 140 days ago