@@ -1671,4 +1671,59 @@ mod tests {
16711671 let tc = gc. get ( "thinkingConfig" ) . expect ( "thinkingConfig should be injected" ) ;
16721672 assert_eq ! ( tc[ "thinkingBudget" ] , DEFAULT_THINKING_BUDGET ) ;
16731673 }
1674+
1675+ #[ test]
1676+ fn sanitize_dual_generation_config_both_get_thinking ( ) {
1677+ // Attacker sends both casings — both should get thinking budget injected.
1678+ let body = serde_json:: json!( {
1679+ "contents" : [ { "parts" : [ { "text" : "hello" } ] } ] ,
1680+ "generation_config" : { "max_output_tokens" : 100 } ,
1681+ "generationConfig" : { "maxOutputTokens" : 200 }
1682+ } ) ;
1683+ let result = sanitize_gemini_body (
1684+ serde_json:: to_vec ( & body) . unwrap ( ) . as_slice ( ) ,
1685+ "generateContent" ,
1686+ ) . unwrap ( ) ;
1687+ let parsed: serde_json:: Value = serde_json:: from_slice ( & result) . unwrap ( ) ;
1688+ // Both casings should have thinkingConfig injected
1689+ let gc_snake = parsed. get ( "generation_config" ) . unwrap ( ) . as_object ( ) . unwrap ( ) ;
1690+ assert ! ( gc_snake. contains_key( "thinkingConfig" ) ) ;
1691+ let gc_camel = parsed. get ( "generationConfig" ) . unwrap ( ) . as_object ( ) . unwrap ( ) ;
1692+ assert ! ( gc_camel. contains_key( "thinkingConfig" ) ) ;
1693+ }
1694+
1695+ #[ test]
1696+ fn sanitize_null_generation_config_gets_new_one ( ) {
1697+ // Malformed: generation_config is null — proxy should create a fresh one.
1698+ let body = serde_json:: json!( {
1699+ "contents" : [ { "parts" : [ { "text" : "hello" } ] } ] ,
1700+ "generation_config" : null
1701+ } ) ;
1702+ let result = sanitize_gemini_body (
1703+ serde_json:: to_vec ( & body) . unwrap ( ) . as_slice ( ) ,
1704+ "generateContent" ,
1705+ ) . unwrap ( ) ;
1706+ let parsed: serde_json:: Value = serde_json:: from_slice ( & result) . unwrap ( ) ;
1707+ // null generation_config is not an object, so proxy creates generationConfig
1708+ let gc = parsed. get ( "generationConfig" ) . expect ( "generationConfig should be created" ) ;
1709+ let tc = gc. get ( "thinkingConfig" ) . expect ( "thinkingConfig should be injected" ) ;
1710+ assert_eq ! ( tc[ "thinkingBudget" ] , DEFAULT_THINKING_BUDGET ) ;
1711+ }
1712+
1713+ #[ test]
1714+ fn sanitize_string_generation_config_gets_new_one ( ) {
1715+ // Malformed: generation_config is a string — proxy should create a fresh one.
1716+ let body = serde_json:: json!( {
1717+ "contents" : [ { "parts" : [ { "text" : "hello" } ] } ] ,
1718+ "generation_config" : "invalid"
1719+ } ) ;
1720+ let result = sanitize_gemini_body (
1721+ serde_json:: to_vec ( & body) . unwrap ( ) . as_slice ( ) ,
1722+ "generateContent" ,
1723+ ) . unwrap ( ) ;
1724+ let parsed: serde_json:: Value = serde_json:: from_slice ( & result) . unwrap ( ) ;
1725+ let gc = parsed. get ( "generationConfig" ) . expect ( "generationConfig should be created" ) ;
1726+ let tc = gc. get ( "thinkingConfig" ) . expect ( "thinkingConfig should be injected" ) ;
1727+ assert_eq ! ( tc[ "thinkingBudget" ] , DEFAULT_THINKING_BUDGET ) ;
1728+ }
16741729}
0 commit comments