@@ -551,4 +551,84 @@ mod tests {
551551 assert ! ( meta. capabilities. contains( & CapabilityClass :: Network ) ) ;
552552 assert_eq ! ( meta. data_sensitivity, DataSensitivity :: Medium ) ;
553553 }
554+
555+ // --- detect_collisions ---
556+
557+ fn trust_map (
558+ entries : & [ ( & str , crate :: manager:: McpTrustLevel ) ] ,
559+ ) -> std:: collections:: HashMap < String , crate :: manager:: McpTrustLevel > {
560+ entries. iter ( ) . map ( |( k, v) | ( ( * k) . to_owned ( ) , * v) ) . collect ( )
561+ }
562+
563+ #[ test]
564+ fn detect_collisions_no_collision_happy_path ( ) {
565+ let tools = vec ! [
566+ make_tool( "server_a" , "tool_one" ) ,
567+ make_tool( "server_b" , "tool_two" ) ,
568+ ] ;
569+ let tm = trust_map ( & [
570+ ( "server_a" , crate :: manager:: McpTrustLevel :: Trusted ) ,
571+ ( "server_b" , crate :: manager:: McpTrustLevel :: Trusted ) ,
572+ ] ) ;
573+ let cols = detect_collisions ( & tools, & tm) ;
574+ assert ! ( cols. is_empty( ) , "different sanitized_ids must not collide" ) ;
575+ }
576+
577+ #[ test]
578+ fn detect_collisions_different_trust_collision ( ) {
579+ // "a.b:c" and "a:b_c" both sanitize to "a_b_c" — collision across trust levels.
580+ let tool_a = make_tool ( "a.b" , "c" ) ;
581+ let tool_b = make_tool ( "a" , "b_c" ) ;
582+ let tm = trust_map ( & [
583+ ( "a.b" , crate :: manager:: McpTrustLevel :: Trusted ) ,
584+ ( "a" , crate :: manager:: McpTrustLevel :: Untrusted ) ,
585+ ] ) ;
586+ let cols = detect_collisions ( & [ tool_a, tool_b] , & tm) ;
587+ assert_eq ! ( cols. len( ) , 1 ) ;
588+ let col = & cols[ 0 ] ;
589+ assert_eq ! ( col. sanitized_id, "a_b_c" ) ;
590+ assert_eq ! ( col. server_a, "a.b" ) ;
591+ assert_eq ! ( col. server_b, "a" ) ;
592+ assert_eq ! ( col. trust_a, crate :: manager:: McpTrustLevel :: Trusted ) ;
593+ assert_eq ! ( col. trust_b, crate :: manager:: McpTrustLevel :: Untrusted ) ;
594+ }
595+
596+ #[ test]
597+ fn detect_collisions_same_trust_collision ( ) {
598+ // Both servers are Untrusted and share a sanitized_id.
599+ let tool_a = make_tool ( "a.b" , "c" ) ;
600+ let tool_b = make_tool ( "a" , "b_c" ) ;
601+ let tm = trust_map ( & [
602+ ( "a.b" , crate :: manager:: McpTrustLevel :: Untrusted ) ,
603+ ( "a" , crate :: manager:: McpTrustLevel :: Untrusted ) ,
604+ ] ) ;
605+ let cols = detect_collisions ( & [ tool_a, tool_b] , & tm) ;
606+ assert_eq ! ( cols. len( ) , 1 ) ;
607+ assert_eq ! ( cols[ 0 ] . trust_a, crate :: manager:: McpTrustLevel :: Untrusted ) ;
608+ assert_eq ! ( cols[ 0 ] . trust_b, crate :: manager:: McpTrustLevel :: Untrusted ) ;
609+ }
610+
611+ #[ test]
612+ fn detect_collisions_multiple_collisions_reported ( ) {
613+ // Three tools, all sharing the same sanitized_id "srv_tool".
614+ let t1 = make_tool ( "srv" , "tool" ) ;
615+ let t2 = make_tool ( "srv.x" , "tool" ) ; // "srv_x_tool" — different, no collision with t1
616+ let t3 = make_tool ( "srv" , "tool" ) ; // exact duplicate of t1 — collision
617+ let tm = trust_map ( & [ ( "srv" , crate :: manager:: McpTrustLevel :: Untrusted ) ] ) ;
618+ let cols = detect_collisions ( & [ t1, t2, t3] , & tm) ;
619+ // t1 and t3 share "srv_tool"; t2 is "srv_x_tool" — one collision
620+ assert_eq ! ( cols. len( ) , 1 ) ;
621+ assert_eq ! ( cols[ 0 ] . sanitized_id, "srv_tool" ) ;
622+ }
623+
624+ #[ test]
625+ fn detect_collisions_unknown_server_defaults_to_untrusted ( ) {
626+ let tool_a = make_tool ( "a.b" , "c" ) ;
627+ let tool_b = make_tool ( "a" , "b_c" ) ;
628+ // No entries in trust_map — both should default to Untrusted.
629+ let cols = detect_collisions ( & [ tool_a, tool_b] , & std:: collections:: HashMap :: new ( ) ) ;
630+ assert_eq ! ( cols. len( ) , 1 ) ;
631+ assert_eq ! ( cols[ 0 ] . trust_a, crate :: manager:: McpTrustLevel :: Untrusted ) ;
632+ assert_eq ! ( cols[ 0 ] . trust_b, crate :: manager:: McpTrustLevel :: Untrusted ) ;
633+ }
554634}
0 commit comments