Skip to content

Commit bc8f455

Browse files
test(mcp-host-config): add adapter registry unit tests
Add 12 unit tests (AR-01 to AR-08 + supporting tests) for AdapterRegistry: Registry Operations: - AR-01: Registry initializes with all 8 default host adapters - AR-02: get_adapter() returns adapter with matching host_name - AR-03: get_adapter() raises KeyError for unknown host - AR-04: has_adapter() returns True for registered hosts - AR-05: has_adapter() returns False for unknown hosts - AR-06: register() adds custom adapters to registry - AR-07: register() raises ValueError for duplicate host - AR-08: unregister() removes adapter from registry Global Functions: - get_default_registry() returns singleton instance - get_adapter() function uses default registry correctly - Error handling for unknown hosts These tests verify the adapter registry infrastructure that maps host names to their corresponding adapter implementations. All 12 tests pass.
1 parent 5371a43 commit bc8f455

File tree

1 file changed

+158
-0
lines changed

1 file changed

+158
-0
lines changed
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
"""Unit tests for adapter registry.
2+
3+
Test IDs: AR-01 to AR-08 (per 02-test_architecture_rebuild_v0.md)
4+
Scope: Registry initialization, adapter lookup, registration.
5+
"""
6+
7+
import unittest
8+
9+
from hatch.mcp_host_config.adapters import (
10+
AdapterRegistry,
11+
get_adapter,
12+
get_default_registry,
13+
BaseAdapter,
14+
ClaudeAdapter,
15+
CodexAdapter,
16+
CursorAdapter,
17+
GeminiAdapter,
18+
KiroAdapter,
19+
LMStudioAdapter,
20+
VSCodeAdapter,
21+
)
22+
23+
24+
class TestAdapterRegistry(unittest.TestCase):
25+
"""Tests for AdapterRegistry class (AR-01 to AR-08)."""
26+
27+
def setUp(self):
28+
"""Create a fresh registry for each test."""
29+
self.registry = AdapterRegistry()
30+
31+
def test_AR01_registry_has_all_default_hosts(self):
32+
"""AR-01: Registry initializes with all default host adapters."""
33+
expected_hosts = {
34+
"claude-desktop",
35+
"claude-code",
36+
"codex",
37+
"cursor",
38+
"gemini",
39+
"kiro",
40+
"lmstudio",
41+
"vscode",
42+
}
43+
44+
actual_hosts = set(self.registry.get_supported_hosts())
45+
46+
self.assertEqual(actual_hosts, expected_hosts)
47+
48+
def test_AR02_get_adapter_returns_correct_type(self):
49+
"""AR-02: get_adapter() returns adapter with matching host_name."""
50+
test_cases = [
51+
("claude-desktop", ClaudeAdapter),
52+
("claude-code", ClaudeAdapter),
53+
("codex", CodexAdapter),
54+
("cursor", CursorAdapter),
55+
("gemini", GeminiAdapter),
56+
("kiro", KiroAdapter),
57+
("lmstudio", LMStudioAdapter),
58+
("vscode", VSCodeAdapter),
59+
]
60+
61+
for host_name, expected_cls in test_cases:
62+
with self.subTest(host=host_name):
63+
adapter = self.registry.get_adapter(host_name)
64+
self.assertIsInstance(adapter, expected_cls)
65+
self.assertEqual(adapter.host_name, host_name)
66+
67+
def test_AR03_get_adapter_raises_for_unknown_host(self):
68+
"""AR-03: get_adapter() raises KeyError for unknown host."""
69+
with self.assertRaises(KeyError) as context:
70+
self.registry.get_adapter("unknown-host")
71+
72+
self.assertIn("unknown-host", str(context.exception))
73+
self.assertIn("Supported hosts", str(context.exception))
74+
75+
def test_AR04_has_adapter_returns_true_for_registered(self):
76+
"""AR-04: has_adapter() returns True for registered hosts."""
77+
for host_name in self.registry.get_supported_hosts():
78+
with self.subTest(host=host_name):
79+
self.assertTrue(self.registry.has_adapter(host_name))
80+
81+
def test_AR05_has_adapter_returns_false_for_unknown(self):
82+
"""AR-05: has_adapter() returns False for unknown hosts."""
83+
self.assertFalse(self.registry.has_adapter("unknown-host"))
84+
85+
def test_AR06_register_adds_new_adapter(self):
86+
"""AR-06: register() adds a new adapter to registry."""
87+
# Create a custom adapter for testing
88+
class CustomAdapter(BaseAdapter):
89+
@property
90+
def host_name(self):
91+
return "custom-host"
92+
93+
def get_supported_fields(self):
94+
return frozenset({"command", "args"})
95+
96+
def validate(self, config):
97+
pass
98+
99+
def serialize(self, config):
100+
return {"command": config.command}
101+
102+
custom = CustomAdapter()
103+
self.registry.register(custom)
104+
105+
self.assertTrue(self.registry.has_adapter("custom-host"))
106+
self.assertIs(self.registry.get_adapter("custom-host"), custom)
107+
108+
def test_AR07_register_raises_for_duplicate(self):
109+
"""AR-07: register() raises ValueError for duplicate host name."""
110+
# Try to register another Claude adapter
111+
duplicate = ClaudeAdapter(variant="desktop")
112+
113+
with self.assertRaises(ValueError) as context:
114+
self.registry.register(duplicate)
115+
116+
self.assertIn("claude-desktop", str(context.exception))
117+
self.assertIn("already registered", str(context.exception))
118+
119+
def test_AR08_unregister_removes_adapter(self):
120+
"""AR-08: unregister() removes adapter from registry."""
121+
self.assertTrue(self.registry.has_adapter("claude-desktop"))
122+
123+
self.registry.unregister("claude-desktop")
124+
125+
self.assertFalse(self.registry.has_adapter("claude-desktop"))
126+
127+
def test_unregister_raises_for_unknown(self):
128+
"""unregister() raises KeyError for unknown host."""
129+
with self.assertRaises(KeyError):
130+
self.registry.unregister("unknown-host")
131+
132+
133+
class TestGlobalRegistryFunctions(unittest.TestCase):
134+
"""Tests for global registry convenience functions."""
135+
136+
def test_get_default_registry_returns_singleton(self):
137+
"""get_default_registry() returns same instance on multiple calls."""
138+
registry1 = get_default_registry()
139+
registry2 = get_default_registry()
140+
141+
self.assertIs(registry1, registry2)
142+
143+
def test_get_adapter_uses_default_registry(self):
144+
"""get_adapter() function uses the default registry."""
145+
adapter = get_adapter("claude-desktop")
146+
147+
self.assertIsInstance(adapter, ClaudeAdapter)
148+
self.assertEqual(adapter.host_name, "claude-desktop")
149+
150+
def test_get_adapter_raises_for_unknown(self):
151+
"""get_adapter() function raises KeyError for unknown host."""
152+
with self.assertRaises(KeyError):
153+
get_adapter("unknown-host")
154+
155+
156+
if __name__ == "__main__":
157+
unittest.main()
158+

0 commit comments

Comments
 (0)