Navegador

navegador / tests / test_enrichment_spring.py
Blame History Raw 274 lines
1
"""Tests for navegador.enrichment.spring — SpringEnricher."""
2
3
from unittest.mock import MagicMock
4
5
import pytest
6
7
from navegador.enrichment.base import EnrichmentResult, FrameworkEnricher
8
from navegador.enrichment.spring import SpringEnricher
9
from navegador.graph.store import GraphStore
10
11
12
# ── Helpers ───────────────────────────────────────────────────────────────────
13
14
15
def _mock_store(result_set=None):
16
"""Return a GraphStore backed by a mock FalkorDB graph."""
17
client = MagicMock()
18
graph = MagicMock()
19
graph.query.return_value = MagicMock(result_set=result_set)
20
client.select_graph.return_value = graph
21
return GraphStore(client)
22
23
24
def _store_with_side_effect(side_effect):
25
"""Return a GraphStore whose graph.query uses a side_effect callable."""
26
client = MagicMock()
27
graph = MagicMock()
28
graph.query.side_effect = side_effect
29
client.select_graph.return_value = graph
30
return GraphStore(client)
31
32
33
# ── Identity / contract ───────────────────────────────────────────────────────
34
35
36
class TestSpringEnricherIdentity:
37
def test_framework_name(self):
38
store = _mock_store()
39
assert SpringEnricher(store).framework_name == "spring"
40
41
def test_is_framework_enricher_subclass(self):
42
assert issubclass(SpringEnricher, FrameworkEnricher)
43
44
def test_detection_patterns_contains_org_springframework(self):
45
store = _mock_store()
46
assert "org.springframework" in SpringEnricher(store).detection_patterns
47
48
def test_detection_files_contains_application_properties(self):
49
store = _mock_store()
50
assert "application.properties" in SpringEnricher(store).detection_files
51
52
def test_detection_files_contains_application_yml(self):
53
store = _mock_store()
54
assert "application.yml" in SpringEnricher(store).detection_files
55
56
def test_detection_patterns_has_one_entry(self):
57
store = _mock_store()
58
assert len(SpringEnricher(store).detection_patterns) == 1
59
60
61
# ── enrich() return type ──────────────────────────────────────────────────────
62
63
64
class TestSpringEnricherEnrichReturnType:
65
def test_returns_enrichment_result(self):
66
store = _mock_store(result_set=[])
67
result = SpringEnricher(store).enrich()
68
assert isinstance(result, EnrichmentResult)
69
70
def test_result_has_promoted_attribute(self):
71
store = _mock_store(result_set=[])
72
result = SpringEnricher(store).enrich()
73
assert hasattr(result, "promoted")
74
75
def test_result_has_edges_added_attribute(self):
76
store = _mock_store(result_set=[])
77
result = SpringEnricher(store).enrich()
78
assert hasattr(result, "edges_added")
79
80
def test_result_has_patterns_found_attribute(self):
81
store = _mock_store(result_set=[])
82
result = SpringEnricher(store).enrich()
83
assert hasattr(result, "patterns_found")
84
85
86
# ── enrich() with no matching nodes ──────────────────────────────────────────
87
88
89
class TestSpringEnricherNoMatches:
90
def test_promoted_is_zero_when_no_nodes(self):
91
store = _mock_store(result_set=[])
92
result = SpringEnricher(store).enrich()
93
assert result.promoted == 0
94
95
def test_all_pattern_counts_zero_when_no_nodes(self):
96
store = _mock_store(result_set=[])
97
result = SpringEnricher(store).enrich()
98
for key in ("controllers", "rest_controllers", "services", "repositories", "entities"):
99
assert result.patterns_found[key] == 0
100
101
def test_patterns_found_has_five_keys(self):
102
store = _mock_store(result_set=[])
103
result = SpringEnricher(store).enrich()
104
assert set(result.patterns_found.keys()) == {
105
"controllers", "rest_controllers", "services", "repositories", "entities"
106
}
107
108
109
# ── enrich() with matching nodes ─────────────────────────────────────────────
110
111
112
class TestSpringEnricherWithMatches:
113
def _make_store_for_annotation(self, target_annotation, rows):
114
"""Return a store that returns `rows` only when the annotation matches."""
115
116
def side_effect(cypher, params):
117
annotation = params.get("annotation", "")
118
if annotation == target_annotation:
119
return MagicMock(result_set=rows)
120
return MagicMock(result_set=[])
121
122
return _store_with_side_effect(side_effect)
123
124
def test_controller_promoted(self):
125
store = self._make_store_for_annotation(
126
"@Controller",
127
[["UserController", "src/main/java/com/example/UserController.java"]],
128
)
129
result = SpringEnricher(store).enrich()
130
assert result.patterns_found["controllers"] == 1
131
assert result.promoted >= 1
132
133
def test_rest_controller_promoted(self):
134
store = self._make_store_for_annotation(
135
"@RestController",
136
[["UserRestController", "src/main/java/com/example/UserRestController.java"]],
137
)
138
result = SpringEnricher(store).enrich()
139
assert result.patterns_found["rest_controllers"] == 1
140
assert result.promoted >= 1
141
142
def test_service_promoted(self):
143
store = self._make_store_for_annotation(
144
"@Service",
145
[["UserService", "src/main/java/com/example/UserService.java"]],
146
)
147
result = SpringEnricher(store).enrich()
148
assert result.patterns_found["services"] == 1
149
assert result.promoted >= 1
150
151
def test_repository_promoted(self):
152
store = self._make_store_for_annotation(
153
"@Repository",
154
[["UserRepository", "src/main/java/com/example/UserRepository.java"]],
155
)
156
result = SpringEnricher(store).enrich()
157
assert result.patterns_found["repositories"] == 1
158
assert result.promoted >= 1
159
160
def test_entity_promoted(self):
161
store = self._make_store_for_annotation(
162
"@Entity",
163
[["User", "src/main/java/com/example/User.java"]],
164
)
165
result = SpringEnricher(store).enrich()
166
assert result.patterns_found["entities"] == 1
167
assert result.promoted >= 1
168
169
def test_promoted_count_accumulates_across_types(self):
170
rows_map = {
171
"@Controller": [
172
["UserController", "src/main/java/UserController.java"],
173
],
174
"@RestController": [
175
["ApiController", "src/main/java/ApiController.java"],
176
["OrderController", "src/main/java/OrderController.java"],
177
],
178
"@Service": [],
179
"@Repository": [["UserRepository", "src/main/java/UserRepository.java"]],
180
"@Entity": [],
181
}
182
183
def side_effect(cypher, params):
184
annotation = params.get("annotation", "")
185
return MagicMock(result_set=rows_map.get(annotation, []))
186
187
store = _store_with_side_effect(side_effect)
188
result = SpringEnricher(store).enrich()
189
assert result.promoted == 4
190
assert result.patterns_found["controllers"] == 1
191
assert result.patterns_found["rest_controllers"] == 2
192
assert result.patterns_found["repositories"] == 1
193
194
def test_promote_node_called_with_spring_controller_type(self):
195
store = self._make_store_for_annotation(
196
"@Controller",
197
[["UserController", "src/main/java/UserController.java"]],
198
)
199
SpringEnricher(store).enrich()
200
calls = [str(c) for c in store._graph.query.call_args_list]
201
promote_calls = [c for c in calls if "semantic_type" in c and "SpringController" in c]
202
assert len(promote_calls) >= 1
203
204
def test_promote_node_called_with_spring_service_type(self):
205
store = self._make_store_for_annotation(
206
"@Service",
207
[["UserService", "src/main/java/UserService.java"]],
208
)
209
SpringEnricher(store).enrich()
210
calls = [str(c) for c in store._graph.query.call_args_list]
211
promote_calls = [c for c in calls if "semantic_type" in c and "SpringService" in c]
212
assert len(promote_calls) >= 1
213
214
def test_promote_node_called_with_spring_repository_type(self):
215
store = self._make_store_for_annotation(
216
"@Repository",
217
[["UserRepository", "src/main/java/UserRepository.java"]],
218
)
219
SpringEnricher(store).enrich()
220
calls = [str(c) for c in store._graph.query.call_args_list]
221
promote_calls = [c for c in calls if "semantic_type" in c and "SpringRepository" in c]
222
assert len(promote_calls) >= 1
223
224
def test_promote_node_called_with_spring_entity_type(self):
225
store = self._make_store_for_annotation(
226
"@Entity",
227
[["User", "src/main/java/User.java"]],
228
)
229
SpringEnricher(store).enrich()
230
calls = [str(c) for c in store._graph.query.call_args_list]
231
promote_calls = [c for c in calls if "semantic_type" in c and "SpringEntity" in c]
232
assert len(promote_calls) >= 1
233
234
def test_promote_node_called_with_spring_rest_controller_type(self):
235
store = self._make_store_for_annotation(
236
"@RestController",
237
[["ApiController", "src/main/java/ApiController.java"]],
238
)
239
SpringEnricher(store).enrich()
240
calls = [str(c) for c in store._graph.query.call_args_list]
241
promote_calls = [c for c in calls if "semantic_type" in c and "SpringRestController" in c]
242
assert len(promote_calls) >= 1
243
244
def test_query_uses_annotation_param_not_fragment(self):
245
"""Verify enrich() passes 'annotation' key, not 'fragment', to the store."""
246
captured = []
247
248
def side_effect(cypher, params):
249
captured.append(params)
250
return MagicMock(result_set=[])
251
252
store = _store_with_side_effect(side_effect)
253
SpringEnricher(store).enrich()
254
# All enrich queries (not _promote_node queries) should use 'annotation'
255
enrich_queries = [p for p in captured if "annotation" in p]
256
assert len(enrich_queries) == 5
257
258
259
# ── detect() integration ──────────────────────────────────────────────────────
260
261
262
class TestSpringEnricherDetect:
263
def test_detect_true_when_spring_boot_annotation_present(self):
264
store = _mock_store(result_set=[[1]])
265
assert SpringEnricher(store).detect() is True
266
267
def test_detect_false_when_no_patterns_match(self):
268
store = _mock_store(result_set=[[0]])
269
assert SpringEnricher(store).detect() is False
270
271
def test_detect_false_on_empty_result_set(self):
272
store = _mock_store(result_set=[])
273
assert SpringEnricher(store).detect() is False
274

Keyboard Shortcuts

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