forked from djaboxx/gemini-update
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtest_tool_fix.py
More file actions
264 lines (226 loc) · 9.41 KB
/
Copy pathtest_tool_fix.py
File metadata and controls
264 lines (226 loc) · 9.41 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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
#!/usr/bin/env python3
"""
Test script to verify that the model objects are handled correctly and string parsing is disabled.
"""
import asyncio
import os
import json
import pytest
from pathlib import Path
import tempfile
import logging
from unittest.mock import patch, MagicMock
try:
from dotenv import load_dotenv
except ImportError:
print("WARNING: python-dotenv not installed. Install with: pip install python-dotenv")
from src.models.feature import FeatureSpec, Requirement, RequirementType, FeatureType, Priority
from src.models.analysis import ImplementationPlan, CodeChange, ChangeType, FeatureScope, Settings
from src.agent.agent import GeminiUpdateAgent
# Configure logging
logging.basicConfig(level=logging.INFO)
def test_feature_spec_handling():
"""
Test that FeatureSpec correctly handles serialization and deserialization.
"""
print("Testing FeatureSpec handling...")
# Create a test feature spec
feature_spec = FeatureSpec(
name="Test Feature",
description="A test feature to verify function signature changes",
feature_type=FeatureType.UI,
priority=Priority.MEDIUM,
requirements=[
Requirement(
id="REQ-001",
description="A test requirement",
type=RequirementType.FUNCTIONAL,
acceptance_criteria=["Test passes"]
)
],
user_personas=["Tester"],
success_metrics=["Test completes successfully"],
technical_notes="Testing the fix for passing Pydantic models to tools"
)
# Serialize to JSON string
json_str = feature_spec.model_dump_json()
print(f"Serialized FeatureSpec: {json_str[:100]}...")
# Deserialize back to object
deserialized_spec = FeatureSpec.model_validate_json(json_str)
# Verify fields match
assert deserialized_spec.name == feature_spec.name, "Name field doesn't match after serialization"
assert deserialized_spec.description == feature_spec.description, "Description field doesn't match"
assert len(deserialized_spec.requirements) == len(feature_spec.requirements), "Requirements count doesn't match"
print("Feature spec test passed!")
def test_implementation_plan_handling():
"""
Test that ImplementationPlan correctly handles serialization and deserialization.
"""
print("Testing ImplementationPlan handling...")
# Create a test implementation plan
impl_plan = ImplementationPlan(
feature_name="Test Feature",
description="Implementation plan for test feature",
scope=FeatureScope(
affected_files=["test_file.py"],
new_files=[],
dependencies_needed=[],
config_changes=[]
),
changes=[
CodeChange(
file_path="test_file.py",
change_type=ChangeType.MODIFY,
description="Test change",
code_snippet="print('Hello world')"
)
],
estimated_complexity="Low",
dependencies=[]
)
# Serialize to JSON string
json_str = impl_plan.model_dump_json()
print(f"Serialized ImplementationPlan: {json_str[:100]}...")
# Deserialize back to object
deserialized_plan = ImplementationPlan.model_validate_json(json_str)
# Verify fields match
assert deserialized_plan.feature_name == impl_plan.feature_name, "Feature name field doesn't match after serialization"
assert deserialized_plan.description == impl_plan.description, "Description field doesn't match"
assert len(deserialized_plan.changes) == len(impl_plan.changes), "Changes count doesn't match"
print("Implementation plan test passed!")
async def test_real_agent_with_string_injection():
"""Test that the real agent properly rejects string responses for FeatureSpec and ImplementationPlan."""
print("Testing real agent with string injection...")
try:
# Load environment variables - API key should be in the environment
from dotenv import load_dotenv
load_dotenv()
# Create settings for the real agent
settings = Settings.from_env()
settings.output_dir = Path(tempfile.mkdtemp())
# Let the agent select the best model instead of using the one from settings
# The _select_best_model method will choose an appropriate model
settings.gemini_model = None
print("Note: Using agent's model selection instead of environment setting")
print(f"Using output directory: {settings.output_dir}")
print(f"Using model: {settings.gemini_model}")
# Create the real GeminiUpdateAgent with actual settings
agent = GeminiUpdateAgent(settings=settings)
# Create a context for testing
context = MagicMock()
context.language = "Python"
context.files = []
context.project_path = str(Path.cwd())
# Override the agent's run method to return strings instead of objects
original_run = agent.agent.run
# First, test with FeatureSpec
async def mock_feature_spec_string(*args, **kwargs):
# Return a valid JSON string instead of a FeatureSpec object
return """
{
"name": "Test Feature",
"description": "A test feature",
"feature_type": "ui",
"priority": "medium",
"requirements": [
{
"id": "REQ-001",
"type": "functional",
"description": "Test requirement",
"acceptance_criteria": ["Test passes"]
}
]
}
"""
# Replace the run method temporarily
agent.agent.run = mock_feature_spec_string
# Test that generate_feature_spec raises TypeError
print("Testing FeatureSpec with string injection...")
try:
await agent.generate_feature_spec("Test feature", context)
assert False, "Should have raised TypeError"
except TypeError as e:
print(f"Successfully rejected string for FeatureSpec: {e}")
assert "Expected FeatureSpec object" in str(e)
# Now test with ImplementationPlan
async def mock_implementation_plan_string(*args, **kwargs):
# Return a valid JSON string instead of an ImplementationPlan object
return """
{
"feature_name": "Test Feature",
"description": "Implementation plan",
"scope": {
"affected_files": ["test.py"],
"new_files": [],
"dependencies_needed": [],
"config_changes": []
},
"changes": [
{
"file_path": "test.py",
"change_type": "modify",
"description": "Test change",
"code_snippet": "print('hello')"
}
],
"estimated_complexity": "Low",
"dependencies": []
}
"""
# Replace the run method for implementation plan test
agent.agent.run = mock_implementation_plan_string
# Test that plan_implementation raises TypeError
print("Testing ImplementationPlan with string injection...")
feature_spec = FeatureSpec(
name="Test Feature",
description="A test feature",
feature_type=FeatureType.UI,
priority=Priority.MEDIUM,
requirements=[
Requirement(
id="REQ-001",
description="Test requirement",
type=RequirementType.FUNCTIONAL,
acceptance_criteria=["Test passes"]
)
],
user_personas=["Tester"],
success_metrics=["Success"]
)
try:
await agent.plan_implementation(feature_spec, context)
assert False, "Should have raised TypeError"
except TypeError as e:
print(f"Successfully rejected string for ImplementationPlan: {e}")
assert "Expected ImplementationPlan object" in str(e)
# Restore the original run method
agent.agent.run = original_run
print("Real agent test passed!")
except Exception as e:
print(f"Error during real agent test: {e}")
raise
def main():
"""Run all tests."""
# Setup environment for tests
api_key = os.environ.get("GEMINI_API_KEY")
if not api_key:
print("WARNING: GEMINI_API_KEY environment variable not set. API tests will be skipped.")
print("Set the GEMINI_API_KEY environment variable to run all tests.")
run_api_tests = False
else:
run_api_tests = True
# Run model serialization tests
test_feature_spec_handling()
print("-" * 50)
test_implementation_plan_handling()
# Run API tests if API key is available
if run_api_tests:
print("-" * 50)
print("Running API tests...")
# Run the async test using asyncio
asyncio.run(test_real_agent_with_string_injection())
else:
print("-" * 50)
print("Skipping API tests due to missing API key.")
if __name__ == "__main__":
main()