MCP server for tangled
1"""tests for public types API"""
2
3import pytest
4from pydantic import ValidationError
5
6from tangled_mcp.types import (
7 CreateIssueResult,
8 ListBranchesResult,
9 UpdateIssueResult,
10)
11
12
13class TestRepoIdentifierValidation:
14 """test RepoIdentifier validation behavior"""
15
16 def test_strips_at_prefix(self):
17 """@ prefix is stripped during validation"""
18 result = CreateIssueResult(repo="@owner/repo", id=1)
19 assert result.repo == "owner/repo"
20
21 def test_accepts_without_at_prefix(self):
22 """repo identifier without @ works"""
23 result = CreateIssueResult(repo="owner/repo", id=1)
24 assert result.repo == "owner/repo"
25
26 def test_rejects_invalid_format(self):
27 """repo identifier without slash is rejected"""
28 with pytest.raises(ValidationError, match="invalid repo format"):
29 CreateIssueResult(repo="invalid", id=1)
30
31
32class TestIssueResultURLs:
33 """test issue result URL generation"""
34
35 def test_create_issue_url(self):
36 """create result generates correct tangled.org URL"""
37 result = CreateIssueResult(repo="owner/repo", id=42)
38 assert result.url == "https://tangled.org/@owner/repo/issues/42"
39
40 def test_update_issue_url(self):
41 """update result generates correct tangled.org URL"""
42 result = UpdateIssueResult(repo="owner/repo", id=42)
43 assert result.url == "https://tangled.org/@owner/repo/issues/42"
44
45 def test_url_handles_at_prefix_input(self):
46 """URL is correct even when input has @ prefix"""
47 result = CreateIssueResult(repo="@owner/repo", id=42)
48 assert result.url == "https://tangled.org/@owner/repo/issues/42"
49
50 def test_repo_excluded_from_serialization(self):
51 """repo field is excluded from JSON output"""
52 result = CreateIssueResult(repo="owner/repo", id=42)
53 data = result.model_dump()
54 assert "repo" not in data
55 assert data["id"] == 42
56 assert "url" in data
57
58
59class TestListBranchesFromAPIResponse:
60 """test ListBranchesResult.from_api_response constructor"""
61
62 def test_parses_branch_data(self):
63 """parses branches from API response structure"""
64 response = {
65 "branches": [
66 {"reference": {"name": "main", "hash": "abc123"}},
67 {"reference": {"name": "dev", "hash": "def456"}},
68 ],
69 }
70
71 result = ListBranchesResult.from_api_response(response)
72
73 assert len(result.branches) == 2
74 assert result.branches[0].name == "main"
75 assert result.branches[0].sha == "abc123"
76 assert result.branches[1].name == "dev"
77 assert result.branches[1].sha == "def456"
78
79 def test_handles_empty_branches(self):
80 """handles empty branches list"""
81 response = {"branches": []}
82
83 result = ListBranchesResult.from_api_response(response)
84
85 assert result.branches == []