MediaWiki  REL1_23
IPTest.php
Go to the documentation of this file.
00001 <?php
00012 class IPTest extends MediaWikiTestCase {
00017     public function testisIPAddress() {
00018         $this->assertFalse( IP::isIPAddress( false ), 'Boolean false is not an IP' );
00019         $this->assertFalse( IP::isIPAddress( true ), 'Boolean true is not an IP' );
00020         $this->assertFalse( IP::isIPAddress( "" ), 'Empty string is not an IP' );
00021         $this->assertFalse( IP::isIPAddress( 'abc' ), 'Garbage IP string' );
00022         $this->assertFalse( IP::isIPAddress( ':' ), 'Single ":" is not an IP' );
00023         $this->assertFalse( IP::isIPAddress( '2001:0DB8::A:1::1' ), 'IPv6 with a double :: occurrence' );
00024         $this->assertFalse(
00025             IP::isIPAddress( '2001:0DB8::A:1::' ),
00026             'IPv6 with a double :: occurrence, last at end'
00027         );
00028         $this->assertFalse(
00029             IP::isIPAddress( '::2001:0DB8::5:1' ),
00030             'IPv6 with a double :: occurrence, firt at beginning'
00031         );
00032         $this->assertFalse( IP::isIPAddress( '124.24.52' ), 'IPv4 not enough quads' );
00033         $this->assertFalse( IP::isIPAddress( '24.324.52.13' ), 'IPv4 out of range' );
00034         $this->assertFalse( IP::isIPAddress( '.24.52.13' ), 'IPv4 starts with period' );
00035         $this->assertFalse( IP::isIPAddress( 'fc:100:300' ), 'IPv6 with only 3 words' );
00036 
00037         $this->assertTrue( IP::isIPAddress( '::' ), 'RFC 4291 IPv6 Unspecified Address' );
00038         $this->assertTrue( IP::isIPAddress( '::1' ), 'RFC 4291 IPv6 Loopback Address' );
00039         $this->assertTrue( IP::isIPAddress( '74.24.52.13/20', 'IPv4 range' ) );
00040         $this->assertTrue( IP::isIPAddress( 'fc:100:a:d:1:e:ac:0/24' ), 'IPv6 range' );
00041         $this->assertTrue( IP::isIPAddress( 'fc::100:a:d:1:e:ac/96' ), 'IPv6 range with "::"' );
00042 
00043         $validIPs = array( 'fc:100::', 'fc:100:a:d:1:e:ac::', 'fc::100', '::fc:100:a:d:1:e:ac',
00044             '::fc', 'fc::100:a:d:1:e:ac', 'fc:100:a:d:1:e:ac:0', '124.24.52.13', '1.24.52.13' );
00045         foreach ( $validIPs as $ip ) {
00046             $this->assertTrue( IP::isIPAddress( $ip ), "$ip is a valid IP address" );
00047         }
00048     }
00049 
00053     public function testisIPv6() {
00054         $this->assertFalse( IP::isIPv6( ':fc:100::' ), 'IPv6 starting with lone ":"' );
00055         $this->assertFalse( IP::isIPv6( 'fc:100:::' ), 'IPv6 ending with a ":::"' );
00056         $this->assertFalse( IP::isIPv6( 'fc:300' ), 'IPv6 with only 2 words' );
00057         $this->assertFalse( IP::isIPv6( 'fc:100:300' ), 'IPv6 with only 3 words' );
00058 
00059         $this->assertTrue( IP::isIPv6( 'fc:100::' ) );
00060         $this->assertTrue( IP::isIPv6( 'fc:100:a::' ) );
00061         $this->assertTrue( IP::isIPv6( 'fc:100:a:d::' ) );
00062         $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1::' ) );
00063         $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e::' ) );
00064         $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e:ac::' ) );
00065 
00066         $this->assertFalse( IP::isIPv6( 'fc:100:a:d:1:e:ac:0::' ), 'IPv6 with 8 words ending with "::"' );
00067         $this->assertFalse(
00068             IP::isIPv6( 'fc:100:a:d:1:e:ac:0:1::' ),
00069             'IPv6 with 9 words ending with "::"'
00070         );
00071 
00072         $this->assertFalse( IP::isIPv6( ':::' ) );
00073         $this->assertFalse( IP::isIPv6( '::0:' ), 'IPv6 ending in a lone ":"' );
00074 
00075         $this->assertTrue( IP::isIPv6( '::' ), 'IPv6 zero address' );
00076         $this->assertTrue( IP::isIPv6( '::0' ) );
00077         $this->assertTrue( IP::isIPv6( '::fc' ) );
00078         $this->assertTrue( IP::isIPv6( '::fc:100' ) );
00079         $this->assertTrue( IP::isIPv6( '::fc:100:a' ) );
00080         $this->assertTrue( IP::isIPv6( '::fc:100:a:d' ) );
00081         $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1' ) );
00082         $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1:e' ) );
00083         $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1:e:ac' ) );
00084 
00085         $this->assertFalse( IP::isIPv6( '::fc:100:a:d:1:e:ac:0' ), 'IPv6 with "::" and 8 words' );
00086         $this->assertFalse( IP::isIPv6( '::fc:100:a:d:1:e:ac:0:1' ), 'IPv6 with 9 words' );
00087 
00088         $this->assertFalse( IP::isIPv6( ':fc::100' ), 'IPv6 starting with lone ":"' );
00089         $this->assertFalse( IP::isIPv6( 'fc::100:' ), 'IPv6 ending with lone ":"' );
00090         $this->assertFalse( IP::isIPv6( 'fc:::100' ), 'IPv6 with ":::" in the middle' );
00091 
00092         $this->assertTrue( IP::isIPv6( 'fc::100' ), 'IPv6 with "::" and 2 words' );
00093         $this->assertTrue( IP::isIPv6( 'fc::100:a' ), 'IPv6 with "::" and 3 words' );
00094         $this->assertTrue( IP::isIPv6( 'fc::100:a:d', 'IPv6 with "::" and 4 words' ) );
00095         $this->assertTrue( IP::isIPv6( 'fc::100:a:d:1' ), 'IPv6 with "::" and 5 words' );
00096         $this->assertTrue( IP::isIPv6( 'fc::100:a:d:1:e' ), 'IPv6 with "::" and 6 words' );
00097         $this->assertTrue( IP::isIPv6( 'fc::100:a:d:1:e:ac' ), 'IPv6 with "::" and 7 words' );
00098         $this->assertTrue( IP::isIPv6( '2001::df' ), 'IPv6 with "::" and 2 words' );
00099         $this->assertTrue( IP::isIPv6( '2001:5c0:1400:a::df' ), 'IPv6 with "::" and 5 words' );
00100         $this->assertTrue( IP::isIPv6( '2001:5c0:1400:a::df:2' ), 'IPv6 with "::" and 6 words' );
00101 
00102         $this->assertFalse( IP::isIPv6( 'fc::100:a:d:1:e:ac:0' ), 'IPv6 with "::" and 8 words' );
00103         $this->assertFalse( IP::isIPv6( 'fc::100:a:d:1:e:ac:0:1' ), 'IPv6 with 9 words' );
00104 
00105         $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e:ac:0' ) );
00106     }
00107 
00111     public function testisIPv4() {
00112         $this->assertFalse( IP::isIPv4( false ), 'Boolean false is not an IP' );
00113         $this->assertFalse( IP::isIPv4( true ), 'Boolean true is not an IP' );
00114         $this->assertFalse( IP::isIPv4( "" ), 'Empty string is not an IP' );
00115         $this->assertFalse( IP::isIPv4( 'abc' ) );
00116         $this->assertFalse( IP::isIPv4( ':' ) );
00117         $this->assertFalse( IP::isIPv4( '124.24.52' ), 'IPv4 not enough quads' );
00118         $this->assertFalse( IP::isIPv4( '24.324.52.13' ), 'IPv4 out of range' );
00119         $this->assertFalse( IP::isIPv4( '.24.52.13' ), 'IPv4 starts with period' );
00120 
00121         $this->assertTrue( IP::isIPv4( '124.24.52.13' ) );
00122         $this->assertTrue( IP::isIPv4( '1.24.52.13' ) );
00123         $this->assertTrue( IP::isIPv4( '74.24.52.13/20', 'IPv4 range' ) );
00124     }
00125 
00129     public function testValidIPs() {
00130         foreach ( range( 0, 255 ) as $i ) {
00131             $a = sprintf( "%03d", $i );
00132             $b = sprintf( "%02d", $i );
00133             $c = sprintf( "%01d", $i );
00134             foreach ( array_unique( array( $a, $b, $c ) ) as $f ) {
00135                 $ip = "$f.$f.$f.$f";
00136                 $this->assertTrue( IP::isValid( $ip ), "$ip is a valid IPv4 address" );
00137             }
00138         }
00139         foreach ( range( 0x0, 0xFFFF, 0xF ) as $i ) {
00140             $a = sprintf( "%04x", $i );
00141             $b = sprintf( "%03x", $i );
00142             $c = sprintf( "%02x", $i );
00143             foreach ( array_unique( array( $a, $b, $c ) ) as $f ) {
00144                 $ip = "$f:$f:$f:$f:$f:$f:$f:$f";
00145                 $this->assertTrue( IP::isValid( $ip ), "$ip is a valid IPv6 address" );
00146             }
00147         }
00148         // test with some abbreviations
00149         $this->assertFalse( IP::isValid( ':fc:100::' ), 'IPv6 starting with lone ":"' );
00150         $this->assertFalse( IP::isValid( 'fc:100:::' ), 'IPv6 ending with a ":::"' );
00151         $this->assertFalse( IP::isValid( 'fc:300' ), 'IPv6 with only 2 words' );
00152         $this->assertFalse( IP::isValid( 'fc:100:300' ), 'IPv6 with only 3 words' );
00153 
00154         $this->assertTrue( IP::isValid( 'fc:100::' ) );
00155         $this->assertTrue( IP::isValid( 'fc:100:a:d:1:e::' ) );
00156         $this->assertTrue( IP::isValid( 'fc:100:a:d:1:e:ac::' ) );
00157 
00158         $this->assertTrue( IP::isValid( 'fc::100' ), 'IPv6 with "::" and 2 words' );
00159         $this->assertTrue( IP::isValid( 'fc::100:a' ), 'IPv6 with "::" and 3 words' );
00160         $this->assertTrue( IP::isValid( '2001::df' ), 'IPv6 with "::" and 2 words' );
00161         $this->assertTrue( IP::isValid( '2001:5c0:1400:a::df' ), 'IPv6 with "::" and 5 words' );
00162         $this->assertTrue( IP::isValid( '2001:5c0:1400:a::df:2' ), 'IPv6 with "::" and 6 words' );
00163         $this->assertTrue( IP::isValid( 'fc::100:a:d:1' ), 'IPv6 with "::" and 5 words' );
00164         $this->assertTrue( IP::isValid( 'fc::100:a:d:1:e:ac' ), 'IPv6 with "::" and 7 words' );
00165 
00166         $this->assertFalse(
00167             IP::isValid( 'fc:100:a:d:1:e:ac:0::' ),
00168             'IPv6 with 8 words ending with "::"'
00169         );
00170         $this->assertFalse(
00171             IP::isValid( 'fc:100:a:d:1:e:ac:0:1::' ),
00172             'IPv6 with 9 words ending with "::"'
00173         );
00174     }
00175 
00179     public function testInvalidIPs() {
00180         // Out of range...
00181         foreach ( range( 256, 999 ) as $i ) {
00182             $a = sprintf( "%03d", $i );
00183             $b = sprintf( "%02d", $i );
00184             $c = sprintf( "%01d", $i );
00185             foreach ( array_unique( array( $a, $b, $c ) ) as $f ) {
00186                 $ip = "$f.$f.$f.$f";
00187                 $this->assertFalse( IP::isValid( $ip ), "$ip is not a valid IPv4 address" );
00188             }
00189         }
00190         foreach ( range( 'g', 'z' ) as $i ) {
00191             $a = sprintf( "%04s", $i );
00192             $b = sprintf( "%03s", $i );
00193             $c = sprintf( "%02s", $i );
00194             foreach ( array_unique( array( $a, $b, $c ) ) as $f ) {
00195                 $ip = "$f:$f:$f:$f:$f:$f:$f:$f";
00196                 $this->assertFalse( IP::isValid( $ip ), "$ip is not a valid IPv6 address" );
00197             }
00198         }
00199         // Have CIDR
00200         $ipCIDRs = array(
00201             '212.35.31.121/32',
00202             '212.35.31.121/18',
00203             '212.35.31.121/24',
00204             '::ff:d:321:5/96',
00205             'ff::d3:321:5/116',
00206             'c:ff:12:1:ea:d:321:5/120',
00207         );
00208         foreach ( $ipCIDRs as $i ) {
00209             $this->assertFalse( IP::isValid( $i ),
00210                 "$i is an invalid IP address because it is a block" );
00211         }
00212         // Incomplete/garbage
00213         $invalid = array(
00214             'www.xn--var-xla.net',
00215             '216.17.184.G',
00216             '216.17.184.1.',
00217             '216.17.184',
00218             '216.17.184.',
00219             '256.17.184.1'
00220         );
00221         foreach ( $invalid as $i ) {
00222             $this->assertFalse( IP::isValid( $i ), "$i is an invalid IP address" );
00223         }
00224     }
00225 
00229     public function testValidBlocks() {
00230         $valid = array(
00231             '116.17.184.5/32',
00232             '0.17.184.5/30',
00233             '16.17.184.1/24',
00234             '30.242.52.14/1',
00235             '10.232.52.13/8',
00236             '30.242.52.14/0',
00237             '::e:f:2001/96',
00238             '::c:f:2001/128',
00239             '::10:f:2001/70',
00240             '::fe:f:2001/1',
00241             '::6d:f:2001/8',
00242             '::fe:f:2001/0',
00243         );
00244         foreach ( $valid as $i ) {
00245             $this->assertTrue( IP::isValidBlock( $i ), "$i is a valid IP block" );
00246         }
00247     }
00248 
00252     public function testInvalidBlocks() {
00253         $invalid = array(
00254             '116.17.184.5/33',
00255             '0.17.184.5/130',
00256             '16.17.184.1/-1',
00257             '10.232.52.13/*',
00258             '7.232.52.13/ab',
00259             '11.232.52.13/',
00260             '::e:f:2001/129',
00261             '::c:f:2001/228',
00262             '::10:f:2001/-1',
00263             '::6d:f:2001/*',
00264             '::86:f:2001/ab',
00265             '::23:f:2001/',
00266         );
00267         foreach ( $invalid as $i ) {
00268             $this->assertFalse( IP::isValidBlock( $i ), "$i is not a valid IP block" );
00269         }
00270     }
00271 
00276     public function testSanitizeIP() {
00277         $this->assertNull( IP::sanitizeIP( '' ) );
00278         $this->assertNull( IP::sanitizeIP( ' ' ) );
00279     }
00280 
00285     public function testToUnsigned( $expected, $input ) {
00286         $result = IP::toUnsigned( $input );
00287         $this->assertTrue( $result === false || is_string( $result ) || is_int( $result ) );
00288         $this->assertEquals( $expected, $result );
00289     }
00290 
00294     public static function provideToUnsigned() {
00295         return array(
00296             array( 1, '0.0.0.1' ),
00297             array( 16909060, '1.2.3.4' ),
00298             array( 2130706433, '127.0.0.1' ),
00299             array( '2147483648', '128.0.0.0' ),
00300             array( 2130706440, '127.0.0.08' ),
00301             array( 2130706441, '127.0.0.09' ),
00302             array( '3735931646', '222.173.202.254' ),
00303             array( pow( 2, 32 ) - 1, '255.255.255.255' ),
00304             array( false, 'IN.VA.LI.D' ),
00305             array( 1, '::1' ),
00306             array( '42540766452641154071740215577757643572', '2001:0db8:85a3:0000:0000:8a2e:0370:7334' ),
00307             array( '42540766452641154071740215577757643572', '2001:db8:85a3::8a2e:0370:7334' ),
00308             array( false, 'IN:VA::LI:D' ),
00309             array( false, ':::1' )
00310         );
00311     }
00312 
00317     public function testToHex( $expected, $input ) {
00318         $result = IP::toHex( $input );
00319         $this->assertTrue( $result === false || is_string( $result ) );
00320         $this->assertEquals( $expected, $result );
00321     }
00322 
00326     public static function provideToHex() {
00327         return array(
00328             array( '00000001', '0.0.0.1' ),
00329             array( '01020304', '1.2.3.4' ),
00330             array( '7F000001', '127.0.0.1' ),
00331             array( '80000000', '128.0.0.0' ),
00332             array( 'DEADCAFE', '222.173.202.254' ),
00333             array( 'FFFFFFFF', '255.255.255.255' ),
00334             array( false, 'IN.VA.LI.D' ),
00335             array( 'v6-00000000000000000000000000000001', '::1' ),
00336             array( 'v6-20010DB885A3000000008A2E03707334', '2001:0db8:85a3:0000:0000:8a2e:0370:7334' ),
00337             array( 'v6-20010DB885A3000000008A2E03707334', '2001:db8:85a3::8a2e:0370:7334' ),
00338             array( false, 'IN:VA::LI:D' ),
00339             array( false, ':::1' )
00340         );
00341     }
00342 
00346     public function testPrivateIPs() {
00347         $private = array( 'fc00::3', 'fc00::ff', '::1', '10.0.0.1', '172.16.0.1', '192.168.0.1' );
00348         foreach ( $private as $p ) {
00349             $this->assertFalse( IP::isPublic( $p ), "$p is not a public IP address" );
00350         }
00351         $public = array( '2001:5c0:1000:a::133', 'fc::3', '00FC::' );
00352         foreach ( $public as $p ) {
00353             $this->assertTrue( IP::isPublic( $p ), "$p is a public IP address" );
00354         }
00355     }
00356 
00357     // Private wrapper used to test CIDR Parsing.
00358     private function assertFalseCIDR( $CIDR, $msg = '' ) {
00359         $ff = array( false, false );
00360         $this->assertEquals( $ff, IP::parseCIDR( $CIDR ), $msg );
00361     }
00362 
00363     // Private wrapper to test network shifting using only dot notation
00364     private function assertNet( $expected, $CIDR ) {
00365         $parse = IP::parseCIDR( $CIDR );
00366         $this->assertEquals( $expected, long2ip( $parse[0] ), "network shifting $CIDR" );
00367     }
00368 
00372     public function testHexToQuad() {
00373         $this->assertEquals( '0.0.0.1', IP::hexToQuad( '00000001' ) );
00374         $this->assertEquals( '255.0.0.0', IP::hexToQuad( 'FF000000' ) );
00375         $this->assertEquals( '255.255.255.255', IP::hexToQuad( 'FFFFFFFF' ) );
00376         $this->assertEquals( '10.188.222.255', IP::hexToQuad( '0ABCDEFF' ) );
00377         // hex not left-padded...
00378         $this->assertEquals( '0.0.0.0', IP::hexToQuad( '0' ) );
00379         $this->assertEquals( '0.0.0.1', IP::hexToQuad( '1' ) );
00380         $this->assertEquals( '0.0.0.255', IP::hexToQuad( 'FF' ) );
00381         $this->assertEquals( '0.0.255.0', IP::hexToQuad( 'FF00' ) );
00382     }
00383 
00387     public function testHexToOctet() {
00388         $this->assertEquals( '0:0:0:0:0:0:0:1',
00389             IP::hexToOctet( '00000000000000000000000000000001' ) );
00390         $this->assertEquals( '0:0:0:0:0:0:FF:3',
00391             IP::hexToOctet( '00000000000000000000000000FF0003' ) );
00392         $this->assertEquals( '0:0:0:0:0:0:FF00:6',
00393             IP::hexToOctet( '000000000000000000000000FF000006' ) );
00394         $this->assertEquals( '0:0:0:0:0:0:FCCF:FAFF',
00395             IP::hexToOctet( '000000000000000000000000FCCFFAFF' ) );
00396         $this->assertEquals( 'FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',
00397             IP::hexToOctet( 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' ) );
00398         // hex not left-padded...
00399         $this->assertEquals( '0:0:0:0:0:0:0:0', IP::hexToOctet( '0' ) );
00400         $this->assertEquals( '0:0:0:0:0:0:0:1', IP::hexToOctet( '1' ) );
00401         $this->assertEquals( '0:0:0:0:0:0:0:FF', IP::hexToOctet( 'FF' ) );
00402         $this->assertEquals( '0:0:0:0:0:0:0:FFD0', IP::hexToOctet( 'FFD0' ) );
00403         $this->assertEquals( '0:0:0:0:0:0:FA00:0', IP::hexToOctet( 'FA000000' ) );
00404         $this->assertEquals( '0:0:0:0:0:0:FCCF:FAFF', IP::hexToOctet( 'FCCFFAFF' ) );
00405     }
00406 
00412     public function testCIDRParsing() {
00413         $this->assertFalseCIDR( '192.0.2.0', "missing mask" );
00414         $this->assertFalseCIDR( '192.0.2.0/', "missing bitmask" );
00415 
00416         // Verify if statement
00417         $this->assertFalseCIDR( '256.0.0.0/32', "invalid net" );
00418         $this->assertFalseCIDR( '192.0.2.0/AA', "mask not numeric" );
00419         $this->assertFalseCIDR( '192.0.2.0/-1', "mask < 0" );
00420         $this->assertFalseCIDR( '192.0.2.0/33', "mask > 32" );
00421 
00422         // Check internal logic
00423         # 0 mask always result in array(0,0)
00424         $this->assertEquals( array( 0, 0 ), IP::parseCIDR( '192.0.0.2/0' ) );
00425         $this->assertEquals( array( 0, 0 ), IP::parseCIDR( '0.0.0.0/0' ) );
00426         $this->assertEquals( array( 0, 0 ), IP::parseCIDR( '255.255.255.255/0' ) );
00427 
00428         // @todo FIXME: Add more tests.
00429 
00430         # This part test network shifting
00431         $this->assertNet( '192.0.0.0', '192.0.0.2/24' );
00432         $this->assertNet( '192.168.5.0', '192.168.5.13/24' );
00433         $this->assertNet( '10.0.0.160', '10.0.0.161/28' );
00434         $this->assertNet( '10.0.0.0', '10.0.0.3/28' );
00435         $this->assertNet( '10.0.0.0', '10.0.0.3/30' );
00436         $this->assertNet( '10.0.0.4', '10.0.0.4/30' );
00437         $this->assertNet( '172.17.32.0', '172.17.35.48/21' );
00438         $this->assertNet( '10.128.0.0', '10.135.0.0/9' );
00439         $this->assertNet( '134.0.0.0', '134.0.5.1/8' );
00440     }
00441 
00445     public function testIPCanonicalizeOnValidIp() {
00446         $this->assertEquals( '192.0.2.152', IP::canonicalize( '192.0.2.152' ),
00447             'Canonicalization of a valid IP returns it unchanged' );
00448     }
00449 
00453     public function testIPCanonicalizeMappedAddress() {
00454         $this->assertEquals(
00455             '192.0.2.152',
00456             IP::canonicalize( '::ffff:192.0.2.152' )
00457         );
00458         $this->assertEquals(
00459             '192.0.2.152',
00460             IP::canonicalize( '::192.0.2.152' )
00461         );
00462     }
00463 
00469     public function testIPIsInRange( $expected, $addr, $range, $message = '' ) {
00470         $this->assertEquals(
00471             $expected,
00472             IP::isInRange( $addr, $range ),
00473             $message
00474         );
00475     }
00476 
00478     public static function provideIPsAndRanges() {
00479         # Format: (expected boolean, address, range, optional message)
00480         return array(
00481             # IPv4
00482             array( true, '192.0.2.0', '192.0.2.0/24', 'Network address' ),
00483             array( true, '192.0.2.77', '192.0.2.0/24', 'Simple address' ),
00484             array( true, '192.0.2.255', '192.0.2.0/24', 'Broadcast address' ),
00485 
00486             array( false, '0.0.0.0', '192.0.2.0/24' ),
00487             array( false, '255.255.255', '192.0.2.0/24' ),
00488 
00489             # IPv6
00490             array( false, '::1', '2001:DB8::/32' ),
00491             array( false, '::', '2001:DB8::/32' ),
00492             array( false, 'FE80::1', '2001:DB8::/32' ),
00493 
00494             array( true, '2001:DB8::', '2001:DB8::/32' ),
00495             array( true, '2001:0DB8::', '2001:DB8::/32' ),
00496             array( true, '2001:DB8::1', '2001:DB8::/32' ),
00497             array( true, '2001:0DB8::1', '2001:DB8::/32' ),
00498             array( true, '2001:0DB8:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',
00499                 '2001:DB8::/32' ),
00500 
00501             array( false, '2001:0DB8:F::', '2001:DB8::/96' ),
00502         );
00503     }
00504 
00509     public function testSplitHostAndPort( $expected, $input, $description ) {
00510         $this->assertEquals( $expected, IP::splitHostAndPort( $input ), $description );
00511     }
00512 
00516     public static function provideSplitHostAndPort() {
00517         return array(
00518             array( false, '[', 'Unclosed square bracket' ),
00519             array( false, '[::', 'Unclosed square bracket 2' ),
00520             array( array( '::', false ), '::', 'Bare IPv6 0' ),
00521             array( array( '::1', false ), '::1', 'Bare IPv6 1' ),
00522             array( array( '::', false ), '[::]', 'Bracketed IPv6 0' ),
00523             array( array( '::1', false ), '[::1]', 'Bracketed IPv6 1' ),
00524             array( array( '::1', 80 ), '[::1]:80', 'Bracketed IPv6 with port' ),
00525             array( false, '::x', 'Double colon but no IPv6' ),
00526             array( array( 'x', 80 ), 'x:80', 'Hostname and port' ),
00527             array( false, 'x:x', 'Hostname and invalid port' ),
00528             array( array( 'x', false ), 'x', 'Plain hostname' )
00529         );
00530     }
00531 
00536     public function testCombineHostAndPort( $expected, $input, $description ) {
00537         list( $host, $port, $defaultPort ) = $input;
00538         $this->assertEquals(
00539             $expected,
00540             IP::combineHostAndPort( $host, $port, $defaultPort ),
00541             $description );
00542     }
00543 
00547     public static function provideCombineHostAndPort() {
00548         return array(
00549             array( '[::1]', array( '::1', 2, 2 ), 'IPv6 default port' ),
00550             array( '[::1]:2', array( '::1', 2, 3 ), 'IPv6 non-default port' ),
00551             array( 'x', array( 'x', 2, 2 ), 'Normal default port' ),
00552             array( 'x:2', array( 'x', 2, 3 ), 'Normal non-default port' ),
00553         );
00554     }
00555 
00560     public function testSanitizeRange( $input, $expected, $description ) {
00561         $this->assertEquals( $expected, IP::sanitizeRange( $input ), $description );
00562     }
00563 
00567     public static function provideIPCIDRs() {
00568         return array(
00569             array( '35.56.31.252/16', '35.56.0.0/16', 'IPv4 range' ),
00570             array( '135.16.21.252/24', '135.16.21.0/24', 'IPv4 range' ),
00571             array( '5.36.71.252/32', '5.36.71.252/32', 'IPv4 silly range' ),
00572             array( '5.36.71.252', '5.36.71.252', 'IPv4 non-range' ),
00573             array( '0:1:2:3:4:c5:f6:7/96', '0:1:2:3:4:C5:0:0/96', 'IPv6 range' ),
00574             array( '0:1:2:3:4:5:6:7/120', '0:1:2:3:4:5:6:0/120', 'IPv6 range' ),
00575             array( '0:e1:2:3:4:5:e6:7/128', '0:E1:2:3:4:5:E6:7/128', 'IPv6 silly range' ),
00576             array( '0:c1:A2:3:4:5:c6:7', '0:C1:A2:3:4:5:C6:7', 'IPv6 non range' ),
00577         );
00578     }
00579 
00584     public function testPrettifyIP( $ip, $prettified ) {
00585         $this->assertEquals( $prettified, IP::prettifyIP( $ip ), "Prettify of $ip" );
00586     }
00587 
00591     public static function provideIPsToPrettify() {
00592         return array(
00593             array( '0:0:0:0:0:0:0:0', '::' ),
00594             array( '0:0:0::0:0:0', '::' ),
00595             array( '0:0:0:1:0:0:0:0', '0:0:0:1::' ),
00596             array( '0:0::f', '::f' ),
00597             array( '0::0:0:0:33:fef:b', '::33:fef:b' ),
00598             array( '3f:535:0:0:0:0:e:fbb', '3f:535::e:fbb' ),
00599             array( '0:0:fef:0:0:0:e:fbb', '0:0:fef::e:fbb' ),
00600             array( 'abbc:2004::0:0:0:0', 'abbc:2004::' ),
00601             array( 'cebc:2004:f:0:0:0:0:0', 'cebc:2004:f::' ),
00602             array( '0:0:0:0:0:0:0:0/16', '::/16' ),
00603             array( '0:0:0::0:0:0/64', '::/64' ),
00604             array( '0:0::f/52', '::f/52' ),
00605             array( '::0:0:33:fef:b/52', '::33:fef:b/52' ),
00606             array( '3f:535:0:0:0:0:e:fbb/48', '3f:535::e:fbb/48' ),
00607             array( '0:0:fef:0:0:0:e:fbb/96', '0:0:fef::e:fbb/96' ),
00608             array( 'abbc:2004:0:0::0:0/40', 'abbc:2004::/40' ),
00609             array( 'aebc:2004:f:0:0:0:0:0/80', 'aebc:2004:f::/80' ),
00610         );
00611     }
00612 }