codeflash/tests/test_get_code.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

281 lines
8.1 KiB
Python

import tempfile
from pathlib import Path
import pytest
from codeflash.discovery.functions_to_optimize import FunctionToOptimize
from codeflash.languages.python.static_analysis.code_extractor import get_code
from codeflash.models.models import FunctionParent
@pytest.fixture
def temp_dir():
with tempfile.TemporaryDirectory() as tmpdirname:
yield Path(tmpdirname)
def test_get_code_function(temp_dir: Path) -> None:
code = """def test(self):
return self._test"""
with (temp_dir / "temp_file.py").open(mode="w") as f:
f.write(code)
f.flush()
new_code, contextual_dunder_methods = get_code([FunctionToOptimize("test", f.name, [])])
assert new_code == code
assert contextual_dunder_methods == set()
def test_get_code_property(temp_dir: Path) -> None:
code = """class TestClass:
def __init__(self):
self._test = 5
@property
def test(self):
return self._test"""
with (temp_dir / "temp_file.py").open(mode="w") as f:
f.write(code)
f.flush()
new_code, contextual_dunder_methods = get_code(
[FunctionToOptimize("test", f.name, [FunctionParent("TestClass", "ClassDef")])]
)
assert new_code == code
assert contextual_dunder_methods == {("TestClass", "__init__")}
def test_get_code_class(temp_dir: Path) -> None:
code = """
class TestClass:
def __init__(self):
self._test = 5
def test_method(self):
return self._test + 1
@property
def test(self):
return self._test"""
expected = """class TestClass:
def __init__(self):
self._test = 5
@property
def test(self):
return self._test"""
with (temp_dir / "temp_file.py").open(mode="w") as f:
f.write(code)
f.flush()
new_code, contextual_dunder_methods = get_code(
[FunctionToOptimize("test", f.name, [FunctionParent("TestClass", "ClassDef")])]
)
assert new_code == expected
assert contextual_dunder_methods == {("TestClass", "__init__")}
def test_get_code_bubble_sort_class(temp_dir: Path) -> None:
code = """
def hi():
pass
class BubbleSortClass:
def __init__(self):
pass
def __call__(self):
pass
def sorter(self, arr):
for i in range(len(arr)):
for j in range(len(arr) - 1):
if arr[j] > arr[j + 1]:
temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
return arr
def helper(self, arr, j):
return arr[j] > arr[j + 1]
"""
expected = """class BubbleSortClass:
def __init__(self):
pass
def __call__(self):
pass
def sorter(self, arr):
for i in range(len(arr)):
for j in range(len(arr) - 1):
if arr[j] > arr[j + 1]:
temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
return arr
"""
with (temp_dir / "temp_file.py").open(mode="w") as f:
f.write(code)
f.flush()
new_code, contextual_dunder_methods = get_code(
[FunctionToOptimize("sorter", f.name, [FunctionParent("BubbleSortClass", "ClassDef")])]
)
assert new_code == expected
assert contextual_dunder_methods == {("BubbleSortClass", "__init__"), ("BubbleSortClass", "__call__")}
def test_get_code_indent(temp_dir: Path) -> None:
code = """def hi():
pass
def hello():
pass
class BubbleSortClass:
def __init__(self):
pass
def unsorter(self, arr):
return shuffle(arr)
def __call__(self):
pass
def sorter(self, arr):
for i in range(len(arr)):
for j in range(len(arr) - 1):
if arr[j] > arr[j + 1]:
temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
return arr
def helper(self, arr, j):
return arr[j] > arr[j + 1]
def oui():
pass
def non():
pass
"""
expected = """class BubbleSortClass:
def __init__(self):
pass
def __call__(self):
pass
def sorter(self, arr):
for i in range(len(arr)):
for j in range(len(arr) - 1):
if arr[j] > arr[j + 1]:
temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
return arr
def helper(self, arr, j):
return arr[j] > arr[j + 1]
"""
with (temp_dir / "temp_file.py").open(mode="w") as f:
f.write(code)
f.flush()
new_code, contextual_dunder_methods = get_code(
[
FunctionToOptimize("sorter", f.name, [FunctionParent("BubbleSortClass", "ClassDef")]),
FunctionToOptimize("helper", f.name, [FunctionParent("BubbleSortClass", "ClassDef")]),
]
)
assert new_code == expected
assert contextual_dunder_methods == {("BubbleSortClass", "__init__"), ("BubbleSortClass", "__call__")}
expected2 = """class BubbleSortClass:
def __init__(self):
pass
def __call__(self):
pass
def sorter(self, arr):
for i in range(len(arr)):
for j in range(len(arr) - 1):
if arr[j] > arr[j + 1]:
temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
return arr
def helper(self, arr, j):
return arr[j] > arr[j + 1]
def unsorter(self, arr):
return shuffle(arr)
"""
with (temp_dir / "temp_file.py").open(mode="w") as f:
f.write(code)
f.flush()
new_code, contextual_dunder_methods = get_code(
[
FunctionToOptimize("sorter", f.name, [FunctionParent("BubbleSortClass", "ClassDef")]),
FunctionToOptimize("helper", f.name, [FunctionParent("BubbleSortClass", "ClassDef")]),
FunctionToOptimize("unsorter", f.name, [FunctionParent("BubbleSortClass", "ClassDef")]),
]
)
assert new_code == expected2
assert contextual_dunder_methods == {("BubbleSortClass", "__init__"), ("BubbleSortClass", "__call__")}
def test_get_code_multiline_class_def(temp_dir: Path) -> None:
code = """class StatementAssignmentVariableConstantMutable(
StatementAssignmentVariableMixin, StatementAssignmentVariableConstantMutableBase
):
kind = "STATEMENT_ASSIGNMENT_VARIABLE_CONSTANT_MUTABLE"
def postInitNode(self):
self.variable_trace = None
self.inplace_suspect = None
def computeStatement(self, trace_collection):
return self, None, None
@staticmethod
def hasVeryTrustedValue():
return False
"""
expected = """class StatementAssignmentVariableConstantMutable(
StatementAssignmentVariableMixin, StatementAssignmentVariableConstantMutableBase
):
def computeStatement(self, trace_collection):
return self, None, None
"""
with (temp_dir / "temp_file.py").open(mode="w") as f:
f.write(code)
f.flush()
new_code, contextual_dunder_methods = get_code(
[
FunctionToOptimize(
"computeStatement",
f.name,
[FunctionParent("StatementAssignmentVariableConstantMutable", "ClassDef")],
)
]
)
assert new_code == expected
assert contextual_dunder_methods == set()
def test_get_code_dataclass_attribute(temp_dir: Path) -> None:
code = """@dataclass
class CustomDataClass:
name: str = ""
data: List[int] = field(default_factory=list)"""
with (temp_dir / "temp_file.py").open(mode="w") as f:
f.write(code)
f.flush()
# This is not something that should ever happen with the current implementation, as get_code only runs with a
# single FunctionToOptimize instance, in the case where that instance has been filtered to represent a function
# (with a definition).
new_code, contextual_dunder_methods = get_code(
[FunctionToOptimize("name", f.name, [FunctionParent("CustomDataClass", "ClassDef")])]
)
assert new_code is None
assert contextual_dunder_methods == set()