@@ -170,6 +170,39 @@ fn response_header_is_correct(
170170 Ok ( ( ) )
171171}
172172
173+ #[ then( expr = "response header {string} starts with {string}" ) ]
174+ fn response_header_starts_with (
175+ world : & mut HitboxWorld ,
176+ header_name : String ,
177+ expected_prefix : String ,
178+ ) -> Result < ( ) , Error > {
179+ let response = world
180+ . state
181+ . response
182+ . as_ref ( )
183+ . ok_or_else ( || anyhow ! ( "No response available" ) ) ?;
184+
185+ let header_value = response
186+ . headers ( )
187+ . get ( & header_name)
188+ . ok_or_else ( || anyhow ! ( "Header '{}' not found" , header_name) ) ?;
189+
190+ let actual_value = header_value
191+ . to_str ( )
192+ . map_err ( |_| anyhow ! ( "Header '{}' contains invalid UTF-8" , header_name) ) ?;
193+
194+ if !actual_value. starts_with ( & expected_prefix) {
195+ return Err ( anyhow ! (
196+ "Expected header '{}' to start with '{}', but found '{}'" ,
197+ header_name,
198+ expected_prefix,
199+ actual_value
200+ ) ) ;
201+ }
202+
203+ Ok ( ( ) )
204+ }
205+
173206#[ then( expr = "backend read was called {int} times with all miss" ) ]
174207fn backend_read_all_miss ( world : & mut HitboxWorld , expected : usize ) -> Result < ( ) , Error > {
175208 let read_count = world. backend . read_count ( ) ;
@@ -286,6 +319,54 @@ fn response_headers_table(world: &mut HitboxWorld, step: &Step) -> Result<(), Er
286319 Ok ( ( ) )
287320}
288321
322+ #[ then( expr = "response headers start with" ) ]
323+ fn response_headers_start_with_table ( world : & mut HitboxWorld , step : & Step ) -> Result < ( ) , Error > {
324+ let table = step
325+ . table
326+ . as_ref ( )
327+ . ok_or_else ( || anyhow ! ( "Expected a table" ) ) ?;
328+
329+ if table. rows . len ( ) != world. state . responses . len ( ) {
330+ return Err ( anyhow ! (
331+ "Expected {} rows but got {}" ,
332+ world. state. responses. len( ) ,
333+ table. rows. len( )
334+ ) ) ;
335+ }
336+
337+ for ( i, ( row, response) ) in table
338+ . rows
339+ . iter ( )
340+ . zip ( world. state . responses . iter ( ) )
341+ . enumerate ( )
342+ {
343+ let header_name = row
344+ . first ( )
345+ . ok_or_else ( || anyhow ! ( "Row {} missing header name" , i) ) ?;
346+ let expected_prefix = row
347+ . get ( 1 )
348+ . ok_or_else ( || anyhow ! ( "Row {} missing value" , i) ) ?;
349+
350+ let actual_value = response
351+ . headers ( )
352+ . get ( header_name)
353+ . map ( |v| v. to_str ( ) . unwrap_or ( "" ) )
354+ . unwrap_or ( "" ) ;
355+
356+ if !actual_value. starts_with ( expected_prefix. as_str ( ) ) {
357+ return Err ( anyhow ! (
358+ "Response {}: header '{}' expected to start with '{}', got '{}'" ,
359+ i,
360+ header_name,
361+ expected_prefix,
362+ actual_value
363+ ) ) ;
364+ }
365+ }
366+
367+ Ok ( ( ) )
368+ }
369+
289370#[ then( expr = "{word} should be called 1 time" ) ]
290371fn upstream_called_once ( world : & mut HitboxWorld , handler : String ) -> Result < ( ) , Error > {
291372 let handler_name: HandlerName = handler
0 commit comments