Skip to content

Commit 5af054b

Browse files
authored
test: add unit tests for fletx/core/routing/config.py
test: add unit tests for fletx/core/routing/config.py
2 parents c7e7ef2 + 298df6e commit 5af054b

1 file changed

Lines changed: 336 additions & 0 deletions

File tree

tests/test_routing_config.py

Lines changed: 336 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,336 @@
1+
"""
2+
Unit tests for FletX Routing Configuration Module
3+
"""
4+
5+
import pytest
6+
import re
7+
from unittest.mock import Mock, patch
8+
9+
from fletx.core.routing.config import (
10+
RouteDefinition,
11+
RoutePattern,
12+
RouterConfig,
13+
ModuleRouter,
14+
router_config
15+
)
16+
from fletx.core.routing.models import RouteType
17+
from fletx.core.routing.guards import RouteGuard
18+
from fletx.core.routing.middleware import RouteMiddleware
19+
20+
21+
class TestRouteDefinition:
22+
"""Test RouteDefinition class."""
23+
24+
def test_creation_with_defaults(self):
25+
"""Test basic creation with default values."""
26+
component = Mock()
27+
route_def = RouteDefinition(path="/test", component=component)
28+
29+
assert route_def.path == "/test"
30+
assert route_def.component == component
31+
assert route_def.route_type == RouteType.PAGE
32+
assert route_def.guards == []
33+
assert route_def.middleware == []
34+
assert route_def.data == {}
35+
assert route_def.children == []
36+
assert route_def.parent is None
37+
38+
def test_creation_with_all_params(self):
39+
"""Test creation with all parameters."""
40+
guard, middleware = Mock(spec=RouteGuard), Mock(spec=RouteMiddleware)
41+
42+
route_def = RouteDefinition(
43+
path="/test",
44+
component=Mock(),
45+
route_type=RouteType.MODULE,
46+
guards=[guard],
47+
middleware=[middleware],
48+
data={"key": "value"},
49+
resolve={"resolver": Mock()},
50+
meta={"meta_key": "meta_value"}
51+
)
52+
53+
assert route_def.route_type == RouteType.MODULE
54+
assert route_def.guards == [guard]
55+
assert route_def.data == {"key": "value"}
56+
assert "resolver" in route_def.resolve
57+
58+
def test_parent_child_relationship(self):
59+
"""Test parent-child relationships."""
60+
parent = RouteDefinition(path="/parent", component=Mock())
61+
child = RouteDefinition(path="/child", component=Mock(), parent=parent)
62+
parent.children.append(child)
63+
64+
assert child.parent == parent
65+
assert child in parent.children
66+
67+
68+
class TestRoutePattern:
69+
"""Test RoutePattern class."""
70+
71+
def test_simple_path(self):
72+
"""Test simple path matching."""
73+
pattern = RoutePattern("/test")
74+
75+
assert pattern.match("/test") == {}
76+
assert pattern.match("/other") is None
77+
78+
def test_parameters(self):
79+
"""Test parameter extraction."""
80+
pattern = RoutePattern("/user/:id/profile/:section")
81+
82+
assert pattern.param_names == ["id", "section"]
83+
assert pattern.match("/user/123/profile/settings") == {
84+
"id": "123", "section": "settings"
85+
}
86+
assert pattern.match("/user/123") is None
87+
88+
def test_wildcard(self):
89+
"""Test wildcard matching."""
90+
pattern = RoutePattern("/files/*")
91+
92+
assert pattern.match("/files/doc.pdf") == {}
93+
assert pattern.match("/files/folder/file.txt") == {}
94+
assert pattern.match("/files") is None
95+
96+
def test_mixed_params_and_wildcard(self):
97+
"""Test mixed parameters and wildcards."""
98+
pattern = RoutePattern("/api/:version/*")
99+
100+
assert pattern.match("/api/v1/users") == {"version": "v1"}
101+
assert pattern.match("/api/v2/data/export") == {"version": "v2"}
102+
103+
def test_regex_compilation(self):
104+
"""Test regex pattern compilation."""
105+
pattern = RoutePattern("/user/:id")
106+
107+
assert isinstance(pattern.regex_pattern, re.Pattern)
108+
assert pattern.regex_pattern.match("/user/123").group(1) == "123"
109+
110+
111+
class TestRouterConfig:
112+
"""Test RouterConfig class."""
113+
114+
def setup_method(self):
115+
self.config = RouterConfig()
116+
self.component = Mock()
117+
118+
def test_add_route_simple(self):
119+
"""Test adding a simple route."""
120+
route_def = self.config.add_route("/test", self.component)
121+
122+
assert route_def.path == "/test"
123+
assert "/test" in self.config._routes
124+
125+
def test_add_route_with_params(self):
126+
"""Test adding route with parameters."""
127+
self.config.add_route("/user/:id", self.component)
128+
129+
assert len(self.config._route_patterns) == 1
130+
assert self.config._route_patterns[0][0].pattern == "/user/:id"
131+
132+
def test_add_multiple_routes(self):
133+
"""Test adding multiple routes."""
134+
routes = [
135+
{"path": "/route1", "component": self.component},
136+
{"path": "/route2", "component": self.component},
137+
]
138+
self.config.add_routes(routes)
139+
140+
assert len(self.config._routes) == 2
141+
142+
def test_add_nested_routes(self):
143+
"""Test nested route creation."""
144+
parent = self.config.add_route("/parent", self.component)
145+
nested = [{"path": "/child", "component": self.component}]
146+
147+
self.config.add_nested_routes("/parent", nested)
148+
149+
child = self.config._routes["/parent/child"]
150+
assert child.parent == parent
151+
assert child in parent.children
152+
153+
def test_nested_routes_parent_not_found(self):
154+
"""Test error when parent route doesn't exist."""
155+
with pytest.raises(ValueError, match="Parent route not found"):
156+
self.config.add_nested_routes("/nonexistent", [])
157+
158+
def test_add_module_routes(self):
159+
"""Test adding module routes."""
160+
module = Mock(spec=ModuleRouter)
161+
module.get_routes.return_value = [
162+
RouteDefinition(path="/mod", component=self.component)
163+
]
164+
module._config._route_patterns = []
165+
166+
self.config.add_module_routes("/api", module)
167+
168+
route = self.config._routes["/api/mod"]
169+
assert route.route_type == RouteType.MODULE
170+
assert route.meta["module"] == module
171+
172+
def test_get_route(self):
173+
"""Test getting route by path."""
174+
route = self.config.add_route("/test", self.component)
175+
176+
assert self.config.get_route("/test") == route
177+
assert self.config.get_route("/nonexistent") is None
178+
179+
def test_match_route_exact(self):
180+
"""Test exact route matching."""
181+
route = self.config.add_route("/test", self.component)
182+
183+
matched, params = self.config.match_route("/test")
184+
assert matched == route
185+
assert params == {}
186+
187+
def test_match_route_pattern(self):
188+
"""Test pattern route matching."""
189+
route = self.config.add_route("/user/:id", self.component)
190+
191+
matched, params = self.config.match_route("/user/123")
192+
assert matched == route
193+
assert params == {"id": "123"}
194+
195+
def test_match_route_no_match(self):
196+
"""Test no route matches."""
197+
self.config.add_route("/test", self.component)
198+
199+
assert self.config.match_route("/other") is None
200+
201+
def test_get_routes_by_type(self):
202+
"""Test filtering routes by type."""
203+
page = self.config.add_route("/page", self.component, route_type=RouteType.PAGE)
204+
module = self.config.add_route("/mod", self.component, route_type=RouteType.MODULE)
205+
206+
assert self.config.get_routes_by_type(RouteType.PAGE) == [page]
207+
assert self.config.get_routes_by_type(RouteType.MODULE) == [module]
208+
209+
def test_get_child_routes(self):
210+
"""Test getting child routes."""
211+
self.config.add_route("/parent", self.component)
212+
self.config.add_nested_routes("/parent", [
213+
{"path": "/child", "component": self.component}
214+
])
215+
216+
assert len(self.config.get_child_routes("/parent")) == 1
217+
assert self.config.get_child_routes("/nonexistent") == []
218+
219+
def test_get_route_hierarchy(self):
220+
"""Test getting route hierarchy."""
221+
gp = self.config.add_route("/gp", self.component)
222+
p = self.config.add_route("/gp/p", self.component)
223+
c = self.config.add_route("/gp/p/c", self.component)
224+
225+
p.parent, c.parent = gp, p
226+
gp.children.append(p)
227+
p.children.append(c)
228+
229+
hierarchy = self.config.get_route_hierarchy("/gp/p/c")
230+
assert hierarchy == [gp, p, c]
231+
232+
233+
class TestModuleRouter:
234+
"""Test ModuleRouter class."""
235+
236+
def setup_method(self):
237+
self.component = Mock()
238+
239+
def test_initialization(self):
240+
"""Test module router initialization."""
241+
class TestRouter(ModuleRouter):
242+
name = "test"
243+
base_path = "/test"
244+
routes = [{"path": "/r1", "component": Mock()}]
245+
sub_routers = []
246+
247+
router = TestRouter()
248+
assert router.name == "test"
249+
assert len(router.get_routes()) == 1
250+
251+
def test_add_route(self):
252+
"""Test adding route to module."""
253+
class TestRouter(ModuleRouter):
254+
name = "test"
255+
base_path = "/test"
256+
routes = []
257+
sub_routers = []
258+
259+
router = TestRouter()
260+
route = router.add_route("/new", self.component)
261+
262+
assert route.path == "/new"
263+
264+
def test_match_route(self):
265+
"""Test route matching in module."""
266+
class TestRouter(ModuleRouter):
267+
name = "test"
268+
base_path = "/test"
269+
routes = [{"path": "/user/:id", "component": Mock()}]
270+
sub_routers = []
271+
272+
router = TestRouter()
273+
matched, params = router.match_route("/user/123")
274+
275+
assert params == {"id": "123"}
276+
277+
def test_add_subrouters(self):
278+
"""Test adding sub-routers."""
279+
class SubRouter(ModuleRouter):
280+
name = "sub"
281+
base_path = "/sub"
282+
routes = [{"path": "/r", "component": Mock()}]
283+
sub_routers = []
284+
285+
class MainRouter(ModuleRouter):
286+
name = "main"
287+
base_path = "/main"
288+
routes = []
289+
sub_routers = [SubRouter]
290+
291+
router = MainRouter()
292+
routes = router.get_routes()
293+
294+
assert len(routes) == 1
295+
assert routes[0].path == "/sub/r"
296+
297+
298+
class TestGlobalConfig:
299+
"""Test global router configuration."""
300+
301+
def test_singleton(self):
302+
"""Test router_config is singleton."""
303+
from fletx.core.routing.config import router_config as c1, router_config as c2
304+
assert c1 is c2
305+
306+
307+
class TestIntegration:
308+
"""Integration tests."""
309+
310+
def setup_method(self):
311+
self.config = RouterConfig()
312+
self.component = Mock()
313+
314+
def test_complex_routing(self):
315+
"""Test complex routing scenario."""
316+
self.config.add_route("/", self.component)
317+
self.config.add_route("/user/:id", self.component)
318+
self.config.add_route("/files/*", self.component)
319+
320+
assert self.config.match_route("/")[0] is not None
321+
_, params = self.config.match_route("/user/123")
322+
assert params == {"id": "123"}
323+
assert self.config.match_route("/files/doc.pdf")[0] is not None
324+
325+
def test_deep_hierarchy(self):
326+
"""Test deep route hierarchy."""
327+
self.config.add_route("/app", self.component)
328+
self.config.add_nested_routes("/app", [
329+
{"path": "/dashboard", "component": self.component}
330+
])
331+
self.config.add_nested_routes("/app/dashboard", [
332+
{"path": "/settings", "component": self.component}
333+
])
334+
335+
hierarchy = self.config.get_route_hierarchy("/app/dashboard/settings")
336+
assert len(hierarchy) == 3

0 commit comments

Comments
 (0)