Skip to content

Commit 9b247ef

Browse files
committed
test(extractor): cover block/segment gate branches and hash reuse fallback
1 parent 67a2a16 commit 9b247ef

2 files changed

Lines changed: 106 additions & 1 deletion

File tree

tests/test_extractor.py

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,111 @@ def f():
374374
assert segments == []
375375

376376

377+
def test_extract_generates_segments_without_blocks_when_only_segment_gate_met() -> None:
378+
lines = ["def f():"]
379+
for i in range(12):
380+
lines.append(f" x{i} = {i}")
381+
lines.append("")
382+
lines.append("")
383+
src = "\n".join(lines)
384+
385+
units, blocks, segments = extract_units_from_source(
386+
source=src,
387+
filepath="x.py",
388+
module_name="mod",
389+
cfg=NormalizationConfig(),
390+
min_loc=1,
391+
min_stmt=1,
392+
)
393+
394+
assert units
395+
assert blocks == []
396+
assert segments
397+
398+
399+
def test_extract_generates_blocks_without_segments_when_only_block_gate_met() -> None:
400+
lines = ["def f():"]
401+
for i in range(10):
402+
lines.append(f" x{i} = {i}")
403+
lines.append("")
404+
lines.append("")
405+
lines.append("")
406+
lines.append("")
407+
src = "\n".join(lines)
408+
409+
units, blocks, segments = extract_units_from_source(
410+
source=src,
411+
filepath="x.py",
412+
module_name="mod",
413+
cfg=NormalizationConfig(),
414+
min_loc=1,
415+
min_stmt=1,
416+
)
417+
418+
assert units
419+
assert blocks
420+
assert segments == []
421+
422+
423+
def test_extract_handles_non_list_function_body_for_hash_reuse(
424+
monkeypatch: pytest.MonkeyPatch,
425+
) -> None:
426+
lines = ["def f():"]
427+
for i in range(12):
428+
lines.append(f" x{i} = {i}")
429+
lines.append("")
430+
lines.append("")
431+
tree = ast.parse("\n".join(lines))
432+
func = tree.body[0]
433+
assert isinstance(func, ast.FunctionDef)
434+
func.body = tuple(func.body) # type: ignore[assignment]
435+
436+
captured_hashes: dict[str, object] = {}
437+
438+
def _fake_parse(_source: str, _timeout_s: int) -> ast.AST:
439+
return tree
440+
441+
def _fake_fingerprint(
442+
_node: ast.FunctionDef | ast.AsyncFunctionDef,
443+
_cfg: NormalizationConfig,
444+
_qualname: str,
445+
) -> str:
446+
return "f" * 40
447+
448+
def _fake_extract_segments(
449+
_node: ast.FunctionDef | ast.AsyncFunctionDef,
450+
filepath: str,
451+
qualname: str,
452+
cfg: NormalizationConfig,
453+
window_size: int = 6,
454+
max_segments: int = 60,
455+
*,
456+
precomputed_hashes: list[str] | None = None,
457+
) -> list[object]:
458+
del filepath, qualname, cfg, window_size, max_segments
459+
captured_hashes["value"] = precomputed_hashes
460+
return []
461+
462+
monkeypatch.setattr(extractor, "_parse_with_limits", _fake_parse)
463+
monkeypatch.setattr(extractor, "_stmt_count", lambda _node: 12)
464+
monkeypatch.setattr(extractor, "get_cfg_fingerprint", _fake_fingerprint)
465+
monkeypatch.setattr(extractor, "extract_segments", _fake_extract_segments)
466+
467+
units, blocks, segments = extract_units_from_source(
468+
source="def f():\n pass\n",
469+
filepath="x.py",
470+
module_name="mod",
471+
cfg=NormalizationConfig(),
472+
min_loc=1,
473+
min_stmt=1,
474+
)
475+
476+
assert len(units) == 1
477+
assert blocks == []
478+
assert segments == []
479+
assert captured_hashes["value"] is None
480+
481+
377482
def test_extract_skips_invalid_positions(monkeypatch: pytest.MonkeyPatch) -> None:
378483
tree = ast.parse(
379484
"""

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)