1+ from unittest import TestCase
2+ from fastapi import FastAPI , APIRouter
3+ from osbot_utils .utils .Dev import pprint
4+
5+ from osbot_utils .utils .Objects import obj
6+
7+ from osbot_utils .type_safe .Type_Safe import Type_Safe
8+ from osbot_utils .type_safe .primitives .core .Safe_Str import Safe_Str
9+ from osbot_utils .type_safe .primitives .domains .identifiers .Safe_Id import Safe_Id
10+ from osbot_fast_api .api .routes .Fast_API__Route__Helper import Fast_API__Route__Helper
11+ from osbot_fast_api .api .routes .Type_Safe__Route__Registration import Type_Safe__Route__Registration
12+
13+
14+ class test_Fast_API__Route__Helper (TestCase ):
15+
16+ def setUp (self ): # Per-test setup for app
17+ self .fastapi_kwargs = dict (docs_url = None , # disables Swagger UI (/docs)
18+ redoc_url = None , # disables ReDoc (/redoc)
19+ openapi_url = None ) # disables OpenAPI schema (/openapi.json)
20+
21+ self .app = FastAPI (** self .fastapi_kwargs )
22+ self .helper = Fast_API__Route__Helper ()
23+
24+ def test__init__ (self ): # Test helper initialization
25+ with Fast_API__Route__Helper () as _ :
26+ assert type (_ ) is Fast_API__Route__Helper
27+ assert type (_ .route_registration ) is Type_Safe__Route__Registration
28+
29+ def test_add_route__with_get_method (self ): # Test adding route with GET method
30+ def test_endpoint ():
31+ return {"status" : "ok" }
32+
33+ self .helper .add_route (self .app , test_endpoint , methods = ['GET' ])
34+
35+ routes = self .app .routes
36+ assert type (routes ) is list
37+
38+ assert len (routes ) == 1
39+ assert routes [0 ].path == '/test-endpoint'
40+ assert routes [0 ].methods == {'GET' }
41+
42+ def test_add_route__with_post_method (self ): # Test adding route with POST method
43+ def create_item ():
44+ return {"created" : True }
45+
46+ self .helper .add_route (self .app , create_item , methods = ['POST' ])
47+
48+ routes = self .app .routes
49+ assert len (routes ) == 1
50+ assert routes [0 ].path == '/create-item'
51+ assert routes [0 ].methods == {'POST' }
52+
53+ def test_add_route__with_multiple_methods (self ): # Test adding route with multiple HTTP methods
54+ def handle_resource ():
55+ return {"handled" : True }
56+
57+ self .helper .add_route (self .app , handle_resource , methods = ['GET' , 'POST' , 'PUT' ])
58+
59+ routes = self .app .routes
60+ assert len (routes ) == 1
61+ assert routes [0 ].methods == {'GET' , 'POST' , 'PUT' }
62+
63+ def test_add_route_get (self ): # Test convenience method for GET routes
64+ def get_data ():
65+ return {"data" : [1 , 2 , 3 ]}
66+
67+ self .helper .add_route_get (self .app , get_data )
68+
69+ routes = self .app .routes
70+ assert len (routes ) == 1
71+ assert routes [0 ].path == '/get-data'
72+ assert routes [0 ].methods == {'GET' }
73+
74+ def test_add_route_post (self ): # Test convenience method for POST routes
75+ def create_user ():
76+ return {"created" : True }
77+
78+ self .helper .add_route_post (self .app , create_user )
79+
80+ routes = self .app .routes
81+ assert len (routes ) == 1
82+ assert routes [0 ].path == '/create-user'
83+ assert routes [0 ].methods == {'POST' }
84+
85+ def test_add_route_put (self ): # Test convenience method for PUT routes
86+ def update_item ():
87+ return {"updated" : True }
88+
89+ self .helper .add_route_put (self .app , update_item )
90+
91+ routes = self .app .routes
92+ assert len (routes ) == 1
93+ assert routes [0 ].path == '/update-item'
94+ assert routes [0 ].methods == {'PUT' }
95+
96+ def test_add_route_delete (self ): # Test convenience method for DELETE routes
97+ def delete_item ():
98+ return {"deleted" : True }
99+
100+ self .helper .add_route_delete (self .app , delete_item )
101+
102+ routes = self .app .routes
103+ assert len (routes ) == 1
104+ assert routes [0 ].path == '/delete-item'
105+ assert routes [0 ].methods == {'DELETE' }
106+
107+ def test_add_route_any__default_path (self ): # Test ANY method with default path parsing
108+ def catch_all ():
109+ return {"method" : "any" }
110+
111+ self .helper .add_route_any (self .app , catch_all )
112+
113+ routes = self .app .routes
114+ assert len (routes ) == 1
115+ assert routes [0 ].path == '/catch-all'
116+ assert routes [0 ].methods == {'DELETE' , 'GET' , 'HEAD' , 'OPTIONS' , 'PATCH' , 'POST' , 'PUT' }
117+
118+ def test_add_route_any__explicit_path (self ): # Test ANY method with explicit path
119+ def proxy (path : str ):
120+ return {"proxied" : path }
121+
122+ self .helper .add_route_any (self .app , proxy , path = "/{path:path}" )
123+
124+ routes = self .app .routes
125+ assert len (routes ) == 1
126+ assert routes [0 ].path == '/{path:path}'
127+ assert routes [0 ].methods == {'DELETE' , 'GET' , 'HEAD' , 'OPTIONS' , 'PATCH' , 'POST' , 'PUT' }
128+
129+ def test_add_route__with_type_safe_params (self ): # Test route with Type_Safe parameters
130+ class User_Data (Type_Safe ):
131+ name : Safe_Str
132+ email : Safe_Str
133+
134+ def create_user (user_data : User_Data ):
135+ return {"created" : True }
136+
137+ self .helper .add_route (self .app , create_user , methods = ['POST' ])
138+
139+ routes = self .app .routes
140+ assert len (routes ) == 1
141+ assert routes [0 ].path == '/create-user'
142+ assert routes [0 ].methods == {'POST' }
143+
144+ def test_add_route__with_path_params (self ): # Test route with path parameters
145+ def get__user_id (user_id : Safe_Id ):
146+ return {"user_id" : str (user_id )}
147+
148+ self .helper .add_route_get (self .app , get__user_id )
149+
150+ routes = self .app .routes
151+ assert len (routes ) == 1
152+ assert routes [0 ].path == '/get/{user_id}'
153+
154+ def test_add_multiple_routes (self ): # Test adding multiple routes to same app
155+ def endpoint_1 ():
156+ pass
157+
158+ def endpoint_2 ():
159+ pass
160+
161+ def endpoint_3 ():
162+ pass
163+
164+ self .helper .add_route_get (self .app , endpoint_1 )
165+ self .helper .add_route_post (self .app , endpoint_2 )
166+ self .helper .add_route_put (self .app , endpoint_3 )
167+
168+ routes = self .app .routes
169+ assert len (routes ) == 3
170+ assert routes [0 ].path == '/endpoint-1'
171+ assert routes [1 ].path == '/endpoint-2'
172+ assert routes [2 ].path == '/endpoint-3'
173+ assert routes [0 ].methods == {'GET' }
174+ assert routes [1 ].methods == {'POST' }
175+ assert routes [2 ].methods == {'PUT' }
176+
177+ def test_add_route__integration_with_analyzer_and_converter (self ): # Test full integration with Type_Safe system
178+ class Order_Data (Type_Safe ):
179+ items : list
180+ quantity : Safe_Id
181+
182+ def create__order_id (order_id : Safe_Id , data : Order_Data ):
183+ return {"order_id" : str (order_id ), "created" : True }
184+
185+ self .helper .add_route_post (self .app , create__order_id )
186+
187+ routes = self .app .routes
188+ assert len (routes ) == 1
189+ assert routes [0 ].path == '/create/{order_id}'
190+
191+ def test_add_route_any__no_explicit_path (self ): # Test ANY without explicit path uses parser
192+ def handle_request ():
193+ return {"handled" : True }
194+
195+ self .helper .add_route_any (self .app , handle_request , path = None )
196+
197+ routes = self .app .routes
198+ assert len (routes ) == 1
199+ assert routes [0 ].path == '/handle-request'
0 commit comments