Skip to content

Commit b8170cf

Browse files
committed
Use temporary files for editor tests
1 parent 7e6c405 commit b8170cf

17 files changed

Lines changed: 668 additions & 468 deletions

src/config.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import os
22
from dataclasses import dataclass
3+
from pathlib import Path
34

45

56
@dataclass
@@ -16,7 +17,9 @@ class Config:
1617
context_lines: int = int(os.getenv("LARGEFILE_CONTEXT_LINES", "2"))
1718

1819
streaming_chunk_size: int = int(os.getenv("LARGEFILE_STREAMING_CHUNK_SIZE", "8192"))
19-
backup_dir: str = os.getenv("LARGEFILE_BACKUP_DIR", ".largefile_backups")
20+
backup_dir: str = os.getenv(
21+
"LARGEFILE_BACKUP_DIR", str(Path.home() / ".largefile" / "backups")
22+
)
2023

2124
enable_tree_sitter: bool = (
2225
os.getenv("LARGEFILE_ENABLE_TREE_SITTER", "true").lower() == "true"

src/mcp_schemas.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def get_tool_schemas() -> list[types.Tool]:
131131

132132
def register_tool_handlers(server, tools_module):
133133
"""Register tool handlers with the MCP server."""
134-
134+
135135
@server.list_tools()
136136
async def list_tools() -> list[types.Tool]:
137137
"""List available tools."""
@@ -151,4 +151,4 @@ async def call_tool(name: str, arguments: dict) -> list[types.TextContent]:
151151
else:
152152
raise ValueError(f"Unknown tool: {name}")
153153

154-
return [types.TextContent(type="text", text=str(result))]
154+
return [types.TextContent(type="text", text=str(result))]

src/server.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ async def main() -> None:
2222
async with stdio_server() as (read_stream, write_stream):
2323
await server.run(
2424
read_stream, write_stream, server.create_initialization_options()
25-
)
25+
)

src/tree_parser.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,18 +48,23 @@ def get_language_parser(file_extension: str) -> Any | None:
4848
language_capsule = None
4949
if language_name == "python":
5050
import tree_sitter_python
51+
5152
language_capsule = tree_sitter_python.language()
5253
elif language_name == "javascript":
5354
import tree_sitter_javascript
55+
5456
language_capsule = tree_sitter_javascript.language()
5557
elif language_name == "typescript":
5658
import tree_sitter_typescript
59+
5760
language_capsule = tree_sitter_typescript.language_typescript()
5861
elif language_name == "rust":
5962
import tree_sitter_rust
63+
6064
language_capsule = tree_sitter_rust.language()
6165
elif language_name == "go":
6266
import tree_sitter_go
67+
6368
language_capsule = tree_sitter_go.language()
6469
else:
6570
return None

src/utils.py

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -55,73 +55,3 @@ def format_file_size(size_bytes: int) -> str:
5555
return f"{size_bytes / (1024 * 1024):.1f} MB"
5656
else:
5757
return f"{size_bytes / (1024 * 1024 * 1024):.1f} GB"
58-
59-
60-
def detect_file_strategy(file_size: int) -> str:
61-
"""Detect the best file access strategy based on size.
62-
63-
This is a convenience function that matches the logic in file_access.py
64-
65-
Args:
66-
file_size: File size in bytes
67-
68-
Returns:
69-
Strategy name: "memory", "mmap", or "streaming"
70-
"""
71-
if file_size < config.memory_threshold:
72-
return "memory"
73-
elif file_size < config.mmap_threshold:
74-
return "mmap"
75-
else:
76-
return "streaming"
77-
78-
79-
def split_long_lines(content: str, max_length: int | None = None) -> str:
80-
"""Split long lines in content for better display.
81-
82-
Args:
83-
content: Text content to process
84-
max_length: Maximum line length (defaults to config.max_line_length)
85-
86-
Returns:
87-
Content with long lines split
88-
"""
89-
if max_length is None:
90-
max_length = config.max_line_length
91-
92-
lines = content.splitlines()
93-
result_lines = []
94-
95-
for line in lines:
96-
if len(line) <= max_length:
97-
result_lines.append(line)
98-
else:
99-
# Split long line into chunks
100-
for i in range(0, len(line), max_length):
101-
chunk = line[i : i + max_length]
102-
if i + max_length < len(line):
103-
chunk += " \\" # Continuation indicator
104-
result_lines.append(chunk)
105-
106-
return "\n".join(result_lines)
107-
108-
109-
def count_file_stats(content: str) -> dict[str, int]:
110-
"""Count basic statistics about file content.
111-
112-
Args:
113-
content: File content to analyze
114-
115-
Returns:
116-
Dictionary with line_count, char_count, long_lines_count
117-
"""
118-
lines = content.splitlines()
119-
line_count = len(lines)
120-
char_count = len(content)
121-
long_lines_count = sum(1 for line in lines if is_long_line(line))
122-
123-
return {
124-
"line_count": line_count,
125-
"char_count": char_count,
126-
"long_lines_count": long_lines_count,
127-
}

tests/integration/test_codebase_workflows.py

Lines changed: 48 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from pathlib import Path
77

8-
from src.tools import get_overview, search_content, read_content, edit_content
8+
from src.tools import edit_content, get_overview, read_content, search_content
99

1010

1111
class TestCodebaseWorkflows:
@@ -17,172 +17,170 @@ def test_data_dir(self):
1717

1818
def test_web_framework_patterns_comparison(self):
1919
"""Compare patterns between Django and Laravel web frameworks.
20-
21-
Scenario: Developer migrating from Django to Laravel needs to
20+
21+
Scenario: Developer migrating from Django to Laravel needs to
2222
understand model patterns and validation approaches.
2323
"""
2424
django_models = self.test_data_dir / "python" / "django-models.py"
2525
laravel_model = self.test_data_dir / "php" / "laravel-model.php"
26-
26+
2727
# Get overview of both frameworks
2828
django_overview = get_overview(str(django_models))
2929
laravel_overview = get_overview(str(laravel_model))
30-
30+
3131
assert django_overview["line_count"] > 0
3232
assert laravel_overview["line_count"] > 0
33-
33+
3434
# Search for model patterns
3535
django_models_search = search_content(str(django_models), "class", fuzzy=False)
3636
laravel_models_search = search_content(str(laravel_model), "class", fuzzy=False)
37-
37+
3838
assert django_models_search["total_matches"] > 0
3939
assert laravel_models_search["total_matches"] > 0
40-
40+
4141
# Search for validation patterns
4242
django_validation = search_content(str(django_models), "valid", fuzzy=True)
4343
laravel_validation = search_content(str(laravel_model), "valid", fuzzy=True)
44-
44+
4545
# At least one should have validation patterns
46-
total_validation = django_validation["total_matches"] + laravel_validation["total_matches"]
46+
total_validation = (
47+
django_validation["total_matches"] + laravel_validation["total_matches"]
48+
)
4749
assert total_validation >= 0
4850

4951
def test_large_javascript_codebase_navigation(self):
5052
"""Navigate large JavaScript utility library effectively.
51-
53+
5254
Scenario: Developer needs to understand specific utility functions
5355
in the Lodash library (532KB file).
5456
"""
5557
lodash_file = self.test_data_dir / "javascript" / "lodash-utility.js"
56-
58+
5759
if not lodash_file.exists():
5860
return # Skip if file doesn't exist
59-
61+
6062
# Get overview - should use mmap strategy for this size
6163
overview = get_overview(str(lodash_file))
6264
assert overview["file_size"] > 500_000 # 532KB file
6365
assert overview["line_count"] > 1000
64-
66+
6567
# Search for common utility functions
6668
function_search = search_content(str(lodash_file), "function", max_results=10)
6769
assert function_search["total_matches"] > 0
68-
70+
6971
# Test performance with specific function search
7072
map_search = search_content(str(lodash_file), "map", fuzzy=True, max_results=5)
7173
assert map_search["total_matches"] >= 0
7274

7375
def test_cross_language_async_patterns(self):
7476
"""Find async patterns across different programming languages.
75-
77+
7678
Scenario: Developer wants to understand async patterns across
7779
JavaScript, Python, Go, and C# codebases.
7880
"""
7981
files = [
8082
self.test_data_dir / "javascript" / "lodash-utility.js",
81-
self.test_data_dir / "python" / "django-models.py",
83+
self.test_data_dir / "python" / "django-models.py",
8284
self.test_data_dir / "go" / "docker-daemon.go",
83-
self.test_data_dir / "csharp" / "aspnet-controller.cs"
85+
self.test_data_dir / "csharp" / "aspnet-controller.cs",
8486
]
85-
87+
8688
async_patterns_found = 0
8789
for file_path in files:
8890
if file_path.exists():
8991
result = search_content(str(file_path), "async", fuzzy=True)
9092
async_patterns_found += result["total_matches"]
91-
93+
9294
# Should find some async patterns across languages
9395
assert async_patterns_found >= 0
9496

9597
def test_rust_serialization_code_analysis(self):
9698
"""Analyze Rust serialization library code structure.
97-
98-
Scenario: Developer learning Rust needs to understand
99+
100+
Scenario: Developer learning Rust needs to understand
99101
serialization patterns in the Serde library.
100102
"""
101103
serde_file = self.test_data_dir / "rust" / "serde-derive.rs"
102-
104+
103105
if not serde_file.exists():
104106
return # Skip if file doesn't exist
105-
107+
106108
overview = get_overview(str(serde_file))
107109
assert overview["line_count"] > 0
108-
110+
109111
# Search for Rust-specific patterns
110112
impl_search = search_content(str(serde_file), "impl", fuzzy=False)
111113
struct_search = search_content(str(serde_file), "struct", fuzzy=False)
112-
114+
113115
# Should find some Rust patterns
114116
rust_patterns = impl_search["total_matches"] + struct_search["total_matches"]
115117
assert rust_patterns > 0
116118

117119
def test_spring_java_application_navigation(self):
118120
"""Navigate Java Spring application code.
119-
120-
Scenario: Developer needs to understand Spring Boot
121+
122+
Scenario: Developer needs to understand Spring Boot
121123
application structure and annotations.
122124
"""
123125
spring_file = self.test_data_dir / "java" / "spring-application.java"
124-
126+
125127
overview = get_overview(str(spring_file))
126128
assert overview["file_size"] > 0
127-
129+
128130
# Search for Spring annotations and patterns
129131
annotation_search = search_content(str(spring_file), "@", fuzzy=False)
130132
class_search = search_content(str(spring_file), "class", fuzzy=False)
131-
133+
132134
assert annotation_search["total_matches"] >= 0
133135
assert class_search["total_matches"] >= 0
134136

135137
def test_code_search_and_context_extraction(self):
136138
"""Test targeted code search with context extraction.
137-
139+
138140
Scenario: Developer needs to find specific method implementations
139141
with surrounding context for understanding.
140142
"""
141143
vscode_extension = self.test_data_dir / "typescript" / "vscode-extension.ts"
142-
144+
143145
if not vscode_extension.exists():
144146
return # Skip if file doesn't exist
145-
147+
146148
# Search for function definitions with context
147-
function_results = search_content(str(vscode_extension), "function", context_lines=3)
148-
149+
function_results = search_content(
150+
str(vscode_extension), "function", context_lines=3
151+
)
152+
149153
for result in function_results["results"][:3]: # Check first 3 results
150154
assert "context_before" in result
151155
assert "context_after" in result
152156
assert "line_number" in result
153-
157+
154158
# Read the specific function with more context
155159
line_num = result["line_number"]
156160
detailed_content = read_content(
157-
str(vscode_extension),
158-
line_num,
159-
mode="lines"
161+
str(vscode_extension), line_num, mode="lines"
160162
)
161163
assert "content" in detailed_content
162164

163165
def test_safe_code_editing_preview(self):
164166
"""Test safe code editing with preview mode.
165-
167+
166168
Scenario: Developer wants to preview code changes before applying
167169
them to ensure no unintended modifications.
168170
"""
169171
# Use a small file for editing tests
170172
spring_file = self.test_data_dir / "java" / "spring-application.java"
171-
173+
172174
# Test search and replace in preview mode
173175
result = edit_content(
174-
str(spring_file),
175-
"class",
176-
"public class",
177-
preview=True,
178-
fuzzy=False
176+
str(spring_file), "class", "public class", preview=True, fuzzy=False
179177
)
180-
178+
181179
assert "success" in result
182180
assert "preview" in result
183181
assert "changes_made" in result
184-
182+
185183
# Verify preview mode doesn't actually modify file
186184
if result["success"]:
187185
assert result["preview"] is True
188-
assert "backup_created" not in result # No backup in preview mode
186+
assert "backup_created" not in result # No backup in preview mode

0 commit comments

Comments
 (0)