Skip to content

Commit bf215c4

Browse files
committed
chore: bump version to 0.4.2 for enhanced tool descriptions
1 parent c1d64e5 commit bf215c4

File tree

3 files changed

+379
-2
lines changed

3 files changed

+379
-2
lines changed

code_extractor/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,7 @@ def main():
449449
parser.add_argument(
450450
"--version",
451451
action="version",
452-
version="mcp-server-code-extractor 0.3.1"
452+
version="mcp-server-code-extractor 0.4.2"
453453
)
454454

455455
# Parse args but ignore them for MCP server mode

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "mcp-server-code-extractor"
3-
version = "0.4.0"
3+
version = "0.4.2"
44
description = "A Model Context Protocol (MCP) server that provides precise code extraction tools using tree-sitter parsing"
55
readme = "README.md"
66
requires-python = ">=3.11"

test_symbol_definitions.py

Lines changed: 377 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,377 @@
1+
#!/usr/bin/env python3
2+
"""
3+
Test script for the new symbol-definitions search functionality.
4+
Run with: python test_symbol_definitions.py
5+
"""
6+
7+
import sys
8+
import os
9+
import tempfile
10+
from pathlib import Path
11+
12+
# Add the project root to the path
13+
sys.path.insert(0, os.path.dirname(__file__))
14+
15+
from code_extractor.search_engine import SearchEngine
16+
from code_extractor.models import SearchParameters
17+
18+
def test_python_symbol_definitions():
19+
"""Test symbol-definitions search on Python code."""
20+
21+
print("=" * 60)
22+
print("Testing SYMBOL-DEFINITIONS search on Python code")
23+
print("=" * 60)
24+
25+
# Test with our actual server.py file
26+
print("\n1. Testing function definitions in server.py:")
27+
params = SearchParameters(
28+
search_type="symbol-definitions",
29+
target="get_symbols",
30+
scope="code_extractor/server.py"
31+
)
32+
33+
engine = SearchEngine()
34+
results = engine.search_file("code_extractor/server.py", params)
35+
36+
print(f"Found {len(results)} results for 'get_symbols' function definitions:")
37+
for i, result in enumerate(results, 1):
38+
print(f" {i}. Line {result.start_line}: {result.match_text.strip()}")
39+
print(f" Symbol type: {result.metadata.get('symbol_type', 'unknown')}")
40+
if result.context_before:
41+
print(f" Context: {result.context_before[-1].strip()}")
42+
43+
# Test class definitions
44+
print("\n2. Testing class definitions:")
45+
params.target = "SearchEngine"
46+
results = engine.search_file("code_extractor/search_engine.py", params)
47+
48+
print(f"Found {len(results)} results for 'SearchEngine' class definitions:")
49+
for i, result in enumerate(results, 1):
50+
print(f" {i}. Line {result.start_line}: {result.match_text.strip()}")
51+
print(f" Symbol type: {result.metadata.get('symbol_type', 'unknown')}")
52+
53+
# Test variable definitions
54+
print("\n3. Testing variable definitions:")
55+
params.target = "supported_types"
56+
results = engine.search_file("code_extractor/server.py", params)
57+
58+
print(f"Found {len(results)} results for 'supported_types' variable definitions:")
59+
for i, result in enumerate(results, 1):
60+
print(f" {i}. Line {result.start_line}: {result.match_text.strip()}")
61+
print(f" Symbol type: {result.metadata.get('symbol_type', 'unknown')}")
62+
63+
def test_javascript_symbol_definitions():
64+
"""Test symbol-definitions search on JavaScript code."""
65+
66+
print("\n" + "=" * 60)
67+
print("Testing SYMBOL-DEFINITIONS search on JavaScript code")
68+
print("=" * 60)
69+
70+
# Create temporary JavaScript file for testing
71+
js_code = '''
72+
function fetchData(url) {
73+
return fetch(url);
74+
}
75+
76+
class DataProcessor {
77+
constructor(options) {
78+
this.options = options;
79+
}
80+
81+
process(data) {
82+
return data.map(item => item.value);
83+
}
84+
}
85+
86+
const API_URL = 'https://api.example.com';
87+
let cache = new Map();
88+
var settings = { debug: true };
89+
'''
90+
91+
with tempfile.NamedTemporaryFile(mode='w', suffix='.js', delete=False) as f:
92+
f.write(js_code)
93+
js_file = f.name
94+
95+
try:
96+
engine = SearchEngine()
97+
98+
# Test function definitions
99+
print("\n1. Testing JavaScript function definitions:")
100+
params = SearchParameters(
101+
search_type="symbol-definitions",
102+
target="fetchData",
103+
scope=js_file
104+
)
105+
106+
results = engine.search_file(js_file, params)
107+
print(f"Found {len(results)} results for 'fetchData' function definitions:")
108+
for i, result in enumerate(results, 1):
109+
print(f" {i}. Line {result.start_line}: {result.match_text.strip()}")
110+
print(f" Symbol type: {result.metadata.get('symbol_type', 'unknown')}")
111+
112+
# Test class definitions
113+
print("\n2. Testing JavaScript class definitions:")
114+
params.target = "DataProcessor"
115+
results = engine.search_file(js_file, params)
116+
117+
print(f"Found {len(results)} results for 'DataProcessor' class definitions:")
118+
for i, result in enumerate(results, 1):
119+
print(f" {i}. Line {result.start_line}: {result.match_text.strip()}")
120+
print(f" Symbol type: {result.metadata.get('symbol_type', 'unknown')}")
121+
122+
# Test variable definitions
123+
print("\n3. Testing JavaScript variable definitions:")
124+
params.target = "API_URL"
125+
results = engine.search_file(js_file, params)
126+
127+
print(f"Found {len(results)} results for 'API_URL' variable definitions:")
128+
for i, result in enumerate(results, 1):
129+
print(f" {i}. Line {result.start_line}: {result.match_text.strip()}")
130+
print(f" Symbol type: {result.metadata.get('symbol_type', 'unknown')}")
131+
132+
finally:
133+
os.unlink(js_file)
134+
135+
def test_typescript_symbol_definitions():
136+
"""Test symbol-definitions search on TypeScript code."""
137+
138+
print("\n" + "=" * 60)
139+
print("Testing SYMBOL-DEFINITIONS search on TypeScript code")
140+
print("=" * 60)
141+
142+
# Create temporary TypeScript file for testing
143+
ts_code = '''
144+
interface User {
145+
id: number;
146+
name: string;
147+
}
148+
149+
type UserResponse = {
150+
user: User;
151+
status: string;
152+
};
153+
154+
class UserService {
155+
private apiUrl: string;
156+
157+
constructor(apiUrl: string) {
158+
this.apiUrl = apiUrl;
159+
}
160+
161+
async getUser(id: number): Promise<User> {
162+
const response = await fetch(`${this.apiUrl}/users/${id}`);
163+
return response.json();
164+
}
165+
}
166+
167+
const defaultTimeout = 5000;
168+
let userCache: Map<number, User> = new Map();
169+
'''
170+
171+
with tempfile.NamedTemporaryFile(mode='w', suffix='.ts', delete=False) as f:
172+
f.write(ts_code)
173+
ts_file = f.name
174+
175+
try:
176+
engine = SearchEngine()
177+
178+
# Test interface definitions
179+
print("\n1. Testing TypeScript interface definitions:")
180+
params = SearchParameters(
181+
search_type="symbol-definitions",
182+
target="User",
183+
scope=ts_file
184+
)
185+
186+
results = engine.search_file(ts_file, params)
187+
print(f"Found {len(results)} results for 'User' interface definitions:")
188+
for i, result in enumerate(results, 1):
189+
print(f" {i}. Line {result.start_line}: {result.match_text.strip()}")
190+
print(f" Symbol type: {result.metadata.get('symbol_type', 'unknown')}")
191+
192+
# Test type definitions
193+
print("\n2. Testing TypeScript type definitions:")
194+
params.target = "UserResponse"
195+
results = engine.search_file(ts_file, params)
196+
197+
print(f"Found {len(results)} results for 'UserResponse' type definitions:")
198+
for i, result in enumerate(results, 1):
199+
print(f" {i}. Line {result.start_line}: {result.match_text.strip()}")
200+
print(f" Symbol type: {result.metadata.get('symbol_type', 'unknown')}")
201+
202+
# Test class definitions
203+
print("\n3. Testing TypeScript class definitions:")
204+
params.target = "UserService"
205+
results = engine.search_file(ts_file, params)
206+
207+
print(f"Found {len(results)} results for 'UserService' class definitions:")
208+
for i, result in enumerate(results, 1):
209+
print(f" {i}. Line {result.start_line}: {result.match_text.strip()}")
210+
print(f" Symbol type: {result.metadata.get('symbol_type', 'unknown')}")
211+
212+
finally:
213+
os.unlink(ts_file)
214+
215+
def test_directory_search():
216+
"""Test symbol-definitions search across a directory."""
217+
218+
print("\n" + "=" * 60)
219+
print("Testing SYMBOL-DEFINITIONS directory search")
220+
print("=" * 60)
221+
222+
engine = SearchEngine()
223+
224+
# Test searching for class definitions across the entire code_extractor directory
225+
print("\n1. Searching for 'SearchEngine' class definitions across directory:")
226+
params = SearchParameters(
227+
search_type="symbol-definitions",
228+
target="SearchEngine",
229+
scope="code_extractor",
230+
file_patterns=["*.py"],
231+
max_results=10
232+
)
233+
234+
results = engine.search_directory("code_extractor", params)
235+
print(f"Found {len(results)} results for 'SearchEngine' class definitions:")
236+
for i, result in enumerate(results, 1):
237+
print(f" {i}. {result.file_path}:{result.start_line} - {result.match_text.strip()}")
238+
print(f" Symbol type: {result.metadata.get('symbol_type', 'unknown')}")
239+
240+
# Test searching for function definitions
241+
print("\n2. Searching for function definitions containing 'extract':")
242+
params.target = "extract"
243+
results = engine.search_directory("code_extractor", params)
244+
245+
print(f"Found {len(results)} results for functions with 'extract' in name:")
246+
for i, result in enumerate(results, 1):
247+
print(f" {i}. {result.file_path}:{result.start_line} - {result.match_text.strip()}")
248+
print(f" Symbol type: {result.metadata.get('symbol_type', 'unknown')}")
249+
250+
def test_comparison_with_function_calls():
251+
"""Compare symbol-definitions vs function-calls search results."""
252+
253+
print("\n" + "=" * 60)
254+
print("COMPARISON: symbol-definitions vs function-calls")
255+
print("=" * 60)
256+
257+
engine = SearchEngine()
258+
259+
# Search for get_file_content definitions vs calls
260+
target = "get_file_content"
261+
scope = "code_extractor/server.py"
262+
263+
print(f"\nComparing searches for '{target}' in {scope}:")
264+
265+
# Symbol definitions
266+
params_def = SearchParameters(
267+
search_type="symbol-definitions",
268+
target=target,
269+
scope=scope
270+
)
271+
results_def = engine.search_file(scope, params_def)
272+
273+
print(f"\nSymbol definitions ({len(results_def)} results):")
274+
for i, result in enumerate(results_def, 1):
275+
print(f" {i}. Line {result.start_line}: {result.match_text.strip()}")
276+
277+
# Function calls
278+
params_calls = SearchParameters(
279+
search_type="function-calls",
280+
target=target,
281+
scope=scope
282+
)
283+
results_calls = engine.search_file(scope, params_calls)
284+
285+
print(f"\nFunction calls ({len(results_calls)} results):")
286+
for i, result in enumerate(results_calls, 1):
287+
print(f" {i}. Line {result.start_line}: {result.match_text.strip()}")
288+
289+
print(f"\nSummary:")
290+
print(f" Definitions found: {len(results_def)}")
291+
print(f" Calls found: {len(results_calls)}")
292+
print(f" This demonstrates the difference between where symbols are DEFINED vs USED")
293+
294+
def test_edge_cases():
295+
"""Test edge cases and error conditions."""
296+
297+
print("\n" + "=" * 60)
298+
print("Testing EDGE CASES and error conditions")
299+
print("=" * 60)
300+
301+
engine = SearchEngine()
302+
303+
# Test with unsupported language
304+
print("\n1. Testing with unsupported language (.txt file):")
305+
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
306+
f.write("This is just text, not code.")
307+
txt_file = f.name
308+
309+
try:
310+
params = SearchParameters(
311+
search_type="symbol-definitions",
312+
target="text",
313+
scope=txt_file
314+
)
315+
316+
results = engine.search_file(txt_file, params)
317+
print(f"Results for unsupported language: {len(results)} (expected: 0)")
318+
319+
finally:
320+
os.unlink(txt_file)
321+
322+
# Test with non-existent target
323+
print("\n2. Testing with non-existent symbol:")
324+
params = SearchParameters(
325+
search_type="symbol-definitions",
326+
target="NonExistentSymbolName12345",
327+
scope="code_extractor/server.py"
328+
)
329+
330+
results = engine.search_file("code_extractor/server.py", params)
331+
print(f"Results for non-existent symbol: {len(results)} (expected: 0)")
332+
333+
# Test with empty file
334+
print("\n3. Testing with empty file:")
335+
with tempfile.NamedTemporaryFile(mode='w', suffix='.py', delete=False) as f:
336+
f.write("") # Empty file
337+
empty_file = f.name
338+
339+
try:
340+
params = SearchParameters(
341+
search_type="symbol-definitions",
342+
target="anything",
343+
scope=empty_file
344+
)
345+
346+
results = engine.search_file(empty_file, params)
347+
print(f"Results for empty file: {len(results)} (expected: 0)")
348+
349+
finally:
350+
os.unlink(empty_file)
351+
352+
def run_all_tests():
353+
"""Run all symbol-definitions tests."""
354+
355+
print("🔍 SYMBOL-DEFINITIONS SEARCH TESTING SUITE")
356+
print("=" * 60)
357+
358+
try:
359+
test_python_symbol_definitions()
360+
test_javascript_symbol_definitions()
361+
test_typescript_symbol_definitions()
362+
test_directory_search()
363+
test_comparison_with_function_calls()
364+
test_edge_cases()
365+
366+
print("\n" + "=" * 60)
367+
print("✅ ALL SYMBOL-DEFINITIONS TESTS COMPLETED SUCCESSFULLY!")
368+
print("Ready for deployment! 🚀")
369+
print("=" * 60)
370+
371+
except Exception as e:
372+
print(f"\n❌ TEST FAILED: {e}")
373+
print("Fix the issue before deployment.")
374+
raise
375+
376+
if __name__ == "__main__":
377+
run_all_tests()

0 commit comments

Comments
 (0)