Navegador

navegador / tests / test_enrichment_express.py
Source Blame History 233 lines
96b97a1… lmata 1 """Tests for navegador.enrichment.express — ExpressEnricher."""
96b97a1… lmata 2
96b97a1… lmata 3 from unittest.mock import MagicMock
96b97a1… lmata 4
96b97a1… lmata 5 import pytest
96b97a1… lmata 6
96b97a1… lmata 7 from navegador.enrichment import EnrichmentResult
96b97a1… lmata 8 from navegador.enrichment.express import ExpressEnricher
96b97a1… lmata 9 from navegador.graph.store import GraphStore
96b97a1… lmata 10
96b97a1… lmata 11
96b97a1… lmata 12 # ── Helpers ───────────────────────────────────────────────────────────────────
96b97a1… lmata 13
96b97a1… lmata 14
96b97a1… lmata 15 def _mock_store(result_set=None):
96b97a1… lmata 16 client = MagicMock()
96b97a1… lmata 17 graph = MagicMock()
96b97a1… lmata 18 graph.query.return_value = MagicMock(result_set=result_set)
96b97a1… lmata 19 client.select_graph.return_value = graph
96b97a1… lmata 20 return GraphStore(client)
96b97a1… lmata 21
96b97a1… lmata 22
96b97a1… lmata 23 def _mock_store_with_responses(responses):
96b97a1… lmata 24 """Return a GraphStore whose graph.query returns the given result sets in order.
96b97a1… lmata 25
96b97a1… lmata 26 Any calls beyond the provided list (e.g. _promote_node SET queries) receive
96b97a1… lmata 27 a MagicMock with result_set=None, which is harmless.
96b97a1… lmata 28 """
96b97a1… lmata 29 client = MagicMock()
96b97a1… lmata 30 graph = MagicMock()
96b97a1… lmata 31 response_iter = iter(responses)
96b97a1… lmata 32
96b97a1… lmata 33 def _side_effect(cypher, params):
96b97a1… lmata 34 try:
96b97a1… lmata 35 rs = next(response_iter)
96b97a1… lmata 36 except StopIteration:
96b97a1… lmata 37 rs = None
96b97a1… lmata 38 return MagicMock(result_set=rs)
96b97a1… lmata 39
96b97a1… lmata 40 graph.query.side_effect = _side_effect
96b97a1… lmata 41 client.select_graph.return_value = graph
96b97a1… lmata 42 return GraphStore(client)
96b97a1… lmata 43
96b97a1… lmata 44
96b97a1… lmata 45 # ── framework_name ────────────────────────────────────────────────────────────
96b97a1… lmata 46
96b97a1… lmata 47
96b97a1… lmata 48 class TestFrameworkName:
96b97a1… lmata 49 def test_framework_name_is_express(self):
96b97a1… lmata 50 enricher = ExpressEnricher(_mock_store())
96b97a1… lmata 51 assert enricher.framework_name == "express"
96b97a1… lmata 52
96b97a1… lmata 53
96b97a1… lmata 54 # ── detection_patterns ────────────────────────────────────────────────────────
96b97a1… lmata 55
96b97a1… lmata 56
96b97a1… lmata 57 class TestDetectionPatterns:
96b97a1… lmata 58 def test_contains_express_lowercase(self):
96b97a1… lmata 59 enricher = ExpressEnricher(_mock_store())
96b97a1… lmata 60 assert "express" in enricher.detection_patterns
96b97a1… lmata 61
96b97a1… lmata 62 def test_returns_list(self):
96b97a1… lmata 63 enricher = ExpressEnricher(_mock_store())
96b97a1… lmata 64 assert isinstance(enricher.detection_patterns, list)
2c266d2… lmata 65
2c266d2… lmata 66 def test_is_nonempty(self):
2c266d2… lmata 67 enricher = ExpressEnricher(_mock_store())
2c266d2… lmata 68 assert len(enricher.detection_patterns) >= 1
96b97a1… lmata 69
96b97a1… lmata 70
96b97a1… lmata 71 # ── detect() ─────────────────────────────────────────────────────────────────
96b97a1… lmata 72
96b97a1… lmata 73
96b97a1… lmata 74 class TestDetect:
96b97a1… lmata 75 def test_returns_true_when_pattern_found(self):
96b97a1… lmata 76 store = _mock_store(result_set=[[1]])
96b97a1… lmata 77 enricher = ExpressEnricher(store)
96b97a1… lmata 78 assert enricher.detect() is True
96b97a1… lmata 79
96b97a1… lmata 80 def test_returns_false_when_no_match(self):
96b97a1… lmata 81 store = _mock_store(result_set=[[0]])
96b97a1… lmata 82 enricher = ExpressEnricher(store)
96b97a1… lmata 83 assert enricher.detect() is False
96b97a1… lmata 84
96b97a1… lmata 85 def test_returns_false_on_empty_result_set(self):
96b97a1… lmata 86 store = _mock_store(result_set=[])
96b97a1… lmata 87 enricher = ExpressEnricher(store)
96b97a1… lmata 88 assert enricher.detect() is False
96b97a1… lmata 89
96b97a1… lmata 90 def test_short_circuits_on_first_match(self):
96b97a1… lmata 91 store = _mock_store(result_set=[[2]])
96b97a1… lmata 92 enricher = ExpressEnricher(store)
96b97a1… lmata 93 assert enricher.detect() is True
96b97a1… lmata 94 assert store._graph.query.call_count == 1
96b97a1… lmata 95
96b97a1… lmata 96
96b97a1… lmata 97 # ── enrich() ─────────────────────────────────────────────────────────────────
96b97a1… lmata 98
96b97a1… lmata 99
96b97a1… lmata 100 class TestEnrich:
96b97a1… lmata 101 def _empty_enricher(self):
96b97a1… lmata 102 # 4 pattern queries: routes, middleware, controllers, routers
96b97a1… lmata 103 store = _mock_store_with_responses([[], [], [], []])
96b97a1… lmata 104 return ExpressEnricher(store)
96b97a1… lmata 105
96b97a1… lmata 106 def test_returns_enrichment_result(self):
96b97a1… lmata 107 assert isinstance(self._empty_enricher().enrich(), EnrichmentResult)
96b97a1… lmata 108
96b97a1… lmata 109 def test_zero_promoted_when_no_matches(self):
96b97a1… lmata 110 result = self._empty_enricher().enrich()
96b97a1… lmata 111 assert result.promoted == 0
96b97a1… lmata 112
96b97a1… lmata 113 def test_patterns_found_keys_present(self):
96b97a1… lmata 114 result = self._empty_enricher().enrich()
96b97a1… lmata 115 assert "routes" in result.patterns_found
96b97a1… lmata 116 assert "middleware" in result.patterns_found
96b97a1… lmata 117 assert "controllers" in result.patterns_found
96b97a1… lmata 118 assert "routers" in result.patterns_found
96b97a1… lmata 119
96b97a1… lmata 120 def test_promotes_route_nodes(self):
96b97a1… lmata 121 """app.get / app.post etc. should be promoted to ExpressRoute."""
96b97a1… lmata 122 store = _mock_store_with_responses(
96b97a1… lmata 123 [
96b97a1… lmata 124 [["app.get/users", "src/routes/users.js"]], # routes
96b97a1… lmata 125 [], # middleware
96b97a1… lmata 126 [], # controllers
96b97a1… lmata 127 [], # routers
96b97a1… lmata 128 ]
96b97a1… lmata 129 )
96b97a1… lmata 130 enricher = ExpressEnricher(store)
96b97a1… lmata 131 result = enricher.enrich()
96b97a1… lmata 132 assert result.promoted == 1
96b97a1… lmata 133 assert result.patterns_found["routes"] == 1
96b97a1… lmata 134
96b97a1… lmata 135 calls = store._graph.query.call_args_list
96b97a1… lmata 136 promote_calls = [c for c in calls if "SET n.semantic_type" in c[0][0]]
96b97a1… lmata 137 assert len(promote_calls) == 1
96b97a1… lmata 138 assert promote_calls[0][0][1]["semantic_type"] == "ExpressRoute"
96b97a1… lmata 139
96b97a1… lmata 140 def test_promotes_middleware_nodes(self):
96b97a1… lmata 141 """app.use calls should be promoted to ExpressMiddleware."""
96b97a1… lmata 142 store = _mock_store_with_responses(
96b97a1… lmata 143 [
96b97a1… lmata 144 [], # routes
96b97a1… lmata 145 [["app.use/auth", "src/middleware/auth.js"]], # middleware
96b97a1… lmata 146 [], # controllers
96b97a1… lmata 147 [], # routers
96b97a1… lmata 148 ]
96b97a1… lmata 149 )
96b97a1… lmata 150 enricher = ExpressEnricher(store)
96b97a1… lmata 151 result = enricher.enrich()
96b97a1… lmata 152 assert result.promoted == 1
96b97a1… lmata 153 assert result.patterns_found["middleware"] == 1
96b97a1… lmata 154
96b97a1… lmata 155 calls = store._graph.query.call_args_list
96b97a1… lmata 156 promote_calls = [c for c in calls if "SET n.semantic_type" in c[0][0]]
96b97a1… lmata 157 assert promote_calls[0][0][1]["semantic_type"] == "ExpressMiddleware"
96b97a1… lmata 158
96b97a1… lmata 159 def test_promotes_controller_nodes(self):
96b97a1… lmata 160 """Nodes inside /controllers/ should become ExpressController."""
96b97a1… lmata 161 store = _mock_store_with_responses(
96b97a1… lmata 162 [
96b97a1… lmata 163 [], # routes
96b97a1… lmata 164 [], # middleware
96b97a1… lmata 165 [["UserController", "src/controllers/UserController.js"]], # controllers
96b97a1… lmata 166 [], # routers
96b97a1… lmata 167 ]
96b97a1… lmata 168 )
96b97a1… lmata 169 enricher = ExpressEnricher(store)
96b97a1… lmata 170 result = enricher.enrich()
96b97a1… lmata 171 assert result.promoted == 1
96b97a1… lmata 172 assert result.patterns_found["controllers"] == 1
96b97a1… lmata 173
96b97a1… lmata 174 calls = store._graph.query.call_args_list
96b97a1… lmata 175 promote_calls = [c for c in calls if "SET n.semantic_type" in c[0][0]]
96b97a1… lmata 176 assert promote_calls[0][0][1]["semantic_type"] == "ExpressController"
96b97a1… lmata 177
96b97a1… lmata 178 def test_promotes_router_nodes(self):
96b97a1… lmata 179 """Router() patterns should become ExpressRouter."""
96b97a1… lmata 180 store = _mock_store_with_responses(
96b97a1… lmata 181 [
96b97a1… lmata 182 [], # routes
96b97a1… lmata 183 [], # middleware
96b97a1… lmata 184 [], # controllers
96b97a1… lmata 185 [["Router", "src/routes/index.js"]], # routers
96b97a1… lmata 186 ]
96b97a1… lmata 187 )
96b97a1… lmata 188 enricher = ExpressEnricher(store)
96b97a1… lmata 189 result = enricher.enrich()
96b97a1… lmata 190 assert result.promoted == 1
96b97a1… lmata 191 assert result.patterns_found["routers"] == 1
96b97a1… lmata 192
96b97a1… lmata 193 calls = store._graph.query.call_args_list
96b97a1… lmata 194 promote_calls = [c for c in calls if "SET n.semantic_type" in c[0][0]]
96b97a1… lmata 195 assert promote_calls[0][0][1]["semantic_type"] == "ExpressRouter"
96b97a1… lmata 196
96b97a1… lmata 197 def test_promoted_accumulates_across_patterns(self):
96b97a1… lmata 198 # Each matched node triggers a _promote_node SET query after its pattern query.
96b97a1… lmata 199 store = _mock_store_with_responses(
96b97a1… lmata 200 [
96b97a1… lmata 201 [["app.get/a", "r.js"], ["app.post/b", "r.js"]], # routes query (2 rows)
96b97a1… lmata 202 None, # _promote_node for app.get/a
96b97a1… lmata 203 None, # _promote_node for app.post/b
96b97a1… lmata 204 [["app.use/logger", "m.js"]], # middleware query (1 row)
96b97a1… lmata 205 None, # _promote_node for app.use/logger
96b97a1… lmata 206 [["AuthCtrl", "controllers/auth.js"]], # controllers query (1 row)
96b97a1… lmata 207 None, # _promote_node for AuthCtrl
96b97a1… lmata 208 [], # routers query
96b97a1… lmata 209 ]
96b97a1… lmata 210 )
96b97a1… lmata 211 enricher = ExpressEnricher(store)
96b97a1… lmata 212 result = enricher.enrich()
96b97a1… lmata 213 assert result.promoted == 4
96b97a1… lmata 214 assert result.patterns_found["routes"] == 2
96b97a1… lmata 215 assert result.patterns_found["middleware"] == 1
96b97a1… lmata 216 assert result.patterns_found["controllers"] == 1
96b97a1… lmata 217 assert result.patterns_found["routers"] == 0
96b97a1… lmata 218
96b97a1… lmata 219 def test_promote_node_called_with_correct_name_and_file(self):
96b97a1… lmata 220 store = _mock_store_with_responses(
96b97a1… lmata 221 [
96b97a1… lmata 222 [["app.get/items", "src/routes/items.js"]],
96b97a1… lmata 223 [], [], [],
96b97a1… lmata 224 ]
96b97a1… lmata 225 )
96b97a1… lmata 226 enricher = ExpressEnricher(store)
96b97a1… lmata 227 enricher.enrich()
96b97a1… lmata 228
96b97a1… lmata 229 calls = store._graph.query.call_args_list
96b97a1… lmata 230 promote_calls = [c for c in calls if "SET n.semantic_type" in c[0][0]]
96b97a1… lmata 231 params = promote_calls[0][0][1]
96b97a1… lmata 232 assert params["name"] == "app.get/items"
96b97a1… lmata 233 assert params["file_path"] == "src/routes/items.js"

Keyboard Shortcuts

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