Navegador

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

Keyboard Shortcuts

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