"""ASV benchmarks for diff review artifact building and serialization. Measures the performance of: - DiffBuilder.build() with various changeset sizes - DiffSerializer.to_plain() / to_json() / to_rich() - Rename detection with content hash matching - ReviewArtifact and DiffEntry construction """ from __future__ import annotations import sys from pathlib import Path try: from cleveragents.domain.models.core.change import ( ChangeEntry, ChangeOperation, SpecChangeSet, ) from cleveragents.domain.models.core.diff_review import ( DiffBuilder, DiffEntry, DiffSerializer, ResourceDiffGroup, ReviewArtifact, ) except ModuleNotFoundError: sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src")) from cleveragents.domain.models.core.change import ( ChangeEntry, ChangeOperation, SpecChangeSet, ) from cleveragents.domain.models.core.diff_review import ( DiffBuilder, DiffEntry, DiffSerializer, ResourceDiffGroup, ReviewArtifact, ) def _make_changeset( n_entries: int = 10, ) -> tuple[SpecChangeSet, dict[str, str], dict[str, str]]: """Create a changeset with n_entries MODIFY entries and content maps.""" cs = SpecChangeSet(plan_id="BENCH-PLAN") before_map: dict[str, str] = {} after_map: dict[str, str] = {} for i in range(n_entries): path = f"src/module_{i:04d}.py" cs.add_change( ChangeEntry( plan_id="BENCH-PLAN", resource_id=f"RES{i % 5:03d}", tool_name="builtin/bench-tool", operation=ChangeOperation.MODIFY, path=path, before_hash=f"before-{i}", after_hash=f"after-{i}", ) ) before_map[path] = f"# module {i}\nx = {i}\n" after_map[path] = f"# module {i}\nx = {i + 1}\ny = {i}\n" return cs, before_map, after_map class DiffBuildSuite: """Benchmark DiffBuilder.build() with various changeset sizes.""" def setup(self) -> None: """Prepare changesets of different sizes.""" self.builder = DiffBuilder() self.cs_small, self.bm_small, self.am_small = _make_changeset(5) self.cs_medium, self.bm_medium, self.am_medium = _make_changeset(50) self.cs_large, self.bm_large, self.am_large = _make_changeset(200) def time_build_small(self) -> None: """Benchmark building artifact from 5-entry changeset.""" self.builder.build( self.cs_small, before_contents=self.bm_small, after_contents=self.am_small, ) def time_build_medium(self) -> None: """Benchmark building artifact from 50-entry changeset.""" self.builder.build( self.cs_medium, before_contents=self.bm_medium, after_contents=self.am_medium, ) def time_build_large(self) -> None: """Benchmark building artifact from 200-entry changeset.""" self.builder.build( self.cs_large, before_contents=self.bm_large, after_contents=self.am_large, ) class DiffSerializationSuite: """Benchmark DiffSerializer output formats.""" def setup(self) -> None: """Build an artifact to serialize.""" cs, bm, am = _make_changeset(20) builder = DiffBuilder() self.artifact = builder.build(cs, before_contents=bm, after_contents=am) def time_to_plain(self) -> None: """Benchmark plain text serialization.""" DiffSerializer.to_plain(self.artifact) def time_to_json(self) -> None: """Benchmark JSON serialization.""" DiffSerializer.to_json(self.artifact) def time_to_rich(self) -> None: """Benchmark rich text serialization.""" DiffSerializer.to_rich(self.artifact) class DiffRenameSuite: """Benchmark rename detection with content hash matching.""" def setup(self) -> None: """Prepare a changeset with rename pairs.""" self.builder = DiffBuilder() self.cs = SpecChangeSet(plan_id="BENCH-PLAN") for i in range(20): self.cs.add_change( ChangeEntry( plan_id="BENCH-PLAN", resource_id="RES001", tool_name="builtin/bench-tool", operation=ChangeOperation.DELETE, path=f"old/module_{i:04d}.py", before_hash=f"hash-{i}", ) ) self.cs.add_change( ChangeEntry( plan_id="BENCH-PLAN", resource_id="RES001", tool_name="builtin/bench-tool", operation=ChangeOperation.CREATE, path=f"new/module_{i:04d}.py", after_hash=f"hash-{i}", ) ) def time_rename_detection(self) -> None: """Benchmark rename detection for 20 pairs.""" self.builder.build(self.cs) class DiffModelSuite: """Benchmark DiffEntry and ReviewArtifact construction.""" def time_diff_entry_construction(self) -> None: """Benchmark creating a DiffEntry.""" DiffEntry( resource_id="RES001", resource_name="test-resource", path="src/main.py", change_type="modify", diff_text="--- a/src/main.py\n+++ b/src/main.py\n", ) def time_resource_diff_group_construction(self) -> None: """Benchmark creating a ResourceDiffGroup.""" ResourceDiffGroup( resource_id="RES001", resource_name="test-resource", entries=[ DiffEntry( resource_id="RES001", path="a.py", change_type="create", ), DiffEntry( resource_id="RES001", path="b.py", change_type="modify", ), ], ) def time_review_artifact_construction(self) -> None: """Benchmark creating a ReviewArtifact.""" ReviewArtifact( plan_id="PLAN001", changeset_id="CS001", total_changes=5, )