Navegador

navegador / tests / test_sdk.py
Source Blame History 549 lines
0392cfc… lmata 1 """
0392cfc… lmata 2 Tests for the Navegador Python SDK (navegador/sdk.py).
0392cfc… lmata 3
0392cfc… lmata 4 All tests use a mock GraphStore so no real database is required.
0392cfc… lmata 5 """
0392cfc… lmata 6
0392cfc… lmata 7 from unittest.mock import MagicMock, patch
0392cfc… lmata 8
0392cfc… lmata 9 import pytest
0392cfc… lmata 10
0392cfc… lmata 11 from navegador.sdk import Navegador
0392cfc… lmata 12
0392cfc… lmata 13
0392cfc… lmata 14 # ── Helpers ───────────────────────────────────────────────────────────────────
0392cfc… lmata 15
0392cfc… lmata 16
0392cfc… lmata 17 def _mock_store(rows=None):
0392cfc… lmata 18 """Return a mock GraphStore whose .query() yields the given rows."""
0392cfc… lmata 19 store = MagicMock()
0392cfc… lmata 20 result = MagicMock()
0392cfc… lmata 21 result.result_set = rows or []
0392cfc… lmata 22 store.query.return_value = result
0392cfc… lmata 23 return store
0392cfc… lmata 24
0392cfc… lmata 25
0392cfc… lmata 26 def _nav(rows=None):
0392cfc… lmata 27 """Return a Navegador instance wired to a mock store."""
0392cfc… lmata 28 return Navegador(_mock_store(rows))
0392cfc… lmata 29
0392cfc… lmata 30
0392cfc… lmata 31 # ── Constructor tests ─────────────────────────────────────────────────────────
0392cfc… lmata 32
0392cfc… lmata 33
0392cfc… lmata 34 class TestConstructors:
0392cfc… lmata 35 def test_direct_init_stores_store(self):
0392cfc… lmata 36 store = _mock_store()
0392cfc… lmata 37 nav = Navegador(store)
0392cfc… lmata 38 assert nav._store is store
0392cfc… lmata 39
0392cfc… lmata 40 def test_sqlite_classmethod(self):
0392cfc… lmata 41 fake_store = _mock_store()
0392cfc… lmata 42 with patch("navegador.graph.store.GraphStore.sqlite", return_value=fake_store) as mock_sqlite:
0392cfc… lmata 43 nav = Navegador.sqlite("/tmp/test.db")
0392cfc… lmata 44 mock_sqlite.assert_called_once_with("/tmp/test.db")
0392cfc… lmata 45 assert nav._store is fake_store
0392cfc… lmata 46
0392cfc… lmata 47 def test_sqlite_default_path(self):
0392cfc… lmata 48 fake_store = _mock_store()
0392cfc… lmata 49 with patch("navegador.graph.store.GraphStore.sqlite", return_value=fake_store) as mock_sqlite:
0392cfc… lmata 50 Navegador.sqlite()
0392cfc… lmata 51 mock_sqlite.assert_called_once_with(".navegador/graph.db")
0392cfc… lmata 52
0392cfc… lmata 53 def test_redis_classmethod(self):
0392cfc… lmata 54 fake_store = _mock_store()
0392cfc… lmata 55 with patch("navegador.graph.store.GraphStore.redis", return_value=fake_store) as mock_redis:
0392cfc… lmata 56 nav = Navegador.redis("redis://myhost:6379")
0392cfc… lmata 57 mock_redis.assert_called_once_with("redis://myhost:6379")
0392cfc… lmata 58 assert nav._store is fake_store
0392cfc… lmata 59
0392cfc… lmata 60 def test_redis_default_url(self):
0392cfc… lmata 61 fake_store = _mock_store()
0392cfc… lmata 62 with patch("navegador.graph.store.GraphStore.redis", return_value=fake_store) as mock_redis:
0392cfc… lmata 63 Navegador.redis()
0392cfc… lmata 64 mock_redis.assert_called_once_with("redis://localhost:6379")
0392cfc… lmata 65
0392cfc… lmata 66
0392cfc… lmata 67 # ── Ingestion ─────────────────────────────────────────────────────────────────
0392cfc… lmata 68
0392cfc… lmata 69
0392cfc… lmata 70 class TestIngest:
0392cfc… lmata 71 def test_ingest_delegates_to_repo_ingester(self):
0392cfc… lmata 72 store = _mock_store()
0392cfc… lmata 73 nav = Navegador(store)
0392cfc… lmata 74 expected = {"files": 3, "functions": 10, "classes": 2, "edges": 5, "skipped": 0}
0392cfc… lmata 75
0392cfc… lmata 76 with patch("navegador.ingestion.RepoIngester") as MockIngester:
0392cfc… lmata 77 mock_instance = MockIngester.return_value
0392cfc… lmata 78 mock_instance.ingest.return_value = expected
0392cfc… lmata 79
0392cfc… lmata 80 result = nav.ingest("/some/repo")
0392cfc… lmata 81
0392cfc… lmata 82 MockIngester.assert_called_once_with(store)
0392cfc… lmata 83 mock_instance.ingest.assert_called_once_with(
0392cfc… lmata 84 "/some/repo", clear=False, incremental=False
0392cfc… lmata 85 )
0392cfc… lmata 86 assert result == expected
0392cfc… lmata 87
0392cfc… lmata 88 def test_ingest_passes_clear_and_incremental(self):
0392cfc… lmata 89 store = _mock_store()
0392cfc… lmata 90 nav = Navegador(store)
0392cfc… lmata 91
0392cfc… lmata 92 with patch("navegador.ingestion.RepoIngester") as MockIngester:
0392cfc… lmata 93 mock_instance = MockIngester.return_value
0392cfc… lmata 94 mock_instance.ingest.return_value = {}
0392cfc… lmata 95
0392cfc… lmata 96 nav.ingest("/repo", clear=True, incremental=True)
0392cfc… lmata 97 mock_instance.ingest.assert_called_once_with(
0392cfc… lmata 98 "/repo", clear=True, incremental=True
0392cfc… lmata 99 )
0392cfc… lmata 100
0392cfc… lmata 101
0392cfc… lmata 102 # ── Context loading ───────────────────────────────────────────────────────────
0392cfc… lmata 103
0392cfc… lmata 104
0392cfc… lmata 105 class TestFileContext:
0392cfc… lmata 106 def test_returns_context_bundle(self):
0392cfc… lmata 107 from navegador.context.loader import ContextBundle, ContextNode
0392cfc… lmata 108
0392cfc… lmata 109 nav = _nav([])
0392cfc… lmata 110 bundle = nav.file_context("src/auth.py")
0392cfc… lmata 111 assert isinstance(bundle, ContextBundle)
0392cfc… lmata 112 assert bundle.target.type == "File"
0392cfc… lmata 113 assert bundle.target.name == "auth.py"
0392cfc… lmata 114
0392cfc… lmata 115 def test_passes_file_path(self):
0392cfc… lmata 116 store = _mock_store([])
0392cfc… lmata 117 nav = Navegador(store)
0392cfc… lmata 118 nav.file_context("src/auth.py")
0392cfc… lmata 119 # store.query must have been called with the file path param
0392cfc… lmata 120 call_args = store.query.call_args
0392cfc… lmata 121 assert call_args[0][1]["path"] == "src/auth.py"
0392cfc… lmata 122
0392cfc… lmata 123
0392cfc… lmata 124 class TestFunctionContext:
0392cfc… lmata 125 def test_returns_context_bundle(self):
0392cfc… lmata 126 from navegador.context.loader import ContextBundle
0392cfc… lmata 127
0392cfc… lmata 128 nav = _nav([])
0392cfc… lmata 129 bundle = nav.function_context("validate_token")
0392cfc… lmata 130 assert isinstance(bundle, ContextBundle)
0392cfc… lmata 131 assert bundle.target.name == "validate_token"
0392cfc… lmata 132 assert bundle.target.type == "Function"
0392cfc… lmata 133
0392cfc… lmata 134 def test_passes_file_path_and_depth(self):
0392cfc… lmata 135 store = _mock_store([])
0392cfc… lmata 136 nav = Navegador(store)
0392cfc… lmata 137
0392cfc… lmata 138 with patch("navegador.context.loader.ContextLoader.load_function") as mock_load:
0392cfc… lmata 139 from navegador.context.loader import ContextBundle, ContextNode
0392cfc… lmata 140 mock_load.return_value = ContextBundle(
0392cfc… lmata 141 target=ContextNode(type="Function", name="fn")
0392cfc… lmata 142 )
0392cfc… lmata 143 nav.function_context("fn", file_path="src/x.py", depth=3)
0392cfc… lmata 144 mock_load.assert_called_once_with("fn", file_path="src/x.py", depth=3)
0392cfc… lmata 145
0392cfc… lmata 146 def test_default_depth(self):
0392cfc… lmata 147 store = _mock_store([])
0392cfc… lmata 148 nav = Navegador(store)
0392cfc… lmata 149
0392cfc… lmata 150 with patch("navegador.context.loader.ContextLoader.load_function") as mock_load:
0392cfc… lmata 151 from navegador.context.loader import ContextBundle, ContextNode
0392cfc… lmata 152 mock_load.return_value = ContextBundle(
0392cfc… lmata 153 target=ContextNode(type="Function", name="fn")
0392cfc… lmata 154 )
0392cfc… lmata 155 nav.function_context("fn")
0392cfc… lmata 156 mock_load.assert_called_once_with("fn", file_path="", depth=2)
0392cfc… lmata 157
0392cfc… lmata 158
0392cfc… lmata 159 class TestClassContext:
0392cfc… lmata 160 def test_returns_context_bundle(self):
0392cfc… lmata 161 from navegador.context.loader import ContextBundle
0392cfc… lmata 162
0392cfc… lmata 163 nav = _nav([])
0392cfc… lmata 164 bundle = nav.class_context("AuthService")
0392cfc… lmata 165 assert isinstance(bundle, ContextBundle)
0392cfc… lmata 166 assert bundle.target.name == "AuthService"
0392cfc… lmata 167 assert bundle.target.type == "Class"
0392cfc… lmata 168
0392cfc… lmata 169 def test_passes_file_path(self):
0392cfc… lmata 170 store = _mock_store([])
0392cfc… lmata 171 nav = Navegador(store)
0392cfc… lmata 172
0392cfc… lmata 173 with patch("navegador.context.loader.ContextLoader.load_class") as mock_load:
0392cfc… lmata 174 from navegador.context.loader import ContextBundle, ContextNode
0392cfc… lmata 175 mock_load.return_value = ContextBundle(
0392cfc… lmata 176 target=ContextNode(type="Class", name="AuthService")
0392cfc… lmata 177 )
0392cfc… lmata 178 nav.class_context("AuthService", file_path="src/auth.py")
0392cfc… lmata 179 mock_load.assert_called_once_with("AuthService", file_path="src/auth.py")
0392cfc… lmata 180
0392cfc… lmata 181
0392cfc… lmata 182 class TestExplain:
0392cfc… lmata 183 def test_returns_context_bundle(self):
0392cfc… lmata 184 from navegador.context.loader import ContextBundle
0392cfc… lmata 185
0392cfc… lmata 186 nav = _nav([])
0392cfc… lmata 187 bundle = nav.explain("validate_token")
0392cfc… lmata 188 assert isinstance(bundle, ContextBundle)
0392cfc… lmata 189 assert bundle.metadata["query"] == "explain"
0392cfc… lmata 190
0392cfc… lmata 191 def test_passes_file_path(self):
0392cfc… lmata 192 store = _mock_store([])
0392cfc… lmata 193 nav = Navegador(store)
0392cfc… lmata 194
0392cfc… lmata 195 with patch("navegador.context.loader.ContextLoader.explain") as mock_explain:
0392cfc… lmata 196 from navegador.context.loader import ContextBundle, ContextNode
0392cfc… lmata 197 mock_explain.return_value = ContextBundle(
0392cfc… lmata 198 target=ContextNode(type="Node", name="fn")
0392cfc… lmata 199 )
0392cfc… lmata 200 nav.explain("fn", file_path="src/x.py")
0392cfc… lmata 201 mock_explain.assert_called_once_with("fn", file_path="src/x.py")
0392cfc… lmata 202
0392cfc… lmata 203
0392cfc… lmata 204 # ── Knowledge ─────────────────────────────────────────────────────────────────
0392cfc… lmata 205
0392cfc… lmata 206
0392cfc… lmata 207 class TestAddConcept:
0392cfc… lmata 208 def test_delegates_to_knowledge_ingester(self):
0392cfc… lmata 209 store = _mock_store()
0392cfc… lmata 210 nav = Navegador(store)
0392cfc… lmata 211
0392cfc… lmata 212 with patch("navegador.ingestion.KnowledgeIngester") as MockK:
0392cfc… lmata 213 mock_k = MockK.return_value
0392cfc… lmata 214 nav.add_concept("JWT", description="Stateless token", domain="auth")
0392cfc… lmata 215 MockK.assert_called_once_with(store)
0392cfc… lmata 216 mock_k.add_concept.assert_called_once_with(
0392cfc… lmata 217 "JWT", description="Stateless token", domain="auth"
0392cfc… lmata 218 )
0392cfc… lmata 219
0392cfc… lmata 220
0392cfc… lmata 221 class TestAddRule:
0392cfc… lmata 222 def test_delegates_to_knowledge_ingester(self):
0392cfc… lmata 223 store = _mock_store()
0392cfc… lmata 224 nav = Navegador(store)
0392cfc… lmata 225
0392cfc… lmata 226 with patch("navegador.ingestion.KnowledgeIngester") as MockK:
0392cfc… lmata 227 mock_k = MockK.return_value
0392cfc… lmata 228 nav.add_rule("tokens must expire", severity="critical")
0392cfc… lmata 229 mock_k.add_rule.assert_called_once_with(
0392cfc… lmata 230 "tokens must expire", severity="critical"
0392cfc… lmata 231 )
0392cfc… lmata 232
0392cfc… lmata 233
0392cfc… lmata 234 class TestAddDecision:
0392cfc… lmata 235 def test_delegates_to_knowledge_ingester(self):
0392cfc… lmata 236 store = _mock_store()
0392cfc… lmata 237 nav = Navegador(store)
0392cfc… lmata 238
0392cfc… lmata 239 with patch("navegador.ingestion.KnowledgeIngester") as MockK:
0392cfc… lmata 240 mock_k = MockK.return_value
0392cfc… lmata 241 nav.add_decision("Use FalkorDB", rationale="Cypher + SQLite", status="accepted")
0392cfc… lmata 242 mock_k.add_decision.assert_called_once_with(
0392cfc… lmata 243 "Use FalkorDB", rationale="Cypher + SQLite", status="accepted"
0392cfc… lmata 244 )
0392cfc… lmata 245
0392cfc… lmata 246
0392cfc… lmata 247 class TestAddPerson:
0392cfc… lmata 248 def test_delegates_to_knowledge_ingester(self):
0392cfc… lmata 249 store = _mock_store()
0392cfc… lmata 250 nav = Navegador(store)
0392cfc… lmata 251
0392cfc… lmata 252 with patch("navegador.ingestion.KnowledgeIngester") as MockK:
0392cfc… lmata 253 mock_k = MockK.return_value
0392cfc… lmata 254 nav.add_person("Alice", email="[email protected]", role="lead")
0392cfc… lmata 255 mock_k.add_person.assert_called_once_with(
0392cfc… lmata 256 "Alice", email="[email protected]", role="lead"
0392cfc… lmata 257 )
0392cfc… lmata 258
0392cfc… lmata 259
0392cfc… lmata 260 class TestAddDomain:
0392cfc… lmata 261 def test_delegates_to_knowledge_ingester(self):
0392cfc… lmata 262 store = _mock_store()
0392cfc… lmata 263 nav = Navegador(store)
0392cfc… lmata 264
0392cfc… lmata 265 with patch("navegador.ingestion.KnowledgeIngester") as MockK:
0392cfc… lmata 266 mock_k = MockK.return_value
0392cfc… lmata 267 nav.add_domain("auth", description="Authentication layer")
0392cfc… lmata 268 mock_k.add_domain.assert_called_once_with(
0392cfc… lmata 269 "auth", description="Authentication layer"
0392cfc… lmata 270 )
0392cfc… lmata 271
0392cfc… lmata 272
0392cfc… lmata 273 class TestAnnotate:
0392cfc… lmata 274 def test_delegates_to_knowledge_ingester(self):
0392cfc… lmata 275 store = _mock_store()
0392cfc… lmata 276 nav = Navegador(store)
0392cfc… lmata 277
0392cfc… lmata 278 with patch("navegador.ingestion.KnowledgeIngester") as MockK:
0392cfc… lmata 279 mock_k = MockK.return_value
0392cfc… lmata 280 nav.annotate("validate_token", "Function", concept="JWT")
0392cfc… lmata 281 mock_k.annotate_code.assert_called_once_with(
0392cfc… lmata 282 "validate_token", "Function", concept="JWT", rule=None
0392cfc… lmata 283 )
0392cfc… lmata 284
0392cfc… lmata 285 def test_passes_rule(self):
0392cfc… lmata 286 store = _mock_store()
0392cfc… lmata 287 nav = Navegador(store)
0392cfc… lmata 288
0392cfc… lmata 289 with patch("navegador.ingestion.KnowledgeIngester") as MockK:
0392cfc… lmata 290 mock_k = MockK.return_value
0392cfc… lmata 291 nav.annotate("validate_token", "Function", rule="tokens must expire")
0392cfc… lmata 292 mock_k.annotate_code.assert_called_once_with(
0392cfc… lmata 293 "validate_token", "Function", concept=None, rule="tokens must expire"
0392cfc… lmata 294 )
0392cfc… lmata 295
0392cfc… lmata 296
0392cfc… lmata 297 class TestConceptLoad:
0392cfc… lmata 298 def test_delegates_to_context_loader(self):
0392cfc… lmata 299 rows = [["JWT", "Stateless token auth", "active", "auth", [], [], [], []]]
0392cfc… lmata 300 nav = _nav(rows)
0392cfc… lmata 301 bundle = nav.concept("JWT")
0392cfc… lmata 302 assert bundle.target.name == "JWT"
0392cfc… lmata 303 assert bundle.target.type == "Concept"
0392cfc… lmata 304
0392cfc… lmata 305 def test_not_found_returns_bundle_with_found_false(self):
0392cfc… lmata 306 nav = _nav([])
0392cfc… lmata 307 bundle = nav.concept("NonExistent")
0392cfc… lmata 308 assert bundle.metadata.get("found") is False
0392cfc… lmata 309
0392cfc… lmata 310
0392cfc… lmata 311 class TestDomainLoad:
0392cfc… lmata 312 def test_delegates_to_context_loader(self):
0392cfc… lmata 313 rows = [["Function", "login", "src/auth.py", "Log in"]]
0392cfc… lmata 314 nav = _nav(rows)
0392cfc… lmata 315 bundle = nav.domain("auth")
0392cfc… lmata 316 assert bundle.target.name == "auth"
0392cfc… lmata 317 assert bundle.target.type == "Domain"
0392cfc… lmata 318
0392cfc… lmata 319
0392cfc… lmata 320 class TestDecisionLoad:
0392cfc… lmata 321 def test_delegates_to_context_loader(self):
0392cfc… lmata 322 rows = [[
0392cfc… lmata 323 "Use FalkorDB",
0392cfc… lmata 324 "Graph DB",
0392cfc… lmata 325 "Cypher queries",
0392cfc… lmata 326 "Neo4j",
0392cfc… lmata 327 "accepted",
0392cfc… lmata 328 "2026-01-01",
0392cfc… lmata 329 "infrastructure",
0392cfc… lmata 330 [],
0392cfc… lmata 331 [],
0392cfc… lmata 332 ]]
0392cfc… lmata 333 nav = _nav(rows)
0392cfc… lmata 334 bundle = nav.decision("Use FalkorDB")
0392cfc… lmata 335 assert bundle.target.name == "Use FalkorDB"
0392cfc… lmata 336 assert bundle.target.type == "Decision"
0392cfc… lmata 337 assert bundle.target.rationale == "Cypher queries"
0392cfc… lmata 338
0392cfc… lmata 339 def test_not_found(self):
0392cfc… lmata 340 nav = _nav([])
0392cfc… lmata 341 bundle = nav.decision("Unknown")
0392cfc… lmata 342 assert bundle.metadata.get("found") is False
0392cfc… lmata 343
0392cfc… lmata 344
0392cfc… lmata 345 # ── Search ────────────────────────────────────────────────────────────────────
0392cfc… lmata 346
0392cfc… lmata 347
0392cfc… lmata 348 class TestSearch:
0392cfc… lmata 349 def test_search_returns_nodes(self):
0392cfc… lmata 350 from navegador.context.loader import ContextNode
0392cfc… lmata 351
0392cfc… lmata 352 rows = [["Function", "validate_token", "src/auth.py", 10, "Validate a token"]]
0392cfc… lmata 353 nav = _nav(rows)
0392cfc… lmata 354 results = nav.search("validate")
0392cfc… lmata 355 assert len(results) == 1
0392cfc… lmata 356 assert isinstance(results[0], ContextNode)
0392cfc… lmata 357 assert results[0].name == "validate_token"
0392cfc… lmata 358
0392cfc… lmata 359 def test_search_empty(self):
0392cfc… lmata 360 nav = _nav([])
0392cfc… lmata 361 assert nav.search("xyz") == []
0392cfc… lmata 362
0392cfc… lmata 363 def test_search_passes_limit(self):
0392cfc… lmata 364 store = _mock_store([])
0392cfc… lmata 365 nav = Navegador(store)
0392cfc… lmata 366
0392cfc… lmata 367 with patch("navegador.context.loader.ContextLoader.search") as mock_search:
0392cfc… lmata 368 mock_search.return_value = []
0392cfc… lmata 369 nav.search("auth", limit=5)
0392cfc… lmata 370 mock_search.assert_called_once_with("auth", limit=5)
0392cfc… lmata 371
0392cfc… lmata 372
0392cfc… lmata 373 class TestSearchAll:
0392cfc… lmata 374 def test_search_all_returns_nodes(self):
0392cfc… lmata 375 from navegador.context.loader import ContextNode
0392cfc… lmata 376
0392cfc… lmata 377 rows = [["Concept", "JWT", "", None, "Stateless token auth"]]
0392cfc… lmata 378 nav = _nav(rows)
0392cfc… lmata 379 results = nav.search_all("JWT")
0392cfc… lmata 380 assert len(results) == 1
0392cfc… lmata 381 assert results[0].type == "Concept"
0392cfc… lmata 382
0392cfc… lmata 383 def test_search_all_passes_limit(self):
0392cfc… lmata 384 store = _mock_store([])
0392cfc… lmata 385 nav = Navegador(store)
0392cfc… lmata 386
0392cfc… lmata 387 with patch("navegador.context.loader.ContextLoader.search_all") as mock_sa:
0392cfc… lmata 388 mock_sa.return_value = []
0392cfc… lmata 389 nav.search_all("auth", limit=10)
0392cfc… lmata 390 mock_sa.assert_called_once_with("auth", limit=10)
0392cfc… lmata 391
0392cfc… lmata 392
0392cfc… lmata 393 class TestSearchKnowledge:
0392cfc… lmata 394 def test_search_knowledge_returns_nodes(self):
0392cfc… lmata 395 from navegador.context.loader import ContextNode
0392cfc… lmata 396
0392cfc… lmata 397 rows = [["Concept", "JWT", "Stateless token auth", "auth", "active"]]
0392cfc… lmata 398 nav = _nav(rows)
0392cfc… lmata 399 results = nav.search_knowledge("JWT")
0392cfc… lmata 400 assert len(results) == 1
0392cfc… lmata 401 assert results[0].domain == "auth"
0392cfc… lmata 402
0392cfc… lmata 403 def test_search_knowledge_empty(self):
0392cfc… lmata 404 nav = _nav([])
0392cfc… lmata 405 assert nav.search_knowledge("missing") == []
0392cfc… lmata 406
0392cfc… lmata 407 def test_search_knowledge_passes_limit(self):
0392cfc… lmata 408 store = _mock_store([])
0392cfc… lmata 409 nav = Navegador(store)
0392cfc… lmata 410
0392cfc… lmata 411 with patch("navegador.context.loader.ContextLoader.search_knowledge") as mock_sk:
0392cfc… lmata 412 mock_sk.return_value = []
0392cfc… lmata 413 nav.search_knowledge("auth", limit=3)
0392cfc… lmata 414 mock_sk.assert_called_once_with("auth", limit=3)
0392cfc… lmata 415
0392cfc… lmata 416
0392cfc… lmata 417 # ── Graph ─────────────────────────────────────────────────────────────────────
0392cfc… lmata 418
0392cfc… lmata 419
0392cfc… lmata 420 class TestQuery:
0392cfc… lmata 421 def test_delegates_to_store(self):
0392cfc… lmata 422 store = _mock_store([[42]])
0392cfc… lmata 423 nav = Navegador(store)
0392cfc… lmata 424 result = nav.query("MATCH (n) RETURN count(n)")
0392cfc… lmata 425 store.query.assert_called_once_with("MATCH (n) RETURN count(n)", None)
0392cfc… lmata 426 assert result.result_set == [[42]]
0392cfc… lmata 427
0392cfc… lmata 428 def test_passes_params(self):
0392cfc… lmata 429 store = _mock_store([])
0392cfc… lmata 430 nav = Navegador(store)
0392cfc… lmata 431 nav.query("MATCH (n:Function {name: $name}) RETURN n", {"name": "foo"})
0392cfc… lmata 432 store.query.assert_called_once_with(
0392cfc… lmata 433 "MATCH (n:Function {name: $name}) RETURN n", {"name": "foo"}
0392cfc… lmata 434 )
0392cfc… lmata 435
0392cfc… lmata 436
0392cfc… lmata 437 class TestStats:
0392cfc… lmata 438 def test_returns_dict_with_expected_keys(self):
0392cfc… lmata 439 node_result = MagicMock()
0392cfc… lmata 440 node_result.result_set = [["Function", 5], ["Class", 2]]
0392cfc… lmata 441 edge_result = MagicMock()
0392cfc… lmata 442 edge_result.result_set = [["CALLS", 8], ["INHERITS", 1]]
0392cfc… lmata 443
0392cfc… lmata 444 store = MagicMock()
0392cfc… lmata 445 store.query.side_effect = [node_result, edge_result]
0392cfc… lmata 446
0392cfc… lmata 447 nav = Navegador(store)
0392cfc… lmata 448 s = nav.stats()
0392cfc… lmata 449
0392cfc… lmata 450 assert s["total_nodes"] == 7
0392cfc… lmata 451 assert s["total_edges"] == 9
0392cfc… lmata 452 assert s["nodes"]["Function"] == 5
0392cfc… lmata 453 assert s["nodes"]["Class"] == 2
0392cfc… lmata 454 assert s["edges"]["CALLS"] == 8
0392cfc… lmata 455 assert s["edges"]["INHERITS"] == 1
0392cfc… lmata 456
0392cfc… lmata 457 def test_empty_graph(self):
0392cfc… lmata 458 store = _mock_store([])
0392cfc… lmata 459 nav = Navegador(store)
0392cfc… lmata 460 s = nav.stats()
0392cfc… lmata 461 assert s["total_nodes"] == 0
0392cfc… lmata 462 assert s["total_edges"] == 0
0392cfc… lmata 463 assert s["nodes"] == {}
0392cfc… lmata 464 assert s["edges"] == {}
0392cfc… lmata 465
0392cfc… lmata 466
0392cfc… lmata 467 class TestExport:
0392cfc… lmata 468 def test_delegates_to_export_graph(self):
0392cfc… lmata 469 store = _mock_store()
0392cfc… lmata 470 nav = Navegador(store)
0392cfc… lmata 471 expected = {"nodes": 10, "edges": 5}
0392cfc… lmata 472
0392cfc… lmata 473 with patch("navegador.graph.export.export_graph", return_value=expected) as mock_export:
0392cfc… lmata 474 result = nav.export("/tmp/out.jsonl")
0392cfc… lmata 475 mock_export.assert_called_once_with(store, "/tmp/out.jsonl")
0392cfc… lmata 476 assert result == expected
0392cfc… lmata 477
0392cfc… lmata 478
0392cfc… lmata 479 class TestImportGraph:
0392cfc… lmata 480 def test_delegates_to_import_graph(self):
0392cfc… lmata 481 store = _mock_store()
0392cfc… lmata 482 nav = Navegador(store)
0392cfc… lmata 483 expected = {"nodes": 10, "edges": 5}
0392cfc… lmata 484
0392cfc… lmata 485 with patch("navegador.graph.export.import_graph", return_value=expected) as mock_import:
0392cfc… lmata 486 result = nav.import_graph("/tmp/in.jsonl")
0392cfc… lmata 487 mock_import.assert_called_once_with(store, "/tmp/in.jsonl", clear=True)
0392cfc… lmata 488 assert result == expected
0392cfc… lmata 489
0392cfc… lmata 490 def test_passes_clear_false(self):
0392cfc… lmata 491 store = _mock_store()
0392cfc… lmata 492 nav = Navegador(store)
0392cfc… lmata 493
0392cfc… lmata 494 with patch("navegador.graph.export.import_graph", return_value={}) as mock_import:
0392cfc… lmata 495 nav.import_graph("/tmp/in.jsonl", clear=False)
0392cfc… lmata 496 mock_import.assert_called_once_with(store, "/tmp/in.jsonl", clear=False)
0392cfc… lmata 497
0392cfc… lmata 498
0392cfc… lmata 499 class TestClear:
0392cfc… lmata 500 def test_delegates_to_store(self):
0392cfc… lmata 501 store = _mock_store()
0392cfc… lmata 502 nav = Navegador(store)
0392cfc… lmata 503 nav.clear()
0392cfc… lmata 504 store.clear.assert_called_once()
0392cfc… lmata 505
0392cfc… lmata 506
0392cfc… lmata 507 # ── Owners ────────────────────────────────────────────────────────────────────
0392cfc… lmata 508
0392cfc… lmata 509
0392cfc… lmata 510 class TestFindOwners:
0392cfc… lmata 511 def test_returns_person_nodes(self):
0392cfc… lmata 512 from navegador.context.loader import ContextNode
0392cfc… lmata 513
0392cfc… lmata 514 rows = [["Class", "AuthService", "Alice", "[email protected]", "lead", "auth"]]
0392cfc… lmata 515 nav = _nav(rows)
0392cfc… lmata 516 results = nav.find_owners("AuthService")
0392cfc… lmata 517 assert len(results) == 1
0392cfc… lmata 518 assert isinstance(results[0], ContextNode)
0392cfc… lmata 519 assert results[0].type == "Person"
0392cfc… lmata 520 assert results[0].name == "Alice"
0392cfc… lmata 521
0392cfc… lmata 522 def test_empty(self):
0392cfc… lmata 523 nav = _nav([])
0392cfc… lmata 524 assert nav.find_owners("nobody") == []
0392cfc… lmata 525
0392cfc… lmata 526 def test_passes_file_path(self):
0392cfc… lmata 527 store = _mock_store([])
0392cfc… lmata 528 nav = Navegador(store)
0392cfc… lmata 529
0392cfc… lmata 530 with patch("navegador.context.loader.ContextLoader.find_owners") as mock_fo:
0392cfc… lmata 531 mock_fo.return_value = []
0392cfc… lmata 532 nav.find_owners("AuthService", file_path="src/auth.py")
0392cfc… lmata 533 mock_fo.assert_called_once_with("AuthService", file_path="src/auth.py")
0392cfc… lmata 534
0392cfc… lmata 535
0392cfc… lmata 536 # ── Top-level import ──────────────────────────────────────────────────────────
0392cfc… lmata 537
0392cfc… lmata 538
0392cfc… lmata 539 class TestTopLevelImport:
0392cfc… lmata 540 def test_navegador_exported_from_package(self):
0392cfc… lmata 541 import navegador
0392cfc… lmata 542
0392cfc… lmata 543 assert hasattr(navegador, "Navegador")
0392cfc… lmata 544 assert navegador.Navegador is Navegador
0392cfc… lmata 545
0392cfc… lmata 546 def test_navegador_in_all(self):
0392cfc… lmata 547 import navegador
0392cfc… lmata 548
0392cfc… lmata 549 assert "Navegador" in navegador.__all__

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button