@@ -575,6 +575,9 @@ fn next_available_prefix(
575575
576576#[ cfg( test) ]
577577mod tests {
578+ use carbide_test_support:: Outcome :: * ;
579+ use carbide_test_support:: { Case , check_cases} ;
580+
578581 use super :: * ;
579582
580583 #[ test]
@@ -911,14 +914,55 @@ mod tests {
911914
912915 #[ test]
913916 fn test_v4_candidate ( ) {
917+ // A /30 from 192.168.1.0/24 always lands on 192.168.1.8/30 once .0 and the
918+ // .4/30 block are taken — and stays there however the already-allocated set
919+ // is spelled: with a bare pair, with a duplicate /32, or with a smaller /31
920+ // already covered by the .4/30. The candidate search collapses all three.
921+ struct AllocatedSet {
922+ scenario : & ' static str ,
923+ allocated_cidrs : Vec < IpNetwork > ,
924+ }
925+
914926 let cidr = "192.168.1.0/24" . parse ( ) . unwrap ( ) ;
915927 let prefix_length = 30 ;
916- let allocated_cidrs = vec ! [
917- "192.168.1.0/32" . parse( ) . unwrap( ) ,
918- "192.168.1.4/30" . parse( ) . unwrap( ) ,
919- ] ;
920- let next_prefix = next_available_prefix ( cidr, prefix_length, allocated_cidrs) . unwrap ( ) ;
921- assert ! ( next_prefix. is_some_and( |prefix| prefix. to_string( ) == "192.168.1.8/30" ) ) ;
928+
929+ check_cases (
930+ [
931+ AllocatedSet {
932+ scenario : "distinct networks" ,
933+ allocated_cidrs : vec ! [
934+ "192.168.1.0/32" . parse( ) . unwrap( ) ,
935+ "192.168.1.4/30" . parse( ) . unwrap( ) ,
936+ ] ,
937+ } ,
938+ AllocatedSet {
939+ scenario : "duplicate /32" ,
940+ allocated_cidrs : vec ! [
941+ "192.168.1.0/32" . parse( ) . unwrap( ) ,
942+ "192.168.1.0/32" . parse( ) . unwrap( ) ,
943+ "192.168.1.4/30" . parse( ) . unwrap( ) ,
944+ ] ,
945+ } ,
946+ AllocatedSet {
947+ scenario : "covered /31 inside the /30" ,
948+ allocated_cidrs : vec ! [
949+ "192.168.1.0/32" . parse( ) . unwrap( ) ,
950+ "192.168.1.0/32" . parse( ) . unwrap( ) ,
951+ "192.168.1.4/31" . parse( ) . unwrap( ) ,
952+ "192.168.1.4/30" . parse( ) . unwrap( ) ,
953+ ] ,
954+ } ,
955+ ]
956+ . map ( |set| Case {
957+ scenario : set. scenario ,
958+ input : set. allocated_cidrs ,
959+ expect : Yields ( Some ( "192.168.1.8/30" . parse ( ) . unwrap ( ) ) ) ,
960+ } ) ,
961+ |allocated_cidrs| {
962+ next_available_prefix ( cidr, prefix_length, allocated_cidrs)
963+ . map_err ( |e| e. to_string ( ) )
964+ } ,
965+ ) ;
922966 }
923967
924968 #[ test]
@@ -936,33 +980,6 @@ mod tests {
936980 assert_eq ! ( next_prefix. ip( ) . to_string( ) , "192.168.1.1" ) ;
937981 }
938982
939- #[ test]
940- fn test_v4_candidate_with_duplicate ( ) {
941- let cidr = "192.168.1.0/24" . parse ( ) . unwrap ( ) ;
942- let prefix_length = 30 ;
943- let allocated_cidrs = vec ! [
944- "192.168.1.0/32" . parse( ) . unwrap( ) ,
945- "192.168.1.0/32" . parse( ) . unwrap( ) ,
946- "192.168.1.4/30" . parse( ) . unwrap( ) ,
947- ] ;
948- let next_prefix = next_available_prefix ( cidr, prefix_length, allocated_cidrs) . unwrap ( ) ;
949- assert ! ( next_prefix. is_some_and( |prefix| prefix. to_string( ) == "192.168.1.8/30" ) ) ;
950- }
951-
952- #[ test]
953- fn test_v4_candidate_with_covered ( ) {
954- let cidr = "192.168.1.0/24" . parse ( ) . unwrap ( ) ;
955- let prefix_length = 30 ;
956- let allocated_cidrs = vec ! [
957- "192.168.1.0/32" . parse( ) . unwrap( ) ,
958- "192.168.1.0/32" . parse( ) . unwrap( ) ,
959- "192.168.1.4/31" . parse( ) . unwrap( ) ,
960- "192.168.1.4/30" . parse( ) . unwrap( ) ,
961- ] ;
962- let next_prefix = next_available_prefix ( cidr, prefix_length, allocated_cidrs) . unwrap ( ) ;
963- assert ! ( next_prefix. is_some_and( |prefix| prefix. to_string( ) == "192.168.1.8/30" ) ) ;
964- }
965-
966983 #[ test]
967984 fn test_v6_candidate ( ) {
968985 // Ode to the 2012 Aston Martin DB9.
0 commit comments