@@ -1,13 +1,15 @@
1 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- """Tests for navegador.mcp.server — create_mcp_server and tool handlers."""
1 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ """Tests for navegador.mcp.server — create_mcp_server and all tool handlers."""
2 2 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
3 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ import json
3 4 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
from unittest.mock import MagicMock, patch
4 5 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
5 6 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
import pytest
6 7 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
7 8 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
from navegador.context.loader import ContextBundle, ContextNode
8 9 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
10 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ── Helpers ───────────────────────────────────────────────────────────────────
9 11 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
10 12 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
def _node(name="foo", type_="Function", file_path="app.py"):
11 13 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return ContextNode(name=name, type=type_, file_path=file_path)
12 14 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
13 15 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
@@ -21,104 +23,332 @@
21 23 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
store.node_count.return_value = 5
22 24 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
store.edge_count.return_value = 3
23 25 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return store
24 26 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
25 27 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
26 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- def _mock_loader(store=None):
27 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- from navegador.context import ContextLoader
28 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- loader = MagicMock(spec=ContextLoader)
29 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- loader.store = store or _mock_store()
30 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- loader.load_file.return_value = _bundle()
31 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- loader.load_function.return_value = _bundle()
32 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- loader.load_class.return_value = _bundle()
33 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- loader.search.return_value = []
34 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- return loader
35 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
36 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
37 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # ── create_mcp_server — import error ─────────────────────────────────────────
38 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
39 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- class TestCreateMcpServerImport:
40 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- def test_raises_import_error_if_mcp_not_installed(self):
41 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- with patch.dict("sys.modules", {"mcp": None, "mcp.server": None, "mcp.types": None}):
42 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- from navegador.mcp.server import create_mcp_server
43 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- with pytest.raises(ImportError, match="mcp"):
44 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- create_mcp_server(lambda: _mock_store())
45 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
46 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
47 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # ── create_mcp_server — happy path ────────────────────────────────────────────
48 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
49 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- class TestCreateMcpServer:
50 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- def _make_server(self, loader=None):
51 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- """Build a server with mocked mcp module."""
52 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_loader = loader or _mock_loader()
53 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_server = MagicMock()
54 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
55 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- # Capture the decorated functions
56 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- list_tools_fn = None
57 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- call_tool_fn = None
28 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class _ServerFixture:
29 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ """
30 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ Builds a navegador MCP server with mocked mcp module and captures the
31 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ list_tools and call_tool async handlers so they can be invoked directly.
32 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ """
33 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
34 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def __init__(self, loader=None):
35 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.store = _mock_store()
36 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.loader = loader or self._default_loader()
37 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.list_tools_fn = None
38 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.call_tool_fn = None
39 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self._build()
40 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
41 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def _default_loader(self):
42 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from navegador.context import ContextLoader
43 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ loader = MagicMock(spec=ContextLoader)
44 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ loader.store = self.store
45 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ loader.load_file.return_value = _bundle("file_target")
46 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ loader.load_function.return_value = _bundle("fn_target")
47 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ loader.load_class.return_value = _bundle("cls_target")
48 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ loader.search.return_value = []
49 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ return loader
50 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
51 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def _build(self):
52 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ list_holder = {}
53 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ call_holder = {}
58 54 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
59 55 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
def list_tools_decorator():
60 56 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
def decorator(fn):
61 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- nonlocal list_tools_fn
62 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- list_tools_fn = fn
57 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ list_holder["fn"] = fn
63 58 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return fn
64 59 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
return decorator
65 60 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
66 61 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
def call_tool_decorator():
67 62 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
def decorator(fn):
68 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- nonlocal call_tool_fn
69 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- call_tool_fn = fn
70 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- return fn
71 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- return decorator
72 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
73 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_server.list_tools = list_tools_decorator
74 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_server.call_tool = call_tool_decorator
75 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
76 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_mcp_server_module = MagicMock()
77 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_mcp_server_module.Server.return_value = mock_server
78 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_mcp_types_module = MagicMock()
79 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_mcp_types_module.Tool = MagicMock
80 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_mcp_types_module.TextContent = MagicMock
81 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
82 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- with patch.dict("sys.modules", {
83 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- "mcp": MagicMock(),
84 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- "mcp.server": mock_mcp_server_module,
85 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- "mcp.types": mock_mcp_types_module,
86 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- }), patch("navegador.context.ContextLoader", return_value=mock_loader):
87 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- from importlib import reload
88 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
89 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- import navegador.mcp.server as srv
90 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- reload(srv)
91 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- srv.create_mcp_server(lambda: mock_loader.store)
92 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
93 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- return list_tools_fn, call_tool_fn, mock_loader
94 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
95 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- def test_returns_server(self):
96 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_server = MagicMock()
97 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_server.list_tools = lambda: lambda f: f
98 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_server.call_tool = lambda: lambda f: f
99 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
100 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_mcp_server_module = MagicMock()
101 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- mock_mcp_server_module.Server.return_value = mock_server
102 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
103 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- with patch.dict("sys.modules", {
104 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- "mcp": MagicMock(),
105 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- "mcp.server": mock_mcp_server_module,
106 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- "mcp.types": MagicMock(),
107 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- }):
108 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- from importlib import reload
109 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
110 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- import navegador.mcp.server as srv
111 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- reload(srv)
112 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- result = srv.create_mcp_server(lambda: _mock_store())
113 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- assert result is mock_server
114 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
115 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- def test_raises_if_mcp_not_available(self):
116 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- with patch.dict("sys.modules", {
117 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- "mcp": None, "mcp.server": None, "mcp.types": None,
118 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- }):
119 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- from importlib import reload
120 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
-
121 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- import navegador.mcp.server as srv
122 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- reload(srv)
123 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- with pytest.raises(ImportError):
124 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
- srv.create_mcp_server(lambda: _mock_store())
63 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ call_holder["fn"] = fn
64 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ return fn
65 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ return decorator
66 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
67 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_server = MagicMock()
68 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_server.list_tools = list_tools_decorator
69 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_server.call_tool = call_tool_decorator
70 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
71 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_mcp_server = MagicMock()
72 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_mcp_server.Server.return_value = mock_server
73 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
74 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_mcp_types = MagicMock()
75 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_mcp_types.Tool = dict # Tool(...) → dict so we can inspect fields
76 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_mcp_types.TextContent = dict # TextContent(type=..., text=...) → dict
77 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
78 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with patch.dict("sys.modules", {
79 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "mcp": MagicMock(),
80 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "mcp.server": mock_mcp_server,
81 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "mcp.types": mock_mcp_types,
82 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }), patch("navegador.context.ContextLoader", return_value=self.loader):
83 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from importlib import reload
84 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
85 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ import navegador.mcp.server as srv
86 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ reload(srv)
87 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.server = srv.create_mcp_server(lambda: self.store)
88 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
89 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.list_tools_fn = list_holder["fn"]
90 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.call_tool_fn = call_holder["fn"]
91 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
92 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
93 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ── Import guard ──────────────────────────────────────────────────────────────
94 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
95 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestCreateMcpServerImport:
96 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def test_raises_import_error_if_mcp_not_installed(self):
97 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with patch.dict("sys.modules", {"mcp": None, "mcp.server": None, "mcp.types": None}):
98 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ from importlib import reload
99 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
100 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ import navegador.mcp.server as srv
101 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ reload(srv)
102 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with pytest.raises(ImportError, match="mcp"):
103 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ srv.create_mcp_server(lambda: _mock_store())
104 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
105 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
106 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ── list_tools ────────────────────────────────────────────────────────────────
107 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
108 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestListTools:
109 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def setup_method(self):
110 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx = _ServerFixture()
111 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
112 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
113 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_returns_seven_tools(self):
114 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ tools = await self.fx.list_tools_fn()
115 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert len(tools) == 7
116 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
117 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
118 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_tool_names(self):
119 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ tools = await self.fx.list_tools_fn()
120 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ names = {t["name"] for t in tools}
121 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert names == {
122 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "ingest_repo",
123 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "load_file_context",
124 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "load_function_context",
125 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "load_class_context",
126 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "search_symbols",
127 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "query_graph",
128 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "graph_stats",
129 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ }
130 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
131 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
132 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_ingest_repo_requires_path(self):
133 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ tools = await self.fx.list_tools_fn()
134 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ t = next(t for t in tools if t["name"] == "ingest_repo")
135 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "path" in t["inputSchema"]["required"]
136 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
137 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
138 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_load_function_context_requires_name_and_file_path(self):
139 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ tools = await self.fx.list_tools_fn()
140 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ t = next(t for t in tools if t["name"] == "load_function_context")
141 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "name" in t["inputSchema"]["required"]
142 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "file_path" in t["inputSchema"]["required"]
143 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
144 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
145 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ── call_tool — ingest_repo ───────────────────────────────────────────────────
146 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
147 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestCallToolIngestRepo:
148 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def setup_method(self):
149 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx = _ServerFixture()
150 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
151 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
152 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_calls_ingester_and_returns_json(self):
153 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ingester = MagicMock()
154 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ingester.ingest.return_value = {"files": 3, "functions": 10, "classes": 2, "edges": 15}
155 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
156 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with patch("navegador.ingestion.RepoIngester", return_value=mock_ingester):
157 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = await self.fx.call_tool_fn("ingest_repo", {"path": "/some/repo"})
158 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
159 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert len(result) == 1
160 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ data = json.loads(result[0]["text"])
161 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert data["files"] == 3
162 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert data["functions"] == 10
163 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
164 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
165 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_passes_clear_flag(self):
166 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ingester = MagicMock()
167 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ingester.ingest.return_value = {"files": 0, "functions": 0, "classes": 0, "edges": 0}
168 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
169 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with patch("navegador.ingestion.RepoIngester", return_value=mock_ingester):
170 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ await self.fx.call_tool_fn("ingest_repo", {"path": "/repo", "clear": True})
171 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
172 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ingester.ingest.assert_called_once_with("/repo", clear=True)
173 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
174 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
175 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_clear_defaults_to_false(self):
176 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ingester = MagicMock()
177 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ingester.ingest.return_value = {"files": 0, "functions": 0, "classes": 0, "edges": 0}
178 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
179 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ with patch("navegador.ingestion.RepoIngester", return_value=mock_ingester):
180 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ await self.fx.call_tool_fn("ingest_repo", {"path": "/repo"})
181 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
182 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ mock_ingester.ingest.assert_called_once_with("/repo", clear=False)
183 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
184 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
185 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ── call_tool — load_file_context ─────────────────────────────────────────────
186 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
187 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestCallToolLoadFileContext:
188 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def setup_method(self):
189 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx = _ServerFixture()
190 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
191 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
192 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_returns_markdown_by_default(self):
193 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = await self.fx.call_tool_fn("load_file_context", {"file_path": "src/main.py"})
194 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx.loader.load_file.assert_called_once_with("src/main.py")
195 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "file_target" in result[0]["text"]
196 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
197 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
198 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_returns_json_when_requested(self):
199 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = await self.fx.call_tool_fn(
200 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "load_file_context", {"file_path": "src/main.py", "format": "json"}
201 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ )
202 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ data = json.loads(result[0]["text"])
203 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert data["target"]["name"] == "file_target"
204 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
205 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
206 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_markdown_format_explicit(self):
207 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = await self.fx.call_tool_fn(
208 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "load_file_context", {"file_path": "src/main.py", "format": "markdown"}
209 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ )
210 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "file_target" in result[0]["text"]
211 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
212 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
213 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ── call_tool — load_function_context ────────────────────────────────────────
214 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
215 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestCallToolLoadFunctionContext:
216 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def setup_method(self):
217 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx = _ServerFixture()
218 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
219 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
220 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_calls_loader_with_depth(self):
221 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ await self.fx.call_tool_fn(
222 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "load_function_context",
223 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ {"name": "parse", "file_path": "parser.py", "depth": 3},
224 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ )
225 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx.loader.load_function.assert_called_once_with("parse", "parser.py", depth=3)
226 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
227 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
228 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_depth_defaults_to_two(self):
229 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ await self.fx.call_tool_fn(
230 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "load_function_context", {"name": "parse", "file_path": "parser.py"}
231 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ )
232 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx.loader.load_function.assert_called_once_with("parse", "parser.py", depth=2)
233 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
234 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
235 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_returns_json_when_requested(self):
236 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = await self.fx.call_tool_fn(
237 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "load_function_context",
238 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ {"name": "parse", "file_path": "parser.py", "format": "json"},
239 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ )
240 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ data = json.loads(result[0]["text"])
241 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert data["target"]["name"] == "fn_target"
242 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
243 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
244 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ── call_tool — load_class_context ───────────────────────────────────────────
245 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
246 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestCallToolLoadClassContext:
247 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def setup_method(self):
248 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx = _ServerFixture()
249 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
250 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
251 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_calls_loader_with_name_and_file(self):
252 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ await self.fx.call_tool_fn(
253 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "load_class_context", {"name": "AuthService", "file_path": "auth.py"}
254 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ )
255 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx.loader.load_class.assert_called_once_with("AuthService", "auth.py")
256 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
257 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
258 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_returns_markdown_by_default(self):
259 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = await self.fx.call_tool_fn(
260 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "load_class_context", {"name": "AuthService", "file_path": "auth.py"}
261 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ )
262 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "cls_target" in result[0]["text"]
263 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
264 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
265 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_returns_json_when_requested(self):
266 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = await self.fx.call_tool_fn(
267 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ "load_class_context",
268 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ {"name": "AuthService", "file_path": "auth.py", "format": "json"},
269 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ )
270 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ data = json.loads(result[0]["text"])
271 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert data["target"]["name"] == "cls_target"
272 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
273 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
274 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ── call_tool — search_symbols ───────────────────────────────────────────────
275 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
276 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestCallToolSearchSymbols:
277 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def setup_method(self):
278 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx = _ServerFixture()
279 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
280 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
281 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_returns_no_results_message_on_empty(self):
282 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = await self.fx.call_tool_fn("search_symbols", {"query": "xyz"})
283 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert result[0]["text"] == "No results."
284 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
285 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
286 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_formats_results_as_bullet_list(self):
287 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ hit = ContextNode(name="do_thing", type="Function", file_path="utils.py", line_start=10)
288 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx.loader.search.return_value = [hit]
289 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = await self.fx.call_tool_fn("search_symbols", {"query": "do"})
290 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ text = result[0]["text"]
291 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "do_thing" in text
292 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "utils.py" in text
293 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "Function" in text
294 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
295 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
296 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_passes_limit(self):
297 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ await self.fx.call_tool_fn("search_symbols", {"query": "foo", "limit": 5})
298 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx.loader.search.assert_called_once_with("foo", limit=5)
299 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
300 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
301 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_limit_defaults_to_twenty(self):
302 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ await self.fx.call_tool_fn("search_symbols", {"query": "foo"})
303 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx.loader.search.assert_called_once_with("foo", limit=20)
304 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
305 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
306 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ── call_tool — query_graph ───────────────────────────────────────────────────
307 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
308 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestCallToolQueryGraph:
309 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def setup_method(self):
310 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx = _ServerFixture()
311 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
312 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
313 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_executes_cypher_and_returns_json(self):
314 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx.store.query.return_value = MagicMock(result_set=[["node_a"], ["node_b"]])
315 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = await self.fx.call_tool_fn("query_graph", {"cypher": "MATCH (n) RETURN n"})
316 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx.store.query.assert_called_once_with("MATCH (n) RETURN n")
317 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ data = json.loads(result[0]["text"])
318 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert len(data) == 2
319 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
320 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
321 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_empty_result_set(self):
322 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx.store.query.return_value = MagicMock(result_set=[])
323 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = await self.fx.call_tool_fn("query_graph", {"cypher": "MATCH (n) RETURN n"})
324 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ data = json.loads(result[0]["text"])
325 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert data == []
326 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
327 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
328 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ── call_tool — graph_stats ───────────────────────────────────────────────────
329 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
330 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestCallToolGraphStats:
331 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def setup_method(self):
332 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx = _ServerFixture()
333 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
334 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
335 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_returns_node_and_edge_counts(self):
336 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx.store.node_count.return_value = 42
337 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx.store.edge_count.return_value = 17
338 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = await self.fx.call_tool_fn("graph_stats", {})
339 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ data = json.loads(result[0]["text"])
340 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert data["nodes"] == 42
341 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert data["edges"] == 17
342 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
343 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
344 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ # ── call_tool — unknown tool ──────────────────────────────────────────────────
345 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
346 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ class TestCallToolUnknown:
347 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ def setup_method(self):
348 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ self.fx = _ServerFixture()
349 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+
350 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ @pytest.mark.asyncio
351 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ async def test_returns_unknown_tool_message(self):
352 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ result = await self.fx.call_tool_fn("nonexistent_tool", {})
353 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "Unknown tool" in result[0]["text"]
354 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!
+ assert "nonexistent_tool" in result[0]["text"]
125 355 { copied = false; pop = false }, 1000)" :class="copied && 'copied'">Copy link Copied!