Skip to main content
Glama

Gemini MCP Server

test_refactor.pyโ€ข16.7 kB
""" Tests for the refactor tool functionality """ import json import pytest from tools.refactor import RefactorTool from utils.file_utils import read_file_content class TestRefactorTool: """Test suite for the refactor tool""" @pytest.fixture def refactor_tool(self): """Create a refactor tool instance for testing""" return RefactorTool() @pytest.fixture def mock_model_response(self): """Create a mock model response with valid JSON""" def _create_response(content=None): if content is None: content = json.dumps( { "refactor_opportunities": [ { "id": "refactor-001", "type": "codesmells", "severity": "high", "file": "/test/file.py", "start_line": 10, "end_line": 25, "context_start_text": "def long_method():", "context_end_text": " return result", "issue": "Method too long with multiple responsibilities", "suggestion": "Extract helper methods", "rationale": "Improves readability and maintainability", "code_to_replace": "# original code", "replacement_code_snippet": "# refactored code", "new_code_snippets": [], } ], "priority_sequence": ["refactor-001"], "next_actions": [], }, ensure_ascii=False, ) from unittest.mock import Mock return Mock( content=content, usage={"input_tokens": 100, "output_tokens": 200, "total_tokens": 300}, model_name="test-model", metadata={"finish_reason": "STOP"}, ) return _create_response def test_get_name(self, refactor_tool): """Test that the tool returns the correct name""" assert refactor_tool.get_name() == "refactor" def test_get_description(self, refactor_tool): """Test that the tool returns a comprehensive description""" description = refactor_tool.get_description() assert "refactoring" in description assert "code smell detection" in description assert "decomposition planning" in description assert "modernization" in description assert "maintainability improvements" in description def test_get_input_schema(self, refactor_tool): """Test that the input schema includes all required workflow fields""" schema = refactor_tool.get_input_schema() assert schema["type"] == "object" # Check workflow-specific fields assert "step" in schema["properties"] assert "step_number" in schema["properties"] assert "total_steps" in schema["properties"] assert "next_step_required" in schema["properties"] assert "findings" in schema["properties"] assert "files_checked" in schema["properties"] assert "relevant_files" in schema["properties"] # Check refactor-specific fields assert "refactor_type" in schema["properties"] assert "confidence" in schema["properties"] # Check refactor_type enum values refactor_enum = schema["properties"]["refactor_type"]["enum"] expected_types = ["codesmells", "decompose", "modernize", "organization"] assert all(rt in refactor_enum for rt in expected_types) # Note: Old language detection and execution tests removed - # new workflow-based refactor tool has different architecture def test_model_category(self, refactor_tool): """Test that the refactor tool uses EXTENDED_REASONING category""" from tools.models import ToolModelCategory category = refactor_tool.get_model_category() assert category == ToolModelCategory.EXTENDED_REASONING def test_default_temperature(self, refactor_tool): """Test that the refactor tool uses analytical temperature""" from config import TEMPERATURE_ANALYTICAL temp = refactor_tool.get_default_temperature() assert temp == TEMPERATURE_ANALYTICAL # Note: format_response tests removed - workflow tools use different response format class TestFileUtilsLineNumbers: """Test suite for line numbering functionality in file_utils""" def test_read_file_content_with_line_numbers(self, project_path): """Test reading file content with line numbers enabled""" # Create a test file within the workspace temp_path = project_path / "test_file.py" with open(temp_path, "w") as f: f.write("def hello():\n print('Hello')\n return True") # Read with line numbers explicitly enabled content, tokens = read_file_content(str(temp_path), include_line_numbers=True) # Check that line numbers are present assert "1โ”‚ def hello():" in content assert "2โ”‚ print('Hello')" in content assert "3โ”‚ return True" in content assert "--- BEGIN FILE:" in content assert "--- END FILE:" in content def test_read_file_content_without_line_numbers(self, project_path): """Test reading file content with line numbers disabled""" # Create a test file within the workspace temp_path = project_path / "test_file.txt" with open(temp_path, "w") as f: f.write("Line 1\nLine 2\nLine 3") # Read with line numbers explicitly disabled content, tokens = read_file_content(str(temp_path), include_line_numbers=False) # Check that line numbers are NOT present assert "1โ”‚" not in content assert "Line 1" in content assert "Line 2" in content assert "--- BEGIN FILE:" in content def test_read_file_content_auto_detect_programming(self, project_path): """Test that auto-detection is OFF by default (backwards compatibility)""" # Create a test file within the workspace temp_path = project_path / "test_auto.py" with open(temp_path, "w") as f: f.write("import os\nprint('test')") # Read without specifying line numbers (should NOT auto-detect for backwards compatibility) content, tokens = read_file_content(str(temp_path)) # Should NOT automatically add line numbers for .py files (default behavior) assert "1โ”‚" not in content assert "import os" in content assert "print('test')" in content def test_read_file_content_auto_detect_text(self, project_path): """Test auto-detection of line numbers for text files""" # Create a test file within the workspace temp_path = project_path / "test_auto.txt" with open(temp_path, "w") as f: f.write("This is a text file\nWith multiple lines") # Read without specifying line numbers (should auto-detect) content, tokens = read_file_content(str(temp_path)) # Should NOT automatically add line numbers for .txt files assert "1โ”‚" not in content assert "This is a text file" in content def test_line_ending_normalization(self): """Test that different line endings are normalized consistently""" from utils.file_utils import _add_line_numbers, _normalize_line_endings # Test different line ending formats content_crlf = "Line 1\r\nLine 2\r\nLine 3" content_cr = "Line 1\rLine 2\rLine 3" content_lf = "Line 1\nLine 2\nLine 3" # All should normalize to the same result normalized_crlf = _normalize_line_endings(content_crlf) normalized_cr = _normalize_line_endings(content_cr) normalized_lf = _normalize_line_endings(content_lf) assert normalized_crlf == normalized_cr == normalized_lf assert normalized_lf == "Line 1\nLine 2\nLine 3" # Line numbering should work consistently numbered = _add_line_numbers(content_crlf) assert " 1โ”‚ Line 1" in numbered assert " 2โ”‚ Line 2" in numbered assert " 3โ”‚ Line 3" in numbered def test_detect_file_type(self): """Test file type detection""" from utils.file_utils import detect_file_type # Test programming language files assert detect_file_type("test.py") == "text" assert detect_file_type("test.js") == "text" assert detect_file_type("test.java") == "text" # Test image files assert detect_file_type("image.png") == "image" assert detect_file_type("photo.jpg") == "image" # Test binary files assert detect_file_type("program.exe") == "binary" assert detect_file_type("library.dll") == "binary" def test_should_add_line_numbers(self): """Test line number detection logic""" from utils.file_utils import should_add_line_numbers # NO files should get line numbers by default (backwards compatibility) assert not should_add_line_numbers("test.py") assert not should_add_line_numbers("app.js") assert not should_add_line_numbers("Main.java") assert not should_add_line_numbers("readme.txt") assert not should_add_line_numbers("data.csv") # Explicit override should work assert should_add_line_numbers("readme.txt", True) assert not should_add_line_numbers("test.py", False) def test_line_numbers_double_triple_digits(self, project_path): """Test line numbering with double and triple digit line numbers""" from utils.file_utils import _add_line_numbers # Create content with many lines to test double and triple digit formatting lines = [] for i in range(1, 125): # Lines 1-124 for testing up to triple digits if i < 10: lines.append(f"# Single digit line {i}") elif i < 100: lines.append(f"# Double digit line {i}") else: lines.append(f"# Triple digit line {i}") content = "\n".join(lines) numbered_content = _add_line_numbers(content) # Test single digit formatting (should be right-aligned with spaces) assert " 1โ”‚ # Single digit line 1" in numbered_content assert " 9โ”‚ # Single digit line 9" in numbered_content # Test double digit formatting (should be right-aligned) assert " 10โ”‚ # Double digit line 10" in numbered_content # Line 10 has "double digit" content assert " 50โ”‚ # Double digit line 50" in numbered_content assert " 99โ”‚ # Double digit line 99" in numbered_content # Test triple digit formatting (should be right-aligned) assert " 100โ”‚ # Triple digit line 100" in numbered_content assert " 124โ”‚ # Triple digit line 124" in numbered_content # Verify consistent alignment - all line numbers should end with "โ”‚ " lines_with_numbers = numbered_content.split("\n") for line in lines_with_numbers: if "โ”‚" in line: # Find the pipe character position pipe_pos = line.find("โ”‚") # Ensure the character before pipe is a digit assert line[pipe_pos - 1].isdigit(), f"Line format issue: {line}" # Ensure the character after pipe is a space assert line[pipe_pos + 1] == " ", f"Line format issue: {line}" def test_line_numbers_with_file_reading(self, project_path): """Test line numbering through file reading with large file""" # Create a test file with 150 functions (600 total lines: 4 lines per function) temp_path = project_path / "large_test_file.py" with open(temp_path, "w") as f: for i in range(1, 151): # Functions 1-150 f.write(f"def function_{i}():\n") f.write(f" # This is function number {i}\n") f.write(f" return {i}\n") f.write("\n") # Read with line numbers enabled content, tokens = read_file_content(str(temp_path), include_line_numbers=True) # Calculate actual line numbers based on file structure (4 lines per function) # Function 1: lines 1-4, Function 2: lines 5-8, etc. # Line 1: def function_1(): # Line 2: # This is function number 1 # Line 3: return 1 # Line 4: (empty) # Test various line number formats in the actual file content assert " 1โ”‚ def function_1():" in content # Function 13 starts at line 49 (12*4 + 1), so line 50 is " # This is function number 13" assert " 50โ”‚ # This is function number 13" in content # Line 100 is actually an empty line after function 25 (line 99 was "return 25") assert " 100โ”‚ " in content # Empty line # Line 99 is "return 25" from function 25 assert " 99โ”‚ return 25" in content # Test more line numbers - line 147 is "return 37" from function 37 assert " 147โ”‚ return 37" in content # Test that we have the final lines (600 total lines) assert " 599โ”‚ return 150" in content assert " 600โ”‚ " in content # Final empty line # Verify the file structure is preserved assert "--- BEGIN FILE:" in content assert "--- END FILE:" in content assert str(temp_path) in content def test_line_numbers_large_files_22k_lines(self, project_path): """Test line numbering for very large files (22,500+ lines)""" from utils.file_utils import _add_line_numbers # Create content simulating a very large file with 25,000 lines lines = [] for i in range(1, 25001): # Lines 1-25000 lines.append(f"// Large file line {i}") content = "\n".join(lines) numbered_content = _add_line_numbers(content) # Test that width dynamically adjusts to 5 digits for large files # Small line numbers should now have 5-digit width assert " 1โ”‚ // Large file line 1" in numbered_content assert " 9โ”‚ // Large file line 9" in numbered_content assert " 10โ”‚ // Large file line 10" in numbered_content assert " 99โ”‚ // Large file line 99" in numbered_content assert " 100โ”‚ // Large file line 100" in numbered_content assert " 999โ”‚ // Large file line 999" in numbered_content assert " 1000โ”‚ // Large file line 1000" in numbered_content assert " 9999โ”‚ // Large file line 9999" in numbered_content assert "10000โ”‚ // Large file line 10000" in numbered_content assert "22500โ”‚ // Large file line 22500" in numbered_content assert "25000โ”‚ // Large file line 25000" in numbered_content # Verify consistent alignment - all line numbers should end with "โ”‚ " lines_with_numbers = numbered_content.split("\n") for i, line in enumerate(lines_with_numbers[:100]): # Check first 100 lines if "โ”‚" in line: pipe_pos = line.find("โ”‚") # For large files, should be 5-character width plus pipe assert line[pipe_pos - 1].isdigit(), f"Line {i+1} format issue: {line}" assert line[pipe_pos + 1] == " ", f"Line {i+1} format issue: {line}" def test_line_numbers_boundary_conditions(self): """Test line numbering at boundary conditions (9999 vs 10000 lines)""" from utils.file_utils import _add_line_numbers # Test exactly 9999 lines (should use 4-digit width) lines_9999 = [f"Line {i}" for i in range(1, 10000)] # 9999 lines content_9999 = "\n".join(lines_9999) numbered_9999 = _add_line_numbers(content_9999) # Should use 4-digit format assert " 1โ”‚ Line 1" in numbered_9999 assert "9999โ”‚ Line 9999" in numbered_9999 # Test exactly 10000 lines (should use 5-digit width) lines_10000 = [f"Line {i}" for i in range(1, 10001)] # 10000 lines content_10000 = "\n".join(lines_10000) numbered_10000 = _add_line_numbers(content_10000) # Should use 5-digit format assert " 1โ”‚ Line 1" in numbered_10000 assert "10000โ”‚ Line 10000" in numbered_10000 if __name__ == "__main__": pytest.main([__file__, "-v"])

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/BeehiveInnovations/gemini-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server