@@ -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