Skip to content

Commit 025ebce

Browse files
authored
ci: use platform ci tests > python version (#3)
* ci: use platform ci tests > python version * delete unnecessary entrypoint * Windows test fixes * Skip flaky Windows signal test * ci cache deps * Add call tool handler tests
1 parent 0317d53 commit 025ebce

File tree

9 files changed

+127
-26
lines changed

9 files changed

+127
-26
lines changed

.github/workflows/ci.yml

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,45 @@
11
name: CI
22

33
on:
4-
pull_request:
5-
branches: [ main ]
64
push:
75
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
88

99
jobs:
1010
test:
11-
runs-on: ubuntu-latest
11+
runs-on: ${{ matrix.os }}
1212
strategy:
1313
matrix:
14-
python-version: ["3.10", "3.11", "3.12"]
14+
os: [ubuntu-latest, macos-latest, windows-latest]
15+
python-version: ["3.11"]
1516

1617
steps:
1718
- name: Checkout code
1819
uses: actions/checkout@v4
1920

2021
- name: Install uv
21-
uses: astral-sh/setup-uv@v3
22+
uses: astral-sh/setup-uv@v6
2223
with:
23-
version: "latest"
24+
enable-cache: true
25+
cache-dependency-glob: "uv.lock"
2426

2527
- name: Set up Python ${{ matrix.python-version }}
2628
uses: actions/setup-python@v5
2729
with:
2830
python-version: ${{ matrix.python-version }}
2931

3032
- name: Install dependencies
31-
run: uv sync --all-extras --dev
33+
run: uv sync --dev
3234

3335
- name: Run tests
3436
run: uv run pytest -v --tb=short
3537

3638
- name: Run type checking
37-
run: uv run mypy src/
39+
run: uv run mypy src
3840

3941
- name: Run linting
40-
run: uv run ruff check
42+
run: uv run ruff check .
4143

4244
- name: Check formatting
4345
run: uv run ruff format --check
@@ -51,12 +53,15 @@ jobs:
5153
uses: actions/checkout@v4
5254

5355
- name: Install uv
54-
uses: astral-sh/setup-uv@v3
56+
uses: astral-sh/setup-uv@v6
57+
with:
58+
enable-cache: true
59+
cache-dependency-glob: "uv.lock"
5560

5661
- name: Set up Python
5762
uses: actions/setup-python@v5
5863
with:
59-
python-version: "3.10"
64+
python-version: "3.11"
6065

6166
- name: Install dependencies
6267
run: uv sync --dev
@@ -84,12 +89,15 @@ jobs:
8489
uses: actions/checkout@v4
8590

8691
- name: Install uv
87-
uses: astral-sh/setup-uv@v3
92+
uses: astral-sh/setup-uv@v6
93+
with:
94+
enable-cache: true
95+
cache-dependency-glob: "uv.lock"
8896

8997
- name: Set up Python
9098
uses: actions/setup-python@v5
9199
with:
92-
python-version: "3.10"
100+
python-version: "3.11"
93101

94102
- name: Install dependencies
95103
run: uv sync --dev

main.py

Lines changed: 0 additions & 6 deletions
This file was deleted.

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "diffchunk"
3-
version = "0.1.5"
3+
version = "0.1.6"
44
description = "MCP server for navigating large diff files with intelligent chunking"
55
readme = "README.md"
66
requires-python = ">=3.10"

src/tools.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,14 @@ def _load_diff_internal(
6464
resolved_file_path = os.path.realpath(os.path.expanduser(absolute_file_path))
6565

6666
# Validate file exists and is readable
67+
if os.path.exists(resolved_file_path) and not os.path.isfile(
68+
resolved_file_path
69+
):
70+
raise ValueError(f"Path is not a file: {resolved_file_path}")
71+
6772
if not os.path.exists(resolved_file_path):
6873
raise ValueError(f"Diff file not found: {absolute_file_path}")
6974

70-
if not os.path.isfile(resolved_file_path):
71-
raise ValueError(f"Path is not a file: {resolved_file_path}")
72-
7375
if not os.access(resolved_file_path, os.R_OK):
7476
raise ValueError(f"Cannot read file: {resolved_file_path}")
7577

tests/test_cli_integration.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
"""CLI integration tests for main.py entry point."""
22

3+
import platform
34
import subprocess
45
import sys
56
import time
@@ -86,6 +87,10 @@ def test_cli_server_startup_basic(self):
8687
process.kill()
8788
process.wait()
8889

90+
@pytest.mark.skipif(
91+
platform.system() == "Windows",
92+
reason="Signal handling unreliable on Windows CI",
93+
)
8994
def test_cli_keyboard_interrupt_handling(self):
9095
"""Test CLI handles KeyboardInterrupt gracefully."""
9196
process = subprocess.Popen(

tests/test_filesystem_edge_cases.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ def test_load_diff_nonexistent_file(self, tools):
3838
def test_load_diff_directory_instead_of_file(self, tools):
3939
"""Test loading directory instead of file."""
4040
with pytest.raises(ValueError, match="not a file"):
41-
tools.load_diff("/tmp")
41+
tools.load_diff(tempfile.gettempdir())
4242

4343
def test_load_diff_empty_file_path(self, tools):
4444
"""Test loading with empty file path."""

tests/test_handle_call_tool.py

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""Test handle_call_tool for code coverage."""
2+
3+
import json
4+
from pathlib import Path
5+
6+
import pytest
7+
from mcp.types import CallToolRequest
8+
9+
from src.server import DiffChunkServer
10+
11+
12+
class TestHandleCallTool:
13+
"""Test handle_call_tool for coverage."""
14+
15+
@pytest.fixture
16+
def server(self):
17+
return DiffChunkServer()
18+
19+
@pytest.fixture
20+
def react_diff_file(self):
21+
diff_file = Path(__file__).parent / "test_data" / "react_18.0_to_18.3.diff"
22+
if not diff_file.exists():
23+
pytest.skip("React test diff not found")
24+
return str(diff_file)
25+
26+
@pytest.mark.asyncio
27+
async def test_handle_call_tool_coverage(self, server, react_diff_file):
28+
"""Test all paths in handle_call_tool for coverage."""
29+
handler = server.app.request_handlers[CallToolRequest]
30+
31+
# Test load_diff
32+
request = CallToolRequest(
33+
method="tools/call",
34+
params={
35+
"name": "load_diff",
36+
"arguments": {"absolute_file_path": react_diff_file},
37+
},
38+
)
39+
result = await handler(request)
40+
data = json.loads(result.root.content[0].text)
41+
assert data["chunks"] > 0
42+
43+
# Test list_chunks
44+
request = CallToolRequest(
45+
method="tools/call",
46+
params={
47+
"name": "list_chunks",
48+
"arguments": {"absolute_file_path": react_diff_file},
49+
},
50+
)
51+
result = await handler(request)
52+
chunks = json.loads(result.root.content[0].text)
53+
assert len(chunks) > 0
54+
55+
# Test get_chunk
56+
request = CallToolRequest(
57+
method="tools/call",
58+
params={
59+
"name": "get_chunk",
60+
"arguments": {"absolute_file_path": react_diff_file, "chunk_number": 1},
61+
},
62+
)
63+
result = await handler(request)
64+
assert "=== Chunk 1 of" in result.root.content[0].text
65+
66+
# Test find_chunks_for_files
67+
request = CallToolRequest(
68+
method="tools/call",
69+
params={
70+
"name": "find_chunks_for_files",
71+
"arguments": {"absolute_file_path": react_diff_file, "pattern": "*"},
72+
},
73+
)
74+
result = await handler(request)
75+
chunk_nums = json.loads(result.root.content[0].text)
76+
assert isinstance(chunk_nums, list)
77+
78+
# Test unknown tool
79+
request = CallToolRequest(
80+
method="tools/call", params={"name": "unknown_tool", "arguments": {}}
81+
)
82+
result = await handler(request)
83+
assert "Unknown tool: unknown_tool" in result.root.content[0].text
84+
85+
# Test None arguments (validation error from MCP layer)
86+
request = CallToolRequest(
87+
method="tools/call", params={"name": "load_diff", "arguments": None}
88+
)
89+
result = await handler(request)
90+
assert "Input validation error" in result.root.content[0].text

tests/test_integration.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
"""Integration tests using real diff files from test_data."""
22

3+
import tempfile
4+
35
import pytest
46
from pathlib import Path
57

@@ -200,7 +202,7 @@ def test_invalid_file_errors(self, tools):
200202

201203
# Directory instead of file
202204
with pytest.raises(ValueError, match="not a file"):
203-
tools.load_diff("/tmp")
205+
tools.load_diff(tempfile.gettempdir())
204206

205207
def test_chunk_size_consistency(self, tools, test_data_dir):
206208
"""Test that chunk sizes are respected reasonably."""

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)