11// Licensed to the .NET Foundation under one or more agreements. 
22// The .NET Foundation licenses this file to you under the MIT license. 
33
4+ using  System . Buffers . Binary ; 
45using  System . Collections ; 
56using  System . Collections . Generic ; 
7+ using  System . Diagnostics ; 
68using  System . Linq ; 
9+ using  System . Net . Sockets ; 
10+ using  System . Runtime . InteropServices ; 
711using  System . Text ; 
812using  Xunit ; 
913
@@ -26,38 +30,64 @@ public class IPNetworkTest
2630        { 
2731            {  "127.0.0.1/33"  } ,  // PrefixLength max is 32 for IPv4 
2832            {  "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/129"  } ,  // PrefixLength max is 128 for IPv6 
29-             {  "127.0.0.1/31"  } ,  // Bits exceed the prefix length of 31 (32nd bit is on) 
30-             {  "198.51.255.0/23"  } ,  // Bits exceed the prefix length of 23 
31-             {  "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/127"  } ,  // Bits exceed the prefix length of 31 
32-             {  "2a01:110:8012::/45"  } ,  // Bits exceed the prefix length of 45 (47th bit is on) 
3333        } ; 
3434
3535        public  static TheoryData < string >  ValidIPNetworkData  =  new  TheoryData < string > ( ) 
3636        { 
3737            {  "0.0.0.0/32"  } ,  // the whole IPv4 space 
3838            {  "0.0.0.0/0"  } , 
39+             {  "192.168.0.10/0"  } , 
3940            {  "128.0.0.0/1"  } , 
41+             {  "127.0.0.1/8"  } , 
42+             {  "127.0.0.1/31"  } , 
43+             {  "198.51.255.0/23"  } , 
4044            {  "::/128"  } ,  // the whole IPv6 space 
4145            {  "255.255.255.255/32"  } , 
4246            {  "198.51.254.0/23"  } , 
4347            {  "42.42.128.0/17"  } , 
4448            {  "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"  } , 
4549            {  "2a01:110:8012::/47"  } , 
4650            {  "2a01:110:8012::/100"  } , 
51+             {  "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/127"  } , 
52+             {  "2a01:110:8012::/45"  } , 
4753        } ; 
4854
55+         private  uint  GetMask32 ( int  prefix ) 
56+         { 
57+             Debug . Assert ( prefix  !=  0 ) ; 
58+ 
59+             uint  mask  =  uint . MaxValue  <<  ( 32  -  prefix ) ; 
60+             return  BitConverter . IsLittleEndian  ?  BinaryPrimitives . ReverseEndianness ( mask )  :  mask ; 
61+         } 
62+         private  UInt128  GetMask128 ( int  prefix ) 
63+         { 
64+             Debug . Assert ( prefix  !=  0 ) ; 
65+ 
66+             UInt128  mask  =  UInt128 . MaxValue  <<  ( 128  -  prefix ) ; 
67+             return  BitConverter . IsLittleEndian  ?  BinaryPrimitives . ReverseEndianness ( mask )  :  mask ; 
68+         } 
69+         private  IPAddress  GetBaseAddress ( IPAddress  address ,  int  prefix ) 
70+             =>  ( address . AddressFamily ,  prefix )  switch 
71+             { 
72+                 ( AddressFamily . InterNetwork ,  0 )  =>  new  IPAddress ( [ 0 ,  0 ,  0 ,  0 ] ) , 
73+                 ( AddressFamily . InterNetwork ,  _ )  =>  new  IPAddress ( MemoryMarshal . Read < uint > ( address . GetAddressBytes ( ) )  &  GetMask32 ( prefix ) ) , 
74+                 ( AddressFamily . InterNetworkV6 ,  0 )  =>  new  IPAddress ( [ 0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ,  0 ] ) , 
75+                 ( AddressFamily . InterNetworkV6 ,  _ )  =>  new  IPAddress ( MemoryMarshal . AsBytes ( [ MemoryMarshal . Read < UInt128 > ( address . GetAddressBytes ( ) )  &  GetMask128 ( prefix ) ] ) ) , 
76+                 _ =>  throw  new  ArgumentOutOfRangeException ( $ "Unexpected address family { address . AddressFamily }  of { address } .") 
77+             } ; 
78+ 
4979        [ Theory ] 
5080        [ MemberData ( nameof ( ValidIPNetworkData ) ) ] 
5181        public  void  Constructor_Valid_Succeeds ( string  input ) 
5282        { 
5383            string [ ]  splitInput  =  input . Split ( '/' ) ; 
5484            IPAddress  address  =  IPAddress . Parse ( splitInput [ 0 ] ) ; 
55-             int  prefixLegth  =  int . Parse ( splitInput [ 1 ] ) ; 
85+             int  prefixLength  =  int . Parse ( splitInput [ 1 ] ) ; 
5686
57-             IPNetwork  network  =  new  IPNetwork ( address ,  prefixLegth ) ; 
87+             IPNetwork  network  =  new  IPNetwork ( address ,  prefixLength ) ; 
5888
59-             Assert . Equal ( address ,  network . BaseAddress ) ; 
60-             Assert . Equal ( prefixLegth ,  network . PrefixLength ) ; 
89+             Assert . Equal ( GetBaseAddress ( address ,   prefixLength ) ,  network . BaseAddress ) ; 
90+             Assert . Equal ( prefixLength ,  network . PrefixLength ) ; 
6191        } 
6292
6393        [ Fact ] 
@@ -77,17 +107,6 @@ public void Constructor_PrefixLenghtOutOfRange_ThrowsArgumentOutOfRangeException
77107            Assert . Throws < ArgumentOutOfRangeException > ( ( )  =>  new  IPNetwork ( address ,  prefixLength ) ) ; 
78108        } 
79109
80-         [ Theory ] 
81-         [ InlineData ( "192.168.0.1" ,  31 ) ] 
82-         [ InlineData ( "42.42.192.0" ,  17 ) ] 
83-         [ InlineData ( "128.0.0.0" ,  0 ) ] 
84-         [ InlineData ( "2a01:110:8012::" ,  46 ) ] 
85-         public  void  Constructor_NonZeroBitsAfterNetworkPrefix_ThrowsArgumentException ( string  ipStr ,  int  prefixLength ) 
86-         { 
87-             IPAddress  address  =  IPAddress . Parse ( ipStr ) ; 
88-             Assert . Throws < ArgumentException > ( ( )  =>  new  IPNetwork ( address ,  prefixLength ) ) ; 
89-         } 
90- 
91110        [ Theory ] 
92111        [ MemberData ( nameof ( IncorrectFormatData ) ) ] 
93112        public  void  Parse_IncorrectFormat_ThrowsFormatException ( string  input ) 
0 commit comments