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 ("\n 1. 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 ("\n 2. 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 ("\n 3. 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 ("\n 1. 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 ("\n 2. 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 ("\n 3. 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 ("\n 1. 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 ("\n 2. 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 ("\n 3. 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 ("\n 1. 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 ("\n 2. 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"\n Comparing 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"\n Symbol 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"\n Function 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"\n Summary:" )
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 ("\n 1. 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 ("\n 2. 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 ("\n 3. 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