@@ -305,6 +305,94 @@ def test_preserves_server_order(self):
305305 assert important_line < less_important_line
306306 assert less_important_line < another_line
307307
308+ def test_snippet_fallback_when_no_description (self ):
309+ """Test that snippet is rendered as truncated content when description is absent."""
310+ response = {
311+ "results" : [
312+ {
313+ "kind" : "Symbol" ,
314+ "identifier" : "owner/repo::file.py::func" ,
315+ "location" : {
316+ "path" : "file.py" ,
317+ "range" : {"start" : {"line" : 1 }, "end" : {"line" : 5 }}
318+ },
319+ "snippet" : "def func(): return 42"
320+ }
321+ ]
322+ }
323+
324+ result = transform_search_response_to_xml (response )
325+
326+ assert '<content truncated="true">' in result
327+ assert "def func(): return 42" in result
328+ assert "</content>" in result
329+ assert "<description>" not in result
330+
331+ def test_snippet_html_escaped (self ):
332+ """Test that snippet content is HTML-escaped."""
333+ response = {
334+ "results" : [
335+ {
336+ "kind" : "Symbol" ,
337+ "identifier" : "owner/repo::file.py::func" ,
338+ "location" : {
339+ "path" : "file.py" ,
340+ "range" : {"start" : {"line" : 1 }, "end" : {"line" : 5 }}
341+ },
342+ "snippet" : 'if x < 10 && y > 5: return "<ok>"'
343+ }
344+ ]
345+ }
346+
347+ result = transform_search_response_to_xml (response )
348+
349+ assert "<" in result
350+ assert "&" in result
351+ assert '<content truncated="true">' in result
352+
353+ def test_description_takes_precedence_over_snippet (self ):
354+ """Test that description wins when both description and snippet are present."""
355+ response = {
356+ "results" : [
357+ {
358+ "kind" : "Symbol" ,
359+ "identifier" : "owner/repo::file.py::func" ,
360+ "location" : {
361+ "path" : "file.py" ,
362+ "range" : {"start" : {"line" : 1 }, "end" : {"line" : 5 }}
363+ },
364+ "description" : "A helper function" ,
365+ "snippet" : "def func(): return 42"
366+ }
367+ ]
368+ }
369+
370+ result = transform_search_response_to_xml (response )
371+
372+ assert "<description>A helper function</description>" in result
373+ assert '<content truncated="true">' not in result
374+
375+ def test_no_description_no_snippet_self_closing (self ):
376+ """Test that results without description and without snippet use self-closing tags."""
377+ response = {
378+ "results" : [
379+ {
380+ "kind" : "Symbol" ,
381+ "identifier" : "owner/repo::file.py::func" ,
382+ "location" : {
383+ "path" : "file.py" ,
384+ "range" : {"start" : {"line" : 1 }, "end" : {"line" : 5 }}
385+ }
386+ }
387+ ]
388+ }
389+
390+ result = transform_search_response_to_xml (response )
391+
392+ assert "/>" in result
393+ assert "<description>" not in result
394+ assert "<content" not in result
395+
308396 def test_data_preservation_without_content (self ):
309397 """Test that all essential data is preserved."""
310398 response = {
0 commit comments