66from unittest .mock import AsyncMock , MagicMock , patch
77
88import pytest
9- from mcp .types import TextContent , Tool
9+ from mcp .types import TextContent , Tool # pylint: disable=import-error
1010
1111# Import the module functions and server instance
1212from gitingest .mcp_server import (
@@ -23,7 +23,7 @@ class TestMCPListTools:
2323 """Test cases for the list_tools handler."""
2424
2525 @pytest .mark .asyncio
26- async def test_list_tools_returns_correct_tools (self ):
26+ async def test_list_tools_returns_correct_tools (self ) -> None :
2727 """Test that list_tools returns the expected tools."""
2828 tools = await list_tools ()
2929
@@ -36,7 +36,7 @@ async def test_list_tools_returns_correct_tools(self):
3636 assert "ingest a git repository" in tool .description .lower ()
3737
3838 @pytest .mark .asyncio
39- async def test_list_tools_schema_validation (self ):
39+ async def test_list_tools_schema_validation (self ) -> None :
4040 """Test that the ingest_repository tool has correct schema."""
4141 tools = await list_tools ()
4242 ingest_tool = tools [0 ]
@@ -69,14 +69,15 @@ async def test_list_tools_schema_validation(self):
6969 assert param in properties
7070
7171 @pytest .mark .asyncio
72- async def test_list_tools_source_examples (self ):
72+ async def test_list_tools_source_examples (self ) -> None :
7373 """Test that the source parameter has proper examples."""
7474 tools = await list_tools ()
7575 source_prop = tools [0 ].inputSchema ["properties" ]["source" ]
7676
7777 assert "examples" in source_prop
7878 examples = source_prop ["examples" ]
79- assert len (examples ) >= 3
79+ min_examples = 3
80+ assert len (examples ) >= min_examples
8081 assert any ("github.com" in ex for ex in examples )
8182 assert any ("/path/to/" in ex for ex in examples )
8283 assert "." in examples
@@ -86,7 +87,7 @@ class TestMCPCallTool:
8687 """Test cases for the call_tool handler."""
8788
8889 @pytest .mark .asyncio
89- async def test_call_tool_ingest_repository_success (self ):
90+ async def test_call_tool_ingest_repository_success (self ) -> None :
9091 """Test successful repository ingestion through call_tool."""
9192 with patch ("gitingest.mcp_server.ingest_async" ) as mock_ingest :
9293 mock_ingest .return_value = (
@@ -110,7 +111,7 @@ async def test_call_tool_ingest_repository_success(self):
110111 assert "Generated by Gitingest MCP Server" in content
111112
112113 @pytest .mark .asyncio
113- async def test_call_tool_unknown_tool (self ):
114+ async def test_call_tool_unknown_tool (self ) -> None :
114115 """Test handling of unknown tool calls."""
115116 result = await call_tool ("unknown_tool" , {})
116117
@@ -120,7 +121,7 @@ async def test_call_tool_unknown_tool(self):
120121 assert "Unknown tool: unknown_tool" in result [0 ].text
121122
122123 @pytest .mark .asyncio
123- async def test_call_tool_exception_handling (self ):
124+ async def test_call_tool_exception_handling (self ) -> None :
124125 """Test exception handling in call_tool."""
125126 with patch ("gitingest.mcp_server._handle_ingest_repository" ) as mock_handle :
126127 mock_handle .side_effect = Exception ("Test exception" )
@@ -132,7 +133,7 @@ async def test_call_tool_exception_handling(self):
132133 assert "Error executing ingest_repository: Test exception" in result [0 ].text
133134
134135 @pytest .mark .asyncio
135- async def test_call_tool_logs_errors (self ):
136+ async def test_call_tool_logs_errors (self ) -> None :
136137 """Test that call_tool logs errors properly."""
137138 with (
138139 patch ("gitingest.mcp_server._handle_ingest_repository" ) as mock_handle ,
@@ -144,15 +145,15 @@ async def test_call_tool_logs_errors(self):
144145 await call_tool ("ingest_repository" , {"source" : "test" })
145146
146147 mock_logger .exception .assert_called_once ()
147- args , kwargs = mock_logger .exception .call_args
148- assert "Error in tool call ingest_repository" in args [ 0 ]
148+ args , _kwargs = mock_logger .exception .call_args
149+ assert args == ( "Error in tool call %s" , "ingest_repository" )
149150
150151
151152class TestHandleIngestRepository :
152153 """Test cases for the _handle_ingest_repository helper function."""
153154
154155 @pytest .mark .asyncio
155- async def test_handle_ingest_repository_minimal_args (self ):
156+ async def test_handle_ingest_repository_minimal_args (self ) -> None :
156157 """Test repository ingestion with minimal arguments."""
157158 with patch ("gitingest.mcp_server.ingest_async" ) as mock_ingest :
158159 mock_ingest .return_value = ("summary" , "tree" , "content" )
@@ -177,7 +178,7 @@ async def test_handle_ingest_repository_minimal_args(self):
177178 )
178179
179180 @pytest .mark .asyncio
180- async def test_handle_ingest_repository_all_args (self ):
181+ async def test_handle_ingest_repository_all_args (self ) -> None :
181182 """Test repository ingestion with all arguments."""
182183 with patch ("gitingest.mcp_server.ingest_async" ) as mock_ingest :
183184 mock_ingest .return_value = ("summary" , "tree" , "content" )
@@ -207,12 +208,12 @@ async def test_handle_ingest_repository_all_args(self):
207208 branch = "develop" ,
208209 include_gitignored = True ,
209210 include_submodules = True ,
210- token = "ghp_test_token" ,
211+ token = "test_token_123" , # noqa: S106
211212 output = None ,
212213 )
213214
214215 @pytest .mark .asyncio
215- async def test_handle_ingest_repository_pattern_conversion (self ):
216+ async def test_handle_ingest_repository_pattern_conversion (self ) -> None :
216217 """Test that patterns are correctly converted to sets."""
217218 with patch ("gitingest.mcp_server.ingest_async" ) as mock_ingest :
218219 mock_ingest .return_value = ("summary" , "tree" , "content" )
@@ -232,7 +233,7 @@ async def test_handle_ingest_repository_pattern_conversion(self):
232233 assert call_args ["exclude_patterns" ] == {"*.txt" }
233234
234235 @pytest .mark .asyncio
235- async def test_handle_ingest_repository_none_patterns (self ):
236+ async def test_handle_ingest_repository_none_patterns (self ) -> None :
236237 """Test handling of None patterns."""
237238 with patch ("gitingest.mcp_server.ingest_async" ) as mock_ingest :
238239 mock_ingest .return_value = ("summary" , "tree" , "content" )
@@ -250,7 +251,7 @@ async def test_handle_ingest_repository_none_patterns(self):
250251 assert call_args ["exclude_patterns" ] is None
251252
252253 @pytest .mark .asyncio
253- async def test_handle_ingest_repository_exception (self ):
254+ async def test_handle_ingest_repository_exception (self ) -> None :
254255 """Test exception handling in _handle_ingest_repository."""
255256 with (
256257 patch ("gitingest.mcp_server.ingest_async" ) as mock_ingest ,
@@ -267,11 +268,11 @@ async def test_handle_ingest_repository_exception(self):
267268
268269 # Verify error was logged
269270 mock_logger .exception .assert_called_once ()
270- args , kwargs = mock_logger .exception .call_args
271- assert "Error during ingestion" in args [ 0 ]
271+ args , _kwargs = mock_logger .exception .call_args
272+ assert args == ( "Error during ingestion" ,)
272273
273274 @pytest .mark .asyncio
274- async def test_handle_ingest_repository_logs_info (self ):
275+ async def test_handle_ingest_repository_logs_info (self ) -> None :
275276 """Test that _handle_ingest_repository logs info messages."""
276277 with (
277278 patch ("gitingest.mcp_server.ingest_async" ) as mock_ingest ,
@@ -289,7 +290,7 @@ async def test_handle_ingest_repository_logs_info(self):
289290 )
290291
291292 @pytest .mark .asyncio
292- async def test_handle_ingest_repository_response_format (self ):
293+ async def test_handle_ingest_repository_response_format (self ) -> None :
293294 """Test the format of the response content."""
294295 with patch ("gitingest.mcp_server.ingest_async" ) as mock_ingest :
295296 mock_ingest .return_value = (
@@ -317,13 +318,13 @@ class TestMCPServerIntegration:
317318 """Integration tests for the MCP server."""
318319
319320 @pytest .mark .asyncio
320- async def test_server_instance_created (self ):
321+ async def test_server_instance_created (self ) -> None :
321322 """Test that the MCP server instance is properly created."""
322323 assert app is not None
323324 assert app .name == "gitingest"
324325
325326 @pytest .mark .asyncio
326- async def test_start_mcp_server_calls_stdio (self ):
327+ async def test_start_mcp_server_calls_stdio (self ) -> None :
327328 """Test that start_mcp_server calls the stdio runner."""
328329 with patch ("gitingest.mcp_server._run_stdio" ) as mock_run_stdio :
329330 mock_run_stdio .return_value = AsyncMock ()
@@ -333,7 +334,7 @@ async def test_start_mcp_server_calls_stdio(self):
333334 mock_run_stdio .assert_called_once ()
334335
335336 @pytest .mark .asyncio
336- async def test_start_mcp_server_logs_startup (self ):
337+ async def test_start_mcp_server_logs_startup (self ) -> None :
337338 """Test that start_mcp_server logs startup message."""
338339 with (
339340 patch ("gitingest.mcp_server._run_stdio" ) as mock_run_stdio ,
@@ -348,7 +349,7 @@ async def test_start_mcp_server_logs_startup(self):
348349 )
349350
350351 @pytest .mark .asyncio
351- async def test_run_stdio_integration (self ):
352+ async def test_run_stdio_integration (self ) -> None :
352353 """Test _run_stdio function integration."""
353354 with patch ("gitingest.mcp_server.stdio_server" ) as mock_stdio_server :
354355 # Mock the async context manager
@@ -374,14 +375,15 @@ async def test_run_stdio_integration(self):
374375 # Verify app.run was called with streams and init options
375376 mock_run .assert_called_once ()
376377 call_args = mock_run .call_args [0 ]
377- assert len (call_args ) == 3 # read_stream, write_stream, init_options
378+ expected_args = 3 # read_stream, write_stream, init_options
379+ assert len (call_args ) == expected_args
378380
379381
380382class TestMCPServerParameterValidation :
381383 """Test parameter validation for MCP server tools."""
382384
383385 @pytest .mark .asyncio
384- async def test_ingest_repository_missing_source (self ):
386+ async def test_ingest_repository_missing_source (self ) -> None :
385387 """Test that missing source parameter is handled."""
386388 # This should raise a KeyError which gets caught by call_tool
387389 result = await call_tool ("ingest_repository" , {})
@@ -391,7 +393,7 @@ async def test_ingest_repository_missing_source(self):
391393 assert "Error ingesting repository" in result [0 ].text
392394
393395 @pytest .mark .asyncio
394- async def test_ingest_repository_invalid_parameters (self ):
396+ async def test_ingest_repository_invalid_parameters (self ) -> None :
395397 """Test handling of invalid parameter types."""
396398 with patch ("gitingest.mcp_server.ingest_async" ) as mock_ingest :
397399 # ingest_async should handle type validation, but let's test edge cases
@@ -410,7 +412,7 @@ async def test_ingest_repository_invalid_parameters(self):
410412 assert "Error ingesting repository: Invalid parameter type" in result [0 ].text
411413
412414 @pytest .mark .asyncio
413- async def test_ingest_repository_empty_patterns (self ):
415+ async def test_ingest_repository_empty_patterns (self ) -> None :
414416 """Test handling of empty pattern lists."""
415417 with patch ("gitingest.mcp_server.ingest_async" ) as mock_ingest :
416418 mock_ingest .return_value = ("summary" , "tree" , "content" )
@@ -433,7 +435,7 @@ class TestMCPServerEdgeCases:
433435 """Test edge cases and error scenarios."""
434436
435437 @pytest .mark .asyncio
436- async def test_call_tool_empty_arguments (self ):
438+ async def test_call_tool_empty_arguments (self ) -> None :
437439 """Test call_tool with empty arguments dict."""
438440 result = await call_tool ("ingest_repository" , {})
439441
@@ -442,7 +444,7 @@ async def test_call_tool_empty_arguments(self):
442444 assert "Error ingesting repository" in result [0 ].text
443445
444446 @pytest .mark .asyncio
445- async def test_handle_ingest_repository_partial_results (self ):
447+ async def test_handle_ingest_repository_partial_results (self ) -> None :
446448 """Test handling when ingest_async returns partial results."""
447449 with patch ("gitingest.mcp_server.ingest_async" ) as mock_ingest :
448450 # Test with empty strings
@@ -459,17 +461,18 @@ async def test_handle_ingest_repository_partial_results(self):
459461 assert "## Content" in content
460462
461463 @pytest .mark .asyncio
462- async def test_concurrent_tool_calls (self ):
464+ async def test_concurrent_tool_calls (self ) -> None :
463465 """Test that concurrent tool calls work correctly."""
464466 with patch ("gitingest.mcp_server.ingest_async" ) as mock_ingest :
465467 mock_ingest .return_value = ("summary" , "tree" , "content" )
466468
467469 # Create multiple concurrent calls
468- tasks = [call_tool ("ingest_repository" , {"source" : f"test-{ i } " }) for i in range (3 )]
470+ num_tasks = 3
471+ tasks = [call_tool ("ingest_repository" , {"source" : f"test-{ i } " }) for i in range (num_tasks )]
469472
470473 results = await asyncio .gather (* tasks )
471474
472- assert len (results ) == 3
475+ assert len (results ) == num_tasks
473476 for result in results :
474477 assert isinstance (result , list )
475478 assert len (result ) == 1
0 commit comments