@@ -190,6 +190,94 @@ fn explicit_path_and_query_mappings_generate_an_ordinary_source_request() {
190190 assert ! ( !prepare. contains( "TODO(evidencectl)" ) , "{prepare}" ) ;
191191}
192192
193+ #[ test]
194+ fn mapped_rendered_path_guard_agrees_with_runtime_admission ( ) {
195+ use registry_evidence:: config:: EvidenceConfig ;
196+ let maximum = format ! ( "/{}" , "a" . repeat( 2047 ) ) ;
197+ let overlong = format ! ( "/{}" , "a" . repeat( 2048 ) ) ;
198+ let cases = [
199+ ( "/v1/records" , "" ) ,
200+ ( "/v1/records/{record_id}" , "/api" ) ,
201+ ( "/v1/exact:record/{record_id}" , "" ) ,
202+ ( "/v1/value%20with%20space/{record_id}" , "" ) ,
203+ ( maximum. as_str ( ) , "" ) ,
204+ ( overlong. as_str ( ) , "" ) ,
205+ ( "/v1/records/{record_id}/" , "" ) ,
206+ ( "/v1//records/{record_id}" , "" ) ,
207+ ( "/v1/./records/{record_id}" , "" ) ,
208+ ( "/v1/../records/{record_id}" , "" ) ,
209+ ( "/v1/récords/{record_id}" , "" ) ,
210+ ( "/v1/records/{record_id}?fixed=1" , "" ) ,
211+ ( "/v1/records/{record_id}#fragment" , "" ) ,
212+ ( "/v1/records\\ other/{record_id}" , "" ) ,
213+ ( "/v1/%2e/{record_id}" , "" ) ,
214+ ( "/v1/%2F/{record_id}" , "" ) ,
215+ ( "/v1/%41/{record_id}" , "" ) ,
216+ ( "/v1/%GG/{record_id}" , "" ) ,
217+ ( "/v1/records/{record_id}" , "/api//v2" ) ,
218+ ( "/v1/records/{record_id}" , "/api/%2F" ) ,
219+ ] ;
220+ for ( case, ( path, prefix) ) in cases. into_iter ( ) . enumerate ( ) {
221+ let mut inputs = base_inputs ( ) ;
222+ inputs. operation . path = path. to_owned ( ) ;
223+ inputs. base_url_suggestion =
224+ emit:: split_server_url ( & format ! ( "https://api.example.invalid{prefix}" ) ) ;
225+ let selector = SelectorReference {
226+ role : "subject" . to_owned ( ) ,
227+ profile : "person-demographics-v1" . to_owned ( ) ,
228+ field : "given_name" . to_owned ( ) ,
229+ scalar_type : SelectorScalarType :: String ,
230+ maximum_bytes : 200 ,
231+ } ;
232+ inputs. request_mappings = vec ! [ RequestMapping {
233+ selector: selector. clone( ) ,
234+ target: RequestTarget :: Query ( "reference" . to_owned( ) ) ,
235+ } ] ;
236+ let mut bindings = serde_json:: Map :: new ( ) ;
237+ if path. contains ( "{record_id}" ) {
238+ inputs. request_mappings . push ( RequestMapping {
239+ selector,
240+ target : RequestTarget :: Path ( "record_id" . to_owned ( ) ) ,
241+ } ) ;
242+ bindings. insert ( "record_id" . to_owned ( ) , json ! ( { "type" : "selector" , "role" : "subject" , "profile" : "person-demographics-v1" , "field" : "given_name" } ) ) ;
243+ }
244+ let rendered = format ! ( "{prefix}{path}" ) ;
245+ let mut bundle: serde_json:: Value = serde_norway:: from_str ( include_str ! (
246+ "../../../products/evidence/fixtures/acceptance/adult-status/evidence.yaml"
247+ ) )
248+ . expect ( "runtime acceptance bundle" ) ;
249+ let request = & mut bundle[ "sources" ] [ "source-a" ] [ "request" ] ;
250+ request[ "path" ] = json ! ( rendered) ;
251+ if !bindings. is_empty ( ) {
252+ request[ "pathBindings" ] = json ! ( bindings) ;
253+ }
254+ let runtime =
255+ EvidenceConfig :: parse_yaml ( & serde_json:: to_vec ( & bundle) . expect ( "runtime bundle" ) ) ;
256+ let draft = emit:: draft ( & inputs) ;
257+ assert_eq ! (
258+ draft. is_ok( ) ,
259+ runtime. is_ok( ) ,
260+ "path case {case} ({} bytes): draft {:?}, runtime {:?}" ,
261+ rendered. len( ) ,
262+ draft. as_ref( ) . err( ) ,
263+ runtime. as_ref( ) . err( )
264+ ) ;
265+ if let Ok ( draft) = draft {
266+ let source: serde_json:: Value =
267+ serde_json:: from_str ( & draft. authoring_source ) . expect ( "Source JSON" ) ;
268+ assert_eq ! ( source[ "request" ] [ "path" ] , rendered) ;
269+ }
270+ }
271+ }
272+
273+ #[ test]
274+ fn unmapped_incomplete_path_drafts_remain_available ( ) {
275+ let mut inputs = base_inputs ( ) ;
276+ inputs. operation . path = "/v1/records/{RecordId}/" . to_owned ( ) ;
277+ let draft = emit:: draft ( & inputs) . expect ( "unmapped authoring draft" ) ;
278+ assert ! ( file_contents( & draft, "functions/search-a-prepare.rhai" ) . contains( "TODO(evidencectl)" ) ) ;
279+ }
280+
193281#[ test]
194282fn explicit_post_body_mappings_generate_a_closed_json_object ( ) {
195283 let mut inputs = base_inputs ( ) ;
0 commit comments