codeflash/tests/code_utils/test_coverage_utils.py
Kevin Turcios eceac13fc3 Merge remote-tracking branch 'origin/main' into omni-java
# Conflicts:
#	.claude/rules/architecture.md
#	.claude/rules/code-style.md
#	.github/workflows/claude.yml
#	.github/workflows/duplicate-code-detector.yml
#	codeflash/api/aiservice.py
#	codeflash/cli_cmds/console.py
#	codeflash/cli_cmds/logging_config.py
#	codeflash/code_utils/deduplicate_code.py
#	codeflash/discovery/discover_unit_tests.py
#	codeflash/languages/base.py
#	codeflash/languages/code_replacer.py
#	codeflash/languages/javascript/mocha_runner.py
#	codeflash/languages/javascript/support.py
#	codeflash/languages/python/support.py
#	codeflash/optimization/function_optimizer.py
#	codeflash/verification/parse_test_output.py
#	codeflash/verification/verification_utils.py
#	codeflash/verification/verifier.py
#	packages/codeflash/package-lock.json
#	packages/codeflash/package.json
#	tests/languages/javascript/test_support_dispatch.py
#	tests/test_codeflash_capture.py
#	tests/test_languages/test_javascript_test_runner.py
#	tests/test_multi_file_code_replacement.py
2026-03-04 01:52:32 -05:00

231 lines
11 KiB
Python

from __future__ import annotations
from typing import Any
from codeflash.languages.python.static_analysis.coverage_utils import (
build_fully_qualified_name,
extract_dependent_function,
)
from codeflash.models.function_types import FunctionParent
from codeflash.models.models import CodeOptimizationContext, CodeString, CodeStringsMarkdown
from codeflash.verification.coverage_utils import CoverageUtils
def _make_code_context(
preexisting_objects: set[tuple[str, tuple[FunctionParent, ...]]],
testgen_code_strings: list[CodeString] | None = None,
) -> CodeOptimizationContext:
"""Helper to create a minimal CodeOptimizationContext for testing."""
return CodeOptimizationContext(
testgen_context=CodeStringsMarkdown(code_strings=testgen_code_strings or []),
read_writable_code=CodeStringsMarkdown(),
helper_functions=[],
preexisting_objects=preexisting_objects,
)
class TestBuildFullyQualifiedName:
def test_bare_name_with_class_parent(self) -> None:
ctx = _make_code_context({("__init__", (FunctionParent(name="HttpInterface", type="ClassDef"),))})
assert build_fully_qualified_name("__init__", ctx) == "HttpInterface.__init__"
def test_bare_name_no_parent(self) -> None:
ctx = _make_code_context({("helper_func", ())})
assert build_fully_qualified_name("helper_func", ctx) == "helper_func"
def test_already_qualified_name_returned_as_is(self) -> None:
"""If name already contains a dot, skip preexisting_objects lookup."""
ctx = _make_code_context({("__init__", (FunctionParent(name="WrongClass", type="ClassDef"),))})
result = build_fully_qualified_name("HttpInterface.__init__", ctx)
assert result == "HttpInterface.__init__"
def test_bare_name_picks_first_match_from_set(self) -> None:
"""With multiple __init__ entries, bare name picks an arbitrary one."""
ctx = _make_code_context(
{
("__init__", (FunctionParent(name="ClassA", type="ClassDef"),)),
("__init__", (FunctionParent(name="ClassB", type="ClassDef"),)),
}
)
result = build_fully_qualified_name("__init__", ctx)
assert result in {"ClassA.__init__", "ClassB.__init__"}
def test_qualified_name_avoids_ambiguity(self) -> None:
"""Qualified name bypasses preexisting_objects entirely, avoiding ambiguity."""
ctx = _make_code_context(
{
("__init__", (FunctionParent(name="ClassA", type="ClassDef"),)),
("__init__", (FunctionParent(name="ClassB", type="ClassDef"),)),
}
)
assert build_fully_qualified_name("ClassB.__init__", ctx) == "ClassB.__init__"
def test_bare_name_not_in_preexisting_objects(self) -> None:
ctx = _make_code_context(set())
assert build_fully_qualified_name("some_func", ctx) == "some_func"
def test_nested_class_parent(self) -> None:
"""Bare name under nested class parents gets fully qualified."""
ctx = _make_code_context(
{("method", (FunctionParent(name="Outer", type="ClassDef"), FunctionParent(name="Inner", type="ClassDef")))}
)
assert build_fully_qualified_name("method", ctx) == "Inner.Outer.method"
def test_non_classdef_parent_ignored(self) -> None:
"""Only ClassDef parents are prepended to the name."""
ctx = _make_code_context({("helper", (FunctionParent(name="wrapper", type="FunctionDef"),))})
assert build_fully_qualified_name("helper", ctx) == "helper"
class TestExtractDependentFunction:
def test_single_dependent_function(self) -> None:
ctx = _make_code_context(
preexisting_objects={("helper", ())},
testgen_code_strings=[CodeString(code="def main_func(): pass\ndef helper(): pass")],
)
result = extract_dependent_function("main_func", ctx)
assert result == "helper"
def test_qualified_main_function_discards_bare_match(self) -> None:
"""Qualified main_function should still discard the matching bare name."""
ctx = _make_code_context(
preexisting_objects={("helper", ())},
testgen_code_strings=[CodeString(code="def __init__(): pass\ndef helper(): pass")],
)
result = extract_dependent_function("HttpInterface.__init__", ctx)
assert result == "helper"
def test_bare_main_function_discards_match(self) -> None:
"""Bare main_function should still work for discarding."""
ctx = _make_code_context(
preexisting_objects={("helper", ())},
testgen_code_strings=[CodeString(code="def main_func(): pass\ndef helper(): pass")],
)
result = extract_dependent_function("main_func", ctx)
assert result == "helper"
def test_no_dependent_functions(self) -> None:
ctx = _make_code_context(preexisting_objects=set(), testgen_code_strings=[CodeString(code="x = 1\n")])
result = extract_dependent_function("main_func", ctx)
assert result is False
def test_multiple_dependent_functions_returns_false(self) -> None:
ctx = _make_code_context(
preexisting_objects=set(),
testgen_code_strings=[CodeString(code="def helper_a(): pass\ndef helper_b(): pass")],
)
result = extract_dependent_function("main_func", ctx)
assert result is False
def test_dependent_function_gets_qualified(self) -> None:
"""The dependent function returned should be qualified via build_fully_qualified_name."""
ctx = _make_code_context(
preexisting_objects={("helper", (FunctionParent(name="MyClass", type="ClassDef"),))},
testgen_code_strings=[CodeString(code="def main_func(): pass\ndef helper(): pass")],
)
result = extract_dependent_function("main_func", ctx)
assert result == "MyClass.helper"
def test_only_main_in_code_returns_false(self) -> None:
"""When code only contains the main function, no dependent function exists."""
ctx = _make_code_context(
preexisting_objects=set(), testgen_code_strings=[CodeString(code="def __init__(): pass")]
)
result = extract_dependent_function("HttpInterface.__init__", ctx)
assert result is False
def test_async_functions_extracted(self) -> None:
"""Async function definitions are also extracted as dependent functions."""
ctx = _make_code_context(
preexisting_objects={("async_helper", ())},
testgen_code_strings=[CodeString(code="def main(): pass\nasync def async_helper(): pass")],
)
result = extract_dependent_function("main", ctx)
assert result == "async_helper"
class TestGrabDependentFunctionFromCoverageData:
def _make_func_data(self, coverage_pct: float = 80.0) -> dict[str, Any]:
return {
"summary": {"percent_covered": coverage_pct},
"executed_lines": [1, 2, 3],
"missing_lines": [4],
"executed_branches": [[1, 0]],
"missing_branches": [[2, 1]],
}
def test_exact_match_in_coverage_data(self) -> None:
coverage_data = {"HttpInterface.__init__": self._make_func_data(90.0)}
result = CoverageUtils.grab_dependent_function_from_coverage_data("HttpInterface.__init__", coverage_data, {})
assert result.name == "HttpInterface.__init__"
assert result.coverage == 90.0
def test_fallback_exact_match_in_original_data(self) -> None:
original_cov_data = {
"files": {"http_api.py": {"functions": {"HttpInterface.__init__": self._make_func_data(75.0)}}}
}
result = CoverageUtils.grab_dependent_function_from_coverage_data(
"HttpInterface.__init__", {}, original_cov_data
)
assert result.name == "HttpInterface.__init__"
assert result.coverage == 75.0
def test_fallback_suffix_match_in_original_data(self) -> None:
"""Qualified dependent name matches via suffix in original coverage data."""
original_cov_data = {
"files": {"http_api.py": {"functions": {"module.HttpInterface.__init__": self._make_func_data(60.0)}}}
}
result = CoverageUtils.grab_dependent_function_from_coverage_data(
"HttpInterface.__init__", {}, original_cov_data
)
assert result.name == "HttpInterface.__init__"
assert result.coverage == 60.0
def test_no_false_substring_match_bare_init(self) -> None:
"""Bare __init__ should NOT match PathAwareCORSMiddleware.__init__ via substring."""
original_cov_data = {
"files": {"cors.py": {"functions": {"PathAwareCORSMiddleware.__init__": self._make_func_data(50.0)}}}
}
result = CoverageUtils.grab_dependent_function_from_coverage_data("__init__", {}, original_cov_data)
assert result.coverage == 0
def test_no_false_substring_match_different_class(self) -> None:
"""Qualified name for one class should not match another class's method."""
original_cov_data = {
"files": {
"api.py": {
"functions": {
"PathAwareCORSMiddleware.__init__": self._make_func_data(50.0),
"HttpInterface.__init__": self._make_func_data(85.0),
}
}
}
}
result = CoverageUtils.grab_dependent_function_from_coverage_data(
"HttpInterface.__init__", {}, original_cov_data
)
assert result.name == "HttpInterface.__init__"
assert result.coverage == 85.0
def test_no_match_returns_zero_coverage(self) -> None:
result = CoverageUtils.grab_dependent_function_from_coverage_data("nonexistent_func", {}, {"files": {}})
assert result.coverage == 0
assert result.executed_lines == []
def test_qualified_suffix_no_match_for_partial_name(self) -> None:
"""Ensure suffix match requires a dot boundary, not just string suffix."""
original_cov_data = {
"files": {"api.py": {"functions": {"XHttpInterface.__init__": self._make_func_data(40.0)}}}
}
# "HttpInterface.__init__" should NOT match "XHttpInterface.__init__" via suffix
result = CoverageUtils.grab_dependent_function_from_coverage_data(
"HttpInterface.__init__", {}, original_cov_data
)
assert result.coverage == 0
def test_bare_name_exact_match_in_fallback(self) -> None:
"""Bare function name should still work with exact match in fallback."""
original_cov_data = {"files": {"utils.py": {"functions": {"helper_func": self._make_func_data(95.0)}}}}
result = CoverageUtils.grab_dependent_function_from_coverage_data("helper_func", {}, original_cov_data)
assert result.name == "helper_func"
assert result.coverage == 95.0