import json import pytest import httpx import respx from gitea_mcp import ( list_labels, create_label, add_issue_labels, list_milestones, create_milestone, ) BASE = "https://gitea.test/api/v1" @respx.mock def test_list_labels(): route = respx.get(f"{BASE}/repos/owner/repo/labels").mock( return_value=httpx.Response(200, json=[{"id": 1, "name": "bug", "color": "#ee0701"}]) ) result = list_labels("owner", "repo") assert route.called assert result[0]["name"] == "bug" @respx.mock def test_create_label(): route = respx.post(f"{BASE}/repos/owner/repo/labels").mock( return_value=httpx.Response(201, json={"id": 5, "name": "enhancement"}) ) result = create_label("owner", "repo", "enhancement", "#84b6eb") assert route.called body = json.loads(route.calls[0].request.content) assert body["name"] == "enhancement" assert body["color"] == "#84b6eb" @respx.mock def test_create_label_with_description(): route = respx.post(f"{BASE}/repos/owner/repo/labels").mock( return_value=httpx.Response(201, json={"id": 6}) ) create_label("owner", "repo", "wontfix", "#ffffff", description="Not going to fix") body = json.loads(route.calls[0].request.content) assert body["description"] == "Not going to fix" @respx.mock def test_create_label_error(): respx.post(f"{BASE}/repos/owner/repo/labels").mock( return_value=httpx.Response(422, json={"message": "validation failed"}) ) with pytest.raises(RuntimeError, match="422"): create_label("owner", "repo", "bad", "notacolor") @respx.mock def test_add_issue_labels(): route = respx.post(f"{BASE}/repos/owner/repo/issues/3/labels").mock( return_value=httpx.Response(200, json=[{"id": 1}]) ) result = add_issue_labels("owner", "repo", 3, [1, 2]) assert route.called body = json.loads(route.calls[0].request.content) assert body["labels"] == [1, 2] @respx.mock def test_list_milestones(): route = respx.get(f"{BASE}/repos/owner/repo/milestones").mock( return_value=httpx.Response(200, json=[{"id": 1, "title": "v1.0"}]) ) result = list_milestones("owner", "repo") assert route.called assert result[0]["title"] == "v1.0" assert dict(route.calls[0].request.url.params)["state"] == "open" @respx.mock def test_list_milestones_closed(): route = respx.get(f"{BASE}/repos/owner/repo/milestones").mock( return_value=httpx.Response(200, json=[]) ) list_milestones("owner", "repo", state="closed") assert dict(route.calls[0].request.url.params)["state"] == "closed" @respx.mock def test_create_milestone(): route = respx.post(f"{BASE}/repos/owner/repo/milestones").mock( return_value=httpx.Response(201, json={"id": 2, "title": "v2.0"}) ) result = create_milestone("owner", "repo", "v2.0") assert route.called body = json.loads(route.calls[0].request.content) assert body["title"] == "v2.0" assert "description" not in body assert "due_on" not in body @respx.mock def test_create_milestone_with_due_date(): route = respx.post(f"{BASE}/repos/owner/repo/milestones").mock( return_value=httpx.Response(201, json={"id": 3}) ) create_milestone("owner", "repo", "v3.0", description="Major release", due_on="2025-12-31T00:00:00Z") body = json.loads(route.calls[0].request.content) assert body["description"] == "Major release" assert body["due_on"] == "2025-12-31T00:00:00Z"