Skip to content

Commit 6ed9387

Browse files
committed
add more tests
1 parent f6b3275 commit 6ed9387

File tree

1 file changed

+335
-0
lines changed

1 file changed

+335
-0
lines changed

tests/test_code_context_extractor.py

Lines changed: 335 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2137,3 +2137,338 @@ def __init__(self, precision="high", fallback_precision=None, mode="standard"):
21372137
"""
21382138
assert read_write_context.strip() == expected_read_write_context.strip()
21392139
assert read_only_context.strip() == expected_read_only_context.strip()
2140+
2141+
2142+
from __future__ import annotations
2143+
2144+
2145+
def test_hashing_code_context_removes_imports_docstrings_and_init() -> None:
2146+
"""Test that hashing context removes imports, docstrings, and __init__ methods properly."""
2147+
code = '''
2148+
import os
2149+
import sys
2150+
from pathlib import Path
2151+
2152+
class MyClass:
2153+
"""A class with a docstring."""
2154+
def __init__(self, value):
2155+
"""Initialize with a value."""
2156+
self.value = value
2157+
2158+
def target_method(self):
2159+
"""Target method with docstring."""
2160+
result = self.helper_method()
2161+
helper_cls = HelperClass()
2162+
data = helper_cls.process_data()
2163+
return self.value * 2
2164+
2165+
def helper_method(self):
2166+
"""Helper method with docstring."""
2167+
return self.value + 1
2168+
2169+
class HelperClass:
2170+
"""Helper class docstring."""
2171+
def __init__(self):
2172+
"""Helper init method."""
2173+
self.data = "test"
2174+
2175+
def process_data(self):
2176+
"""Process data method."""
2177+
return self.data.upper()
2178+
2179+
def standalone_function():
2180+
"""Standalone function."""
2181+
return "standalone"
2182+
'''
2183+
with tempfile.NamedTemporaryFile(mode="w") as f:
2184+
f.write(code)
2185+
f.flush()
2186+
file_path = Path(f.name).resolve()
2187+
opt = Optimizer(
2188+
Namespace(
2189+
project_root=file_path.parent.resolve(),
2190+
disable_telemetry=True,
2191+
tests_root="tests",
2192+
test_framework="pytest",
2193+
pytest_cmd="pytest",
2194+
experiment_id=None,
2195+
test_project_root=Path().resolve(),
2196+
)
2197+
)
2198+
function_to_optimize = FunctionToOptimize(
2199+
function_name="target_method",
2200+
file_path=file_path,
2201+
parents=[FunctionParent(name="MyClass", type="ClassDef")],
2202+
starting_line=None,
2203+
ending_line=None,
2204+
)
2205+
2206+
code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root)
2207+
hashing_context = code_ctx.hashing_code_context
2208+
2209+
# Expected behavior based on current implementation:
2210+
# - Should not contain imports
2211+
# - Should remove docstrings from target functions (but currently doesn't - this is a bug)
2212+
# - Should not contain __init__ methods
2213+
# - Should contain target function and helper methods that are actually called
2214+
# - Should be formatted as markdown
2215+
2216+
# Test that it's formatted as markdown
2217+
assert hashing_context.startswith("```python:")
2218+
assert hashing_context.endswith("```")
2219+
2220+
# Test basic structure requirements
2221+
assert "import" not in hashing_context # Should not contain imports
2222+
assert "__init__" not in hashing_context # Should not contain __init__ methods
2223+
assert "target_method" in hashing_context # Should contain target function
2224+
assert "standalone_function" not in hashing_context # Should not contain unused functions
2225+
2226+
# Test that helper functions are included when they're called
2227+
assert "helper_method" in hashing_context # Should contain called helper method
2228+
assert "process_data" in hashing_context # Should contain called helper method
2229+
2230+
# Test for docstring removal (this should pass when implementation is fixed)
2231+
# Currently this will fail because docstrings are not being removed properly
2232+
assert '"""Target method with docstring."""' not in hashing_context, (
2233+
"Docstrings should be removed from target functions"
2234+
)
2235+
assert '"""Helper method with docstring."""' not in hashing_context, (
2236+
"Docstrings should be removed from helper functions"
2237+
)
2238+
assert '"""Process data method."""' not in hashing_context, (
2239+
"Docstrings should be removed from helper class methods"
2240+
)
2241+
2242+
2243+
def test_hashing_code_context_with_nested_classes() -> None:
2244+
"""Test that hashing context handles nested classes properly (should exclude them)."""
2245+
code = '''
2246+
class OuterClass:
2247+
"""Outer class docstring."""
2248+
def __init__(self):
2249+
"""Outer init."""
2250+
self.value = 1
2251+
2252+
def target_method(self):
2253+
"""Target method."""
2254+
return self.NestedClass().nested_method()
2255+
2256+
class NestedClass:
2257+
"""Nested class - should be excluded."""
2258+
def __init__(self):
2259+
self.nested_value = 2
2260+
2261+
def nested_method(self):
2262+
return self.nested_value
2263+
'''
2264+
with tempfile.NamedTemporaryFile(mode="w") as f:
2265+
f.write(code)
2266+
f.flush()
2267+
file_path = Path(f.name).resolve()
2268+
opt = Optimizer(
2269+
Namespace(
2270+
project_root=file_path.parent.resolve(),
2271+
disable_telemetry=True,
2272+
tests_root="tests",
2273+
test_framework="pytest",
2274+
pytest_cmd="pytest",
2275+
experiment_id=None,
2276+
test_project_root=Path().resolve(),
2277+
)
2278+
)
2279+
function_to_optimize = FunctionToOptimize(
2280+
function_name="target_method",
2281+
file_path=file_path,
2282+
parents=[FunctionParent(name="OuterClass", type="ClassDef")],
2283+
starting_line=None,
2284+
ending_line=None,
2285+
)
2286+
2287+
code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root)
2288+
hashing_context = code_ctx.hashing_code_context
2289+
2290+
# Test basic requirements
2291+
assert hashing_context.startswith("```python:")
2292+
assert hashing_context.endswith("```")
2293+
assert "target_method" in hashing_context
2294+
assert "__init__" not in hashing_context # Should not contain __init__ methods
2295+
2296+
# Verify nested classes are excluded from the hashing context
2297+
# The prune_cst_for_code_hashing function should not recurse into nested classes
2298+
assert "class NestedClass:" not in hashing_context # Nested class definition should not be present
2299+
2300+
# The target method will reference NestedClass, but the actual nested class definition should not be included
2301+
# The call to self.NestedClass().nested_method() should be in the target method but the nested class itself excluded
2302+
target_method_call_present = "self.NestedClass().nested_method()" in hashing_context
2303+
assert target_method_call_present, "The target method should contain the call to nested class"
2304+
2305+
# But the actual nested method definition should not be present
2306+
nested_method_definition_present = "def nested_method(self):" in hashing_context
2307+
assert not nested_method_definition_present, "Nested method definition should not be present in hashing context"
2308+
2309+
2310+
def test_hashing_code_context_hash_consistency() -> None:
2311+
"""Test that the same code produces the same hash."""
2312+
code = """
2313+
class TestClass:
2314+
def target_method(self):
2315+
return "test"
2316+
"""
2317+
with tempfile.NamedTemporaryFile(mode="w") as f:
2318+
f.write(code)
2319+
f.flush()
2320+
file_path = Path(f.name).resolve()
2321+
opt = Optimizer(
2322+
Namespace(
2323+
project_root=file_path.parent.resolve(),
2324+
disable_telemetry=True,
2325+
tests_root="tests",
2326+
test_framework="pytest",
2327+
pytest_cmd="pytest",
2328+
experiment_id=None,
2329+
test_project_root=Path().resolve(),
2330+
)
2331+
)
2332+
function_to_optimize = FunctionToOptimize(
2333+
function_name="target_method",
2334+
file_path=file_path,
2335+
parents=[FunctionParent(name="TestClass", type="ClassDef")],
2336+
starting_line=None,
2337+
ending_line=None,
2338+
)
2339+
2340+
# Generate context twice
2341+
code_ctx1 = get_code_optimization_context(function_to_optimize, opt.args.project_root)
2342+
code_ctx2 = get_code_optimization_context(function_to_optimize, opt.args.project_root)
2343+
2344+
# Hash should be consistent
2345+
assert code_ctx1.hashing_code_context_hash == code_ctx2.hashing_code_context_hash
2346+
assert code_ctx1.hashing_code_context == code_ctx2.hashing_code_context
2347+
2348+
# Hash should be valid SHA256
2349+
import hashlib
2350+
2351+
expected_hash = hashlib.sha256(code_ctx1.hashing_code_context.encode("utf-8")).hexdigest()
2352+
assert code_ctx1.hashing_code_context_hash == expected_hash
2353+
2354+
2355+
def test_hashing_code_context_different_code_different_hash() -> None:
2356+
"""Test that different code produces different hashes."""
2357+
code1 = """
2358+
class TestClass:
2359+
def target_method(self):
2360+
return "test1"
2361+
"""
2362+
code2 = """
2363+
class TestClass:
2364+
def target_method(self):
2365+
return "test2"
2366+
"""
2367+
2368+
with tempfile.NamedTemporaryFile(mode="w") as f1, tempfile.NamedTemporaryFile(mode="w") as f2:
2369+
f1.write(code1)
2370+
f1.flush()
2371+
f2.write(code2)
2372+
f2.flush()
2373+
2374+
file_path1 = Path(f1.name).resolve()
2375+
file_path2 = Path(f2.name).resolve()
2376+
2377+
opt1 = Optimizer(
2378+
Namespace(
2379+
project_root=file_path1.parent.resolve(),
2380+
disable_telemetry=True,
2381+
tests_root="tests",
2382+
test_framework="pytest",
2383+
pytest_cmd="pytest",
2384+
experiment_id=None,
2385+
test_project_root=Path().resolve(),
2386+
)
2387+
)
2388+
opt2 = Optimizer(
2389+
Namespace(
2390+
project_root=file_path2.parent.resolve(),
2391+
disable_telemetry=True,
2392+
tests_root="tests",
2393+
test_framework="pytest",
2394+
pytest_cmd="pytest",
2395+
experiment_id=None,
2396+
test_project_root=Path().resolve(),
2397+
)
2398+
)
2399+
2400+
function_to_optimize1 = FunctionToOptimize(
2401+
function_name="target_method",
2402+
file_path=file_path1,
2403+
parents=[FunctionParent(name="TestClass", type="ClassDef")],
2404+
starting_line=None,
2405+
ending_line=None,
2406+
)
2407+
function_to_optimize2 = FunctionToOptimize(
2408+
function_name="target_method",
2409+
file_path=file_path2,
2410+
parents=[FunctionParent(name="TestClass", type="ClassDef")],
2411+
starting_line=None,
2412+
ending_line=None,
2413+
)
2414+
2415+
code_ctx1 = get_code_optimization_context(function_to_optimize1, opt1.args.project_root)
2416+
code_ctx2 = get_code_optimization_context(function_to_optimize2, opt2.args.project_root)
2417+
2418+
# Different code should produce different hashes
2419+
assert code_ctx1.hashing_code_context_hash != code_ctx2.hashing_code_context_hash
2420+
assert code_ctx1.hashing_code_context != code_ctx2.hashing_code_context
2421+
2422+
2423+
def test_hashing_code_context_format_is_markdown() -> None:
2424+
"""Test that hashing context is formatted as markdown."""
2425+
code = """
2426+
class SimpleClass:
2427+
def simple_method(self):
2428+
return 42
2429+
"""
2430+
with tempfile.NamedTemporaryFile(mode="w") as f:
2431+
f.write(code)
2432+
f.flush()
2433+
file_path = Path(f.name).resolve()
2434+
opt = Optimizer(
2435+
Namespace(
2436+
project_root=file_path.parent.resolve(),
2437+
disable_telemetry=True,
2438+
tests_root="tests",
2439+
test_framework="pytest",
2440+
pytest_cmd="pytest",
2441+
experiment_id=None,
2442+
test_project_root=Path().resolve(),
2443+
)
2444+
)
2445+
function_to_optimize = FunctionToOptimize(
2446+
function_name="simple_method",
2447+
file_path=file_path,
2448+
parents=[FunctionParent(name="SimpleClass", type="ClassDef")],
2449+
starting_line=None,
2450+
ending_line=None,
2451+
)
2452+
2453+
code_ctx = get_code_optimization_context(function_to_optimize, opt.args.project_root)
2454+
hashing_context = code_ctx.hashing_code_context
2455+
2456+
# Should be formatted as markdown code block
2457+
assert hashing_context.startswith("```python:")
2458+
assert hashing_context.endswith("```")
2459+
2460+
# Should contain the relative file path in the markdown header
2461+
relative_path = file_path.relative_to(opt.args.project_root)
2462+
assert str(relative_path) in hashing_context
2463+
2464+
# Should contain the actual code between the markdown markers
2465+
lines = hashing_context.strip().split("\n")
2466+
assert lines[0].startswith("```python:")
2467+
assert lines[-1] == "```"
2468+
2469+
# Code should be between the markers
2470+
code_lines = lines[1:-1]
2471+
code_content = "\n".join(code_lines)
2472+
assert "class SimpleClass:" in code_content
2473+
assert "def simple_method(self):" in code_content
2474+
assert "return 42" in code_content

0 commit comments

Comments
 (0)