-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcode-analyzer.py
More file actions
108 lines (84 loc) · 4.45 KB
/
code-analyzer.py
File metadata and controls
108 lines (84 loc) · 4.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
"""
CodeAnalyzer module for analyzing code structure and relationships.
"""
import os
import ast
import re
from typing import List, Dict, Any
class CodeAnalyzer:
"""Analyzes code structure and relationships."""
@staticmethod
def map_test_to_source_files(source_files: List[str], test_files: List[str]) -> Dict[str, str]:
"""Map test files to their corresponding source files."""
mapping = {}
source_base_names = {os.path.splitext(os.path.basename(f))[0]: f for f in source_files}
for test_file in test_files:
test_name = os.path.splitext(os.path.basename(test_file))[0]
# Handle common naming patterns
if test_name.startswith('test_'):
source_name = test_name[5:] # Remove 'test_'
if source_name in source_base_names:
mapping[source_base_names[source_name]] = test_file
elif test_name.endswith('_test'):
source_name = test_name[:-5] # Remove '_test'
if source_name in source_base_names:
mapping[source_base_names[source_name]] = test_file
# If no match found by naming convention, try to infer from content
if test_file not in mapping.values():
# This would require more sophisticated analysis in a production tool
pass
return mapping
@staticmethod
def create_prompt_for_mutant(source_file: str, test_file: str, mutant: Dict[str, Any]) -> str:
"""Create a prompt for the LLM to generate a test for the given mutant."""
# Read the source file to extract the relevant function
with open(source_file, 'r', encoding='utf-8') as f:
source_content = f.read()
# Read the test file to extract existing tests
with open(test_file, 'r', encoding='utf-8') as f:
test_content = f.read()
# Parse the source file to find the function containing the mutation
tree = ast.parse(source_content)
function_name = None
function_code = None
for node in ast.walk(tree):
if isinstance(node, ast.FunctionDef):
if hasattr(node, 'lineno') and hasattr(node, 'end_lineno'):
if node.lineno <= mutant['line_number'] <= node.end_lineno:
function_name = node.name
function_code = source_content.splitlines()[node.lineno-1:node.end_lineno]
function_code = '\n'.join(function_code)
break
if not function_name or not function_code:
# If we couldn't find the function, use a more generic approach
# Extract a few lines around the mutation
lines = source_content.splitlines()
start_line = max(0, mutant['line_number'] - 5)
end_line = min(len(lines), mutant['line_number'] + 5)
context_code = '\n'.join(lines[start_line:end_line])
# Try to extract the function name from the context
match = re.search(r'def\s+(\w+)\s*\(', context_code)
if match:
function_name = match.group(1)
else:
function_name = "unknown_function"
# Extract existing tests for this function
existing_tests = ""
test_tree = ast.parse(test_content)
for node in ast.walk(test_tree):
if isinstance(node, ast.FunctionDef):
if node.name.startswith('test_') and function_name.lower() in node.name.lower():
test_code = test_content.splitlines()[node.lineno-1:node.end_lineno]
existing_tests += '\n'.join(test_code) + '\n\n'
# Create the prompt
module_name = os.path.splitext(os.path.basename(source_file))[0]
prompt = f"""
I have a function in module '{module_name}':
{function_code}
My current test(s) for this function:
{existing_tests}
I found a bug where changing '{mutant['original_line']}' to '{mutant['mutated_line']}' at line {mutant['line_number']} isn't caught by my test suite.
Please generate a new test method that would detect this change. The test should pass on the original code but fail if the mutation is applied.
Return only the Python code for the test method, properly indented and with docstrings explaining what it tests.
"""
return prompt