Navegador

navegador / tests / test_enrichment_rails.py
Source Blame History 256 lines
93cfcc4… lmata 1 """Tests for navegador.enrichment.rails — RailsEnricher."""
93cfcc4… lmata 2
93cfcc4… lmata 3 from unittest.mock import MagicMock, call
93cfcc4… lmata 4
93cfcc4… lmata 5 import pytest
93cfcc4… lmata 6
93cfcc4… lmata 7 from navegador.enrichment.base import EnrichmentResult, FrameworkEnricher
93cfcc4… lmata 8 from navegador.enrichment.rails import RailsEnricher
93cfcc4… lmata 9 from navegador.graph.store import GraphStore
93cfcc4… lmata 10
93cfcc4… lmata 11
93cfcc4… lmata 12 # ── Helpers ───────────────────────────────────────────────────────────────────
93cfcc4… lmata 13
93cfcc4… lmata 14
93cfcc4… lmata 15 def _mock_store(result_set=None):
93cfcc4… lmata 16 """Return a GraphStore backed by a mock FalkorDB graph."""
93cfcc4… lmata 17 client = MagicMock()
93cfcc4… lmata 18 graph = MagicMock()
93cfcc4… lmata 19 graph.query.return_value = MagicMock(result_set=result_set)
93cfcc4… lmata 20 client.select_graph.return_value = graph
93cfcc4… lmata 21 return GraphStore(client)
93cfcc4… lmata 22
93cfcc4… lmata 23
93cfcc4… lmata 24 def _store_with_side_effect(side_effect):
93cfcc4… lmata 25 """Return a GraphStore whose graph.query uses a side_effect callable."""
93cfcc4… lmata 26 client = MagicMock()
93cfcc4… lmata 27 graph = MagicMock()
93cfcc4… lmata 28 graph.query.side_effect = side_effect
93cfcc4… lmata 29 client.select_graph.return_value = graph
93cfcc4… lmata 30 return GraphStore(client)
93cfcc4… lmata 31
93cfcc4… lmata 32
93cfcc4… lmata 33 # ── Identity / contract ───────────────────────────────────────────────────────
93cfcc4… lmata 34
93cfcc4… lmata 35
93cfcc4… lmata 36 class TestRailsEnricherIdentity:
93cfcc4… lmata 37 def test_framework_name(self):
93cfcc4… lmata 38 store = _mock_store()
93cfcc4… lmata 39 assert RailsEnricher(store).framework_name == "rails"
93cfcc4… lmata 40
93cfcc4… lmata 41 def test_is_framework_enricher_subclass(self):
93cfcc4… lmata 42 assert issubclass(RailsEnricher, FrameworkEnricher)
93cfcc4… lmata 43
2c266d2… lmata 44 def test_detection_patterns_contains_rails(self):
2c266d2… lmata 45 store = _mock_store()
2c266d2… lmata 46 assert "rails" in RailsEnricher(store).detection_patterns
93cfcc4… lmata 47
93cfcc4… lmata 48 def test_detection_patterns_contains_active_record(self):
93cfcc4… lmata 49 store = _mock_store()
2c266d2… lmata 50 assert "active_record" in RailsEnricher(store).detection_patterns
2c266d2… lmata 51
2c266d2… lmata 52 def test_detection_patterns_contains_action_controller(self):
2c266d2… lmata 53 store = _mock_store()
2c266d2… lmata 54 assert "action_controller" in RailsEnricher(store).detection_patterns
2c266d2… lmata 55
2c266d2… lmata 56 def test_detection_files_contains_gemfile(self):
2c266d2… lmata 57 store = _mock_store()
2c266d2… lmata 58 assert "Gemfile" in RailsEnricher(store).detection_files
93cfcc4… lmata 59
2c266d2… lmata 60 def test_detection_patterns_has_three_entries(self):
93cfcc4… lmata 61 store = _mock_store()
2c266d2… lmata 62 assert len(RailsEnricher(store).detection_patterns) == 3
93cfcc4… lmata 63
93cfcc4… lmata 64
93cfcc4… lmata 65 # ── enrich() return type ──────────────────────────────────────────────────────
93cfcc4… lmata 66
93cfcc4… lmata 67
93cfcc4… lmata 68 class TestRailsEnricherEnrichReturnType:
93cfcc4… lmata 69 def test_returns_enrichment_result(self):
93cfcc4… lmata 70 store = _mock_store(result_set=[])
93cfcc4… lmata 71 result = RailsEnricher(store).enrich()
93cfcc4… lmata 72 assert isinstance(result, EnrichmentResult)
93cfcc4… lmata 73
93cfcc4… lmata 74 def test_result_has_promoted_attribute(self):
93cfcc4… lmata 75 store = _mock_store(result_set=[])
93cfcc4… lmata 76 result = RailsEnricher(store).enrich()
93cfcc4… lmata 77 assert hasattr(result, "promoted")
93cfcc4… lmata 78
93cfcc4… lmata 79 def test_result_has_edges_added_attribute(self):
93cfcc4… lmata 80 store = _mock_store(result_set=[])
93cfcc4… lmata 81 result = RailsEnricher(store).enrich()
93cfcc4… lmata 82 assert hasattr(result, "edges_added")
93cfcc4… lmata 83
93cfcc4… lmata 84 def test_result_has_patterns_found_attribute(self):
93cfcc4… lmata 85 store = _mock_store(result_set=[])
93cfcc4… lmata 86 result = RailsEnricher(store).enrich()
93cfcc4… lmata 87 assert hasattr(result, "patterns_found")
93cfcc4… lmata 88
93cfcc4… lmata 89
93cfcc4… lmata 90 # ── enrich() with no matching nodes ──────────────────────────────────────────
93cfcc4… lmata 91
93cfcc4… lmata 92
93cfcc4… lmata 93 class TestRailsEnricherNoMatches:
93cfcc4… lmata 94 def test_promoted_is_zero_when_no_nodes(self):
93cfcc4… lmata 95 store = _mock_store(result_set=[])
93cfcc4… lmata 96 result = RailsEnricher(store).enrich()
93cfcc4… lmata 97 assert result.promoted == 0
93cfcc4… lmata 98
93cfcc4… lmata 99 def test_all_pattern_counts_zero_when_no_nodes(self):
93cfcc4… lmata 100 store = _mock_store(result_set=[])
93cfcc4… lmata 101 result = RailsEnricher(store).enrich()
93cfcc4… lmata 102 for key in ("controllers", "models", "routes", "jobs", "concerns"):
93cfcc4… lmata 103 assert result.patterns_found[key] == 0
93cfcc4… lmata 104
93cfcc4… lmata 105 def test_patterns_found_has_five_keys(self):
93cfcc4… lmata 106 store = _mock_store(result_set=[])
93cfcc4… lmata 107 result = RailsEnricher(store).enrich()
93cfcc4… lmata 108 assert set(result.patterns_found.keys()) == {
93cfcc4… lmata 109 "controllers", "models", "routes", "jobs", "concerns"
93cfcc4… lmata 110 }
93cfcc4… lmata 111
93cfcc4… lmata 112
93cfcc4… lmata 113 # ── enrich() with matching nodes ─────────────────────────────────────────────
93cfcc4… lmata 114
93cfcc4… lmata 115
93cfcc4… lmata 116 class TestRailsEnricherWithMatches:
93cfcc4… lmata 117 def _make_store_for_fragment(self, target_fragment, rows):
93cfcc4… lmata 118 """Return a store that returns `rows` only when the query fragment matches."""
93cfcc4… lmata 119
93cfcc4… lmata 120 def side_effect(cypher, params):
93cfcc4… lmata 121 fragment = params.get("fragment", "")
93cfcc4… lmata 122 if fragment == target_fragment:
93cfcc4… lmata 123 return MagicMock(result_set=rows)
93cfcc4… lmata 124 return MagicMock(result_set=[])
93cfcc4… lmata 125
93cfcc4… lmata 126 return _store_with_side_effect(side_effect)
93cfcc4… lmata 127
93cfcc4… lmata 128 def test_controller_promoted(self):
93cfcc4… lmata 129 store = self._make_store_for_fragment(
93cfcc4… lmata 130 "controllers/", [["UsersController", "app/controllers/users_controller.rb"]]
93cfcc4… lmata 131 )
93cfcc4… lmata 132 result = RailsEnricher(store).enrich()
93cfcc4… lmata 133 assert result.patterns_found["controllers"] == 1
93cfcc4… lmata 134 assert result.promoted >= 1
93cfcc4… lmata 135
93cfcc4… lmata 136 def test_model_promoted(self):
93cfcc4… lmata 137 store = self._make_store_for_fragment(
93cfcc4… lmata 138 "models/", [["User", "app/models/user.rb"]]
93cfcc4… lmata 139 )
93cfcc4… lmata 140 result = RailsEnricher(store).enrich()
93cfcc4… lmata 141 assert result.patterns_found["models"] == 1
93cfcc4… lmata 142 assert result.promoted >= 1
93cfcc4… lmata 143
93cfcc4… lmata 144 def test_route_promoted(self):
93cfcc4… lmata 145 store = self._make_store_for_fragment(
93cfcc4… lmata 146 "routes.rb", [["routes", "config/routes.rb"]]
93cfcc4… lmata 147 )
93cfcc4… lmata 148 result = RailsEnricher(store).enrich()
93cfcc4… lmata 149 assert result.patterns_found["routes"] == 1
93cfcc4… lmata 150 assert result.promoted >= 1
93cfcc4… lmata 151
93cfcc4… lmata 152 def test_job_promoted(self):
93cfcc4… lmata 153 store = self._make_store_for_fragment(
93cfcc4… lmata 154 "jobs/", [["SendEmailJob", "app/jobs/send_email_job.rb"]]
93cfcc4… lmata 155 )
93cfcc4… lmata 156 result = RailsEnricher(store).enrich()
93cfcc4… lmata 157 assert result.patterns_found["jobs"] == 1
93cfcc4… lmata 158 assert result.promoted >= 1
93cfcc4… lmata 159
93cfcc4… lmata 160 def test_concern_promoted(self):
93cfcc4… lmata 161 store = self._make_store_for_fragment(
93cfcc4… lmata 162 "concerns/", [["Auditable", "app/models/concerns/auditable.rb"]]
93cfcc4… lmata 163 )
93cfcc4… lmata 164 result = RailsEnricher(store).enrich()
93cfcc4… lmata 165 assert result.patterns_found["concerns"] == 1
93cfcc4… lmata 166 assert result.promoted >= 1
93cfcc4… lmata 167
93cfcc4… lmata 168 def test_promoted_count_accumulates_across_types(self):
93cfcc4… lmata 169 rows_map = {
93cfcc4… lmata 170 "controllers/": [
93cfcc4… lmata 171 ["UsersController", "app/controllers/users_controller.rb"],
93cfcc4… lmata 172 ["PostsController", "app/controllers/posts_controller.rb"],
93cfcc4… lmata 173 ],
93cfcc4… lmata 174 "models/": [["User", "app/models/user.rb"]],
93cfcc4… lmata 175 "routes.rb": [],
93cfcc4… lmata 176 "jobs/": [],
93cfcc4… lmata 177 "concerns/": [],
93cfcc4… lmata 178 }
93cfcc4… lmata 179
93cfcc4… lmata 180 def side_effect(cypher, params):
93cfcc4… lmata 181 fragment = params.get("fragment", "")
93cfcc4… lmata 182 return MagicMock(result_set=rows_map.get(fragment, []))
93cfcc4… lmata 183
93cfcc4… lmata 184 store = _store_with_side_effect(side_effect)
93cfcc4… lmata 185 result = RailsEnricher(store).enrich()
93cfcc4… lmata 186 assert result.promoted == 3
93cfcc4… lmata 187 assert result.patterns_found["controllers"] == 2
93cfcc4… lmata 188 assert result.patterns_found["models"] == 1
93cfcc4… lmata 189
93cfcc4… lmata 190 def test_promote_node_called_with_correct_semantic_type_for_controller(self):
93cfcc4… lmata 191 store = self._make_store_for_fragment(
93cfcc4… lmata 192 "controllers/", [["UsersController", "app/controllers/users_controller.rb"]]
93cfcc4… lmata 193 )
93cfcc4… lmata 194 RailsEnricher(store).enrich()
93cfcc4… lmata 195
93cfcc4… lmata 196 # The _promote_node path ultimately calls store.query with SET n.semantic_type
93cfcc4… lmata 197 calls = [str(c) for c in store._graph.query.call_args_list]
93cfcc4… lmata 198 promote_calls = [c for c in calls if "semantic_type" in c and "RailsController" in c]
93cfcc4… lmata 199 assert len(promote_calls) >= 1
93cfcc4… lmata 200
93cfcc4… lmata 201 def test_promote_node_called_with_correct_semantic_type_for_model(self):
93cfcc4… lmata 202 store = self._make_store_for_fragment(
93cfcc4… lmata 203 "models/", [["User", "app/models/user.rb"]]
93cfcc4… lmata 204 )
93cfcc4… lmata 205 RailsEnricher(store).enrich()
93cfcc4… lmata 206
93cfcc4… lmata 207 calls = [str(c) for c in store._graph.query.call_args_list]
93cfcc4… lmata 208 promote_calls = [c for c in calls if "semantic_type" in c and "RailsModel" in c]
93cfcc4… lmata 209 assert len(promote_calls) >= 1
93cfcc4… lmata 210
93cfcc4… lmata 211 def test_promote_node_called_with_correct_semantic_type_for_job(self):
93cfcc4… lmata 212 store = self._make_store_for_fragment(
93cfcc4… lmata 213 "jobs/", [["SendEmailJob", "app/jobs/send_email_job.rb"]]
93cfcc4… lmata 214 )
93cfcc4… lmata 215 RailsEnricher(store).enrich()
93cfcc4… lmata 216
93cfcc4… lmata 217 calls = [str(c) for c in store._graph.query.call_args_list]
93cfcc4… lmata 218 promote_calls = [c for c in calls if "semantic_type" in c and "RailsJob" in c]
93cfcc4… lmata 219 assert len(promote_calls) >= 1
93cfcc4… lmata 220
93cfcc4… lmata 221 def test_promote_node_called_with_correct_semantic_type_for_concern(self):
93cfcc4… lmata 222 store = self._make_store_for_fragment(
93cfcc4… lmata 223 "concerns/", [["Auditable", "app/models/concerns/auditable.rb"]]
93cfcc4… lmata 224 )
93cfcc4… lmata 225 RailsEnricher(store).enrich()
93cfcc4… lmata 226
93cfcc4… lmata 227 calls = [str(c) for c in store._graph.query.call_args_list]
93cfcc4… lmata 228 promote_calls = [c for c in calls if "semantic_type" in c and "RailsConcern" in c]
93cfcc4… lmata 229 assert len(promote_calls) >= 1
93cfcc4… lmata 230
93cfcc4… lmata 231 def test_promote_node_called_with_correct_semantic_type_for_route(self):
93cfcc4… lmata 232 store = self._make_store_for_fragment(
93cfcc4… lmata 233 "routes.rb", [["routes", "config/routes.rb"]]
93cfcc4… lmata 234 )
93cfcc4… lmata 235 RailsEnricher(store).enrich()
93cfcc4… lmata 236
93cfcc4… lmata 237 calls = [str(c) for c in store._graph.query.call_args_list]
93cfcc4… lmata 238 promote_calls = [c for c in calls if "semantic_type" in c and "RailsRoute" in c]
93cfcc4… lmata 239 assert len(promote_calls) >= 1
93cfcc4… lmata 240
93cfcc4… lmata 241
93cfcc4… lmata 242 # ── detect() integration ──────────────────────────────────────────────────────
93cfcc4… lmata 243
93cfcc4… lmata 244
93cfcc4… lmata 245 class TestRailsEnricherDetect:
93cfcc4… lmata 246 def test_detect_true_when_gemfile_present(self):
93cfcc4… lmata 247 store = _mock_store(result_set=[[1]])
93cfcc4… lmata 248 assert RailsEnricher(store).detect() is True
93cfcc4… lmata 249
93cfcc4… lmata 250 def test_detect_false_when_no_patterns_match(self):
93cfcc4… lmata 251 store = _mock_store(result_set=[[0]])
93cfcc4… lmata 252 assert RailsEnricher(store).detect() is False
93cfcc4… lmata 253
93cfcc4… lmata 254 def test_detect_false_on_empty_result_set(self):
93cfcc4… lmata 255 store = _mock_store(result_set=[])
93cfcc4… lmata 256 assert RailsEnricher(store).detect() is False

Keyboard Shortcuts

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