Merge "Allow overriding the resultSetType reported via event logging of suggestions"
[lhc/web/wiklou.git] / tests / phpunit / includes / utils / IPTest.php
1 <?php
2 /**
3 * Tests for IP validity functions.
4 *
5 * Ported from /t/inc/IP.t by avar.
6 *
7 * @group IP
8 * @todo Test methods in this call should be split into a method and a
9 * dataprovider.
10 */
11
12 class IPTest extends PHPUnit_Framework_TestCase {
13 /**
14 * @covers IP::isIPAddress
15 * @dataProvider provideInvalidIPs
16 */
17 public function isNotIPAddress( $val, $desc ) {
18 $this->assertFalse( IP::isIPAddress( $val ), $desc );
19 }
20
21 /**
22 * Provide a list of things that aren't IP addresses
23 */
24 public function provideInvalidIPs() {
25 return array(
26 array( false, 'Boolean false is not an IP' ),
27 array( true, 'Boolean true is not an IP' ),
28 array( '', 'Empty string is not an IP' ),
29 array( 'abc', 'Garbage IP string' ),
30 array( ':', 'Single ":" is not an IP' ),
31 array( '2001:0DB8::A:1::1', 'IPv6 with a double :: occurrence' ),
32 array( '2001:0DB8::A:1::', 'IPv6 with a double :: occurrence, last at end' ),
33 array( '::2001:0DB8::5:1', 'IPv6 with a double :: occurrence, firt at beginning' ),
34 array( '124.24.52', 'IPv4 not enough quads' ),
35 array( '24.324.52.13', 'IPv4 out of range' ),
36 array( '.24.52.13', 'IPv4 starts with period' ),
37 array( 'fc:100:300', 'IPv6 with only 3 words' ),
38 );
39 }
40
41 /**
42 * @covers IP::isIPAddress
43 */
44 public function testisIPAddress() {
45 $this->assertTrue( IP::isIPAddress( '::' ), 'RFC 4291 IPv6 Unspecified Address' );
46 $this->assertTrue( IP::isIPAddress( '::1' ), 'RFC 4291 IPv6 Loopback Address' );
47 $this->assertTrue( IP::isIPAddress( '74.24.52.13/20', 'IPv4 range' ) );
48 $this->assertTrue( IP::isIPAddress( 'fc:100:a:d:1:e:ac:0/24' ), 'IPv6 range' );
49 $this->assertTrue( IP::isIPAddress( 'fc::100:a:d:1:e:ac/96' ), 'IPv6 range with "::"' );
50
51 $validIPs = array( 'fc:100::', 'fc:100:a:d:1:e:ac::', 'fc::100', '::fc:100:a:d:1:e:ac',
52 '::fc', 'fc::100:a:d:1:e:ac', 'fc:100:a:d:1:e:ac:0', '124.24.52.13', '1.24.52.13' );
53 foreach ( $validIPs as $ip ) {
54 $this->assertTrue( IP::isIPAddress( $ip ), "$ip is a valid IP address" );
55 }
56 }
57
58 /**
59 * @covers IP::isIPv6
60 */
61 public function testisIPv6() {
62 $this->assertFalse( IP::isIPv6( ':fc:100::' ), 'IPv6 starting with lone ":"' );
63 $this->assertFalse( IP::isIPv6( 'fc:100:::' ), 'IPv6 ending with a ":::"' );
64 $this->assertFalse( IP::isIPv6( 'fc:300' ), 'IPv6 with only 2 words' );
65 $this->assertFalse( IP::isIPv6( 'fc:100:300' ), 'IPv6 with only 3 words' );
66
67 $this->assertTrue( IP::isIPv6( 'fc:100::' ) );
68 $this->assertTrue( IP::isIPv6( 'fc:100:a::' ) );
69 $this->assertTrue( IP::isIPv6( 'fc:100:a:d::' ) );
70 $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1::' ) );
71 $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e::' ) );
72 $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e:ac::' ) );
73
74 $this->assertFalse( IP::isIPv6( 'fc:100:a:d:1:e:ac:0::' ), 'IPv6 with 8 words ending with "::"' );
75 $this->assertFalse(
76 IP::isIPv6( 'fc:100:a:d:1:e:ac:0:1::' ),
77 'IPv6 with 9 words ending with "::"'
78 );
79
80 $this->assertFalse( IP::isIPv6( ':::' ) );
81 $this->assertFalse( IP::isIPv6( '::0:' ), 'IPv6 ending in a lone ":"' );
82
83 $this->assertTrue( IP::isIPv6( '::' ), 'IPv6 zero address' );
84 $this->assertTrue( IP::isIPv6( '::0' ) );
85 $this->assertTrue( IP::isIPv6( '::fc' ) );
86 $this->assertTrue( IP::isIPv6( '::fc:100' ) );
87 $this->assertTrue( IP::isIPv6( '::fc:100:a' ) );
88 $this->assertTrue( IP::isIPv6( '::fc:100:a:d' ) );
89 $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1' ) );
90 $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1:e' ) );
91 $this->assertTrue( IP::isIPv6( '::fc:100:a:d:1:e:ac' ) );
92
93 $this->assertFalse( IP::isIPv6( '::fc:100:a:d:1:e:ac:0' ), 'IPv6 with "::" and 8 words' );
94 $this->assertFalse( IP::isIPv6( '::fc:100:a:d:1:e:ac:0:1' ), 'IPv6 with 9 words' );
95
96 $this->assertFalse( IP::isIPv6( ':fc::100' ), 'IPv6 starting with lone ":"' );
97 $this->assertFalse( IP::isIPv6( 'fc::100:' ), 'IPv6 ending with lone ":"' );
98 $this->assertFalse( IP::isIPv6( 'fc:::100' ), 'IPv6 with ":::" in the middle' );
99
100 $this->assertTrue( IP::isIPv6( 'fc::100' ), 'IPv6 with "::" and 2 words' );
101 $this->assertTrue( IP::isIPv6( 'fc::100:a' ), 'IPv6 with "::" and 3 words' );
102 $this->assertTrue( IP::isIPv6( 'fc::100:a:d', 'IPv6 with "::" and 4 words' ) );
103 $this->assertTrue( IP::isIPv6( 'fc::100:a:d:1' ), 'IPv6 with "::" and 5 words' );
104 $this->assertTrue( IP::isIPv6( 'fc::100:a:d:1:e' ), 'IPv6 with "::" and 6 words' );
105 $this->assertTrue( IP::isIPv6( 'fc::100:a:d:1:e:ac' ), 'IPv6 with "::" and 7 words' );
106 $this->assertTrue( IP::isIPv6( '2001::df' ), 'IPv6 with "::" and 2 words' );
107 $this->assertTrue( IP::isIPv6( '2001:5c0:1400:a::df' ), 'IPv6 with "::" and 5 words' );
108 $this->assertTrue( IP::isIPv6( '2001:5c0:1400:a::df:2' ), 'IPv6 with "::" and 6 words' );
109
110 $this->assertFalse( IP::isIPv6( 'fc::100:a:d:1:e:ac:0' ), 'IPv6 with "::" and 8 words' );
111 $this->assertFalse( IP::isIPv6( 'fc::100:a:d:1:e:ac:0:1' ), 'IPv6 with 9 words' );
112
113 $this->assertTrue( IP::isIPv6( 'fc:100:a:d:1:e:ac:0' ) );
114 }
115
116 /**
117 * @covers IP::isIPv4
118 * @dataProvider provideInvalidIPv4Addresses
119 */
120 public function testisNotIPv4( $bogusIP, $desc ) {
121 $this->assertFalse( IP::isIPv4( $bogusIP ), $desc );
122 }
123
124 public function provideInvalidIPv4Addresses() {
125 return array(
126 array( false, 'Boolean false is not an IP' ),
127 array( true, 'Boolean true is not an IP' ),
128 array( '', 'Empty string is not an IP' ),
129 array( 'abc', 'Letters are not an IP' ),
130 array( ':', 'A colon is not an IP' ),
131 array( '124.24.52', 'IPv4 not enough quads' ),
132 array( '24.324.52.13', 'IPv4 out of range' ),
133 array( '.24.52.13', 'IPv4 starts with period' ),
134 );
135 }
136
137 /**
138 * @covers IP::isIPv4
139 * @dataProvider provideValidIPv4Address
140 */
141 public function testIsIPv4( $ip, $desc ) {
142 $this->assertTrue( IP::isIPv4( $ip ), $desc );
143 }
144
145 /**
146 * Provide some IPv4 addresses and ranges
147 */
148 public function provideValidIPv4Address() {
149 return array(
150 array( '124.24.52.13', 'Valid IPv4 address' ),
151 array( '1.24.52.13', 'Another valid IPv4 address' ),
152 array( '74.24.52.13/20', 'An IPv4 range' ),
153 );
154 }
155
156 /**
157 * @covers IP::isValid
158 */
159 public function testValidIPs() {
160 foreach ( range( 0, 255 ) as $i ) {
161 $a = sprintf( "%03d", $i );
162 $b = sprintf( "%02d", $i );
163 $c = sprintf( "%01d", $i );
164 foreach ( array_unique( array( $a, $b, $c ) ) as $f ) {
165 $ip = "$f.$f.$f.$f";
166 $this->assertTrue( IP::isValid( $ip ), "$ip is a valid IPv4 address" );
167 }
168 }
169 foreach ( range( 0x0, 0xFFFF, 0xF ) as $i ) {
170 $a = sprintf( "%04x", $i );
171 $b = sprintf( "%03x", $i );
172 $c = sprintf( "%02x", $i );
173 foreach ( array_unique( array( $a, $b, $c ) ) as $f ) {
174 $ip = "$f:$f:$f:$f:$f:$f:$f:$f";
175 $this->assertTrue( IP::isValid( $ip ), "$ip is a valid IPv6 address" );
176 }
177 }
178 // test with some abbreviations
179 $this->assertFalse( IP::isValid( ':fc:100::' ), 'IPv6 starting with lone ":"' );
180 $this->assertFalse( IP::isValid( 'fc:100:::' ), 'IPv6 ending with a ":::"' );
181 $this->assertFalse( IP::isValid( 'fc:300' ), 'IPv6 with only 2 words' );
182 $this->assertFalse( IP::isValid( 'fc:100:300' ), 'IPv6 with only 3 words' );
183
184 $this->assertTrue( IP::isValid( 'fc:100::' ) );
185 $this->assertTrue( IP::isValid( 'fc:100:a:d:1:e::' ) );
186 $this->assertTrue( IP::isValid( 'fc:100:a:d:1:e:ac::' ) );
187
188 $this->assertTrue( IP::isValid( 'fc::100' ), 'IPv6 with "::" and 2 words' );
189 $this->assertTrue( IP::isValid( 'fc::100:a' ), 'IPv6 with "::" and 3 words' );
190 $this->assertTrue( IP::isValid( '2001::df' ), 'IPv6 with "::" and 2 words' );
191 $this->assertTrue( IP::isValid( '2001:5c0:1400:a::df' ), 'IPv6 with "::" and 5 words' );
192 $this->assertTrue( IP::isValid( '2001:5c0:1400:a::df:2' ), 'IPv6 with "::" and 6 words' );
193 $this->assertTrue( IP::isValid( 'fc::100:a:d:1' ), 'IPv6 with "::" and 5 words' );
194 $this->assertTrue( IP::isValid( 'fc::100:a:d:1:e:ac' ), 'IPv6 with "::" and 7 words' );
195
196 $this->assertFalse(
197 IP::isValid( 'fc:100:a:d:1:e:ac:0::' ),
198 'IPv6 with 8 words ending with "::"'
199 );
200 $this->assertFalse(
201 IP::isValid( 'fc:100:a:d:1:e:ac:0:1::' ),
202 'IPv6 with 9 words ending with "::"'
203 );
204 }
205
206 /**
207 * @covers IP::isValid
208 */
209 public function testInvalidIPs() {
210 // Out of range...
211 foreach ( range( 256, 999 ) as $i ) {
212 $a = sprintf( "%03d", $i );
213 $b = sprintf( "%02d", $i );
214 $c = sprintf( "%01d", $i );
215 foreach ( array_unique( array( $a, $b, $c ) ) as $f ) {
216 $ip = "$f.$f.$f.$f";
217 $this->assertFalse( IP::isValid( $ip ), "$ip is not a valid IPv4 address" );
218 }
219 }
220 foreach ( range( 'g', 'z' ) as $i ) {
221 $a = sprintf( "%04s", $i );
222 $b = sprintf( "%03s", $i );
223 $c = sprintf( "%02s", $i );
224 foreach ( array_unique( array( $a, $b, $c ) ) as $f ) {
225 $ip = "$f:$f:$f:$f:$f:$f:$f:$f";
226 $this->assertFalse( IP::isValid( $ip ), "$ip is not a valid IPv6 address" );
227 }
228 }
229 // Have CIDR
230 $ipCIDRs = array(
231 '212.35.31.121/32',
232 '212.35.31.121/18',
233 '212.35.31.121/24',
234 '::ff:d:321:5/96',
235 'ff::d3:321:5/116',
236 'c:ff:12:1:ea:d:321:5/120',
237 );
238 foreach ( $ipCIDRs as $i ) {
239 $this->assertFalse( IP::isValid( $i ),
240 "$i is an invalid IP address because it is a block" );
241 }
242 // Incomplete/garbage
243 $invalid = array(
244 'www.xn--var-xla.net',
245 '216.17.184.G',
246 '216.17.184.1.',
247 '216.17.184',
248 '216.17.184.',
249 '256.17.184.1'
250 );
251 foreach ( $invalid as $i ) {
252 $this->assertFalse( IP::isValid( $i ), "$i is an invalid IP address" );
253 }
254 }
255
256 /**
257 * Provide some valid IP blocks
258 */
259 public function provideValidBlocks() {
260 return array(
261 array( '116.17.184.5/32' ),
262 array( '0.17.184.5/30' ),
263 array( '16.17.184.1/24' ),
264 array( '30.242.52.14/1' ),
265 array( '10.232.52.13/8' ),
266 array( '30.242.52.14/0' ),
267 array( '::e:f:2001/96' ),
268 array( '::c:f:2001/128' ),
269 array( '::10:f:2001/70' ),
270 array( '::fe:f:2001/1' ),
271 array( '::6d:f:2001/8' ),
272 array( '::fe:f:2001/0' ),
273 );
274 }
275
276 /**
277 * @covers IP::isValidBlock
278 * @dataProvider provideValidBlocks
279 */
280 public function testValidBlocks( $block ) {
281 $this->assertTrue( IP::isValidBlock( $block ), "$block is a valid IP block" );
282 }
283
284 /**
285 * @covers IP::isValidBlock
286 * @dataProvider provideInvalidBlocks
287 */
288 public function testInvalidBlocks( $invalid ) {
289 $this->assertFalse( IP::isValidBlock( $invalid ), "$invalid is not a valid IP block" );
290 }
291
292 public function provideInvalidBlocks() {
293 return array(
294 array( '116.17.184.5/33' ),
295 array( '0.17.184.5/130' ),
296 array( '16.17.184.1/-1' ),
297 array( '10.232.52.13/*' ),
298 array( '7.232.52.13/ab' ),
299 array( '11.232.52.13/' ),
300 array( '::e:f:2001/129' ),
301 array( '::c:f:2001/228' ),
302 array( '::10:f:2001/-1' ),
303 array( '::6d:f:2001/*' ),
304 array( '::86:f:2001/ab' ),
305 array( '::23:f:2001/' ),
306 );
307 }
308
309 /**
310 * @covers IP::sanitizeIP
311 * @dataProvider provideSanitizeIP
312 */
313 public function testSanitizeIP( $expected, $input ) {
314 $result = IP::sanitizeIP( $input );
315 $this->assertEquals( $expected, $result );
316 }
317
318 /**
319 * Provider for IP::testSanitizeIP()
320 */
321 public static function provideSanitizeIP() {
322 return array(
323 array( '0.0.0.0', '0.0.0.0' ),
324 array( '0.0.0.0', '00.00.00.00' ),
325 array( '0.0.0.0', '000.000.000.000' ),
326 array( '141.0.11.253', '141.000.011.253' ),
327 array( '1.2.4.5', '1.2.4.5' ),
328 array( '1.2.4.5', '01.02.04.05' ),
329 array( '1.2.4.5', '001.002.004.005' ),
330 array( '10.0.0.1', '010.0.000.1' ),
331 array( '80.72.250.4', '080.072.250.04' ),
332 array( 'Foo.1000.00', 'Foo.1000.00' ),
333 array( 'Bar.01', 'Bar.01' ),
334 array( 'Bar.010', 'Bar.010' ),
335 array( null, '' ),
336 array( null, ' ' )
337 );
338 }
339
340 /**
341 * @covers IP::toHex
342 * @dataProvider provideToHex
343 */
344 public function testToHex( $expected, $input ) {
345 $result = IP::toHex( $input );
346 $this->assertTrue( $result === false || is_string( $result ) );
347 $this->assertEquals( $expected, $result );
348 }
349
350 /**
351 * Provider for IP::testToHex()
352 */
353 public static function provideToHex() {
354 return array(
355 array( '00000001', '0.0.0.1' ),
356 array( '01020304', '1.2.3.4' ),
357 array( '7F000001', '127.0.0.1' ),
358 array( '80000000', '128.0.0.0' ),
359 array( 'DEADCAFE', '222.173.202.254' ),
360 array( 'FFFFFFFF', '255.255.255.255' ),
361 array( '8D000BFD', '141.000.11.253' ),
362 array( false, 'IN.VA.LI.D' ),
363 array( 'v6-00000000000000000000000000000001', '::1' ),
364 array( 'v6-20010DB885A3000000008A2E03707334', '2001:0db8:85a3:0000:0000:8a2e:0370:7334' ),
365 array( 'v6-20010DB885A3000000008A2E03707334', '2001:db8:85a3::8a2e:0370:7334' ),
366 array( false, 'IN:VA::LI:D' ),
367 array( false, ':::1' )
368 );
369 }
370
371 /**
372 * @covers IP::isPublic
373 * @dataProvider provideIsPublic
374 */
375 public function testIsPublic( $expected, $input ) {
376 $result = IP::isPublic( $input );
377 $this->assertEquals( $expected, $result );
378 }
379
380 /**
381 * Provider for IP::testIsPublic()
382 */
383 public static function provideIsPublic() {
384 return array(
385 array( false, 'fc00::3' ), # RFC 4193 (local)
386 array( false, 'fc00::ff' ), # RFC 4193 (local)
387 array( false, '127.1.2.3' ), # loopback
388 array( false, '::1' ), # loopback
389 array( false, 'fe80::1' ), # link-local
390 array( false, '169.254.1.1' ), # link-local
391 array( false, '10.0.0.1' ), # RFC 1918 (private)
392 array( false, '172.16.0.1' ), # RFC 1918 (private)
393 array( false, '192.168.0.1' ), # RFC 1918 (private)
394 array( true, '2001:5c0:1000:a::133' ), # public
395 array( true, 'fc::3' ), # public
396 array( true, '00FC::' ) # public
397 );
398 }
399
400 // Private wrapper used to test CIDR Parsing.
401 private function assertFalseCIDR( $CIDR, $msg = '' ) {
402 $ff = array( false, false );
403 $this->assertEquals( $ff, IP::parseCIDR( $CIDR ), $msg );
404 }
405
406 // Private wrapper to test network shifting using only dot notation
407 private function assertNet( $expected, $CIDR ) {
408 $parse = IP::parseCIDR( $CIDR );
409 $this->assertEquals( $expected, long2ip( $parse[0] ), "network shifting $CIDR" );
410 }
411
412 /**
413 * @covers IP::hexToQuad
414 * @dataProvider provideIPsAndHexes
415 */
416 public function testHexToQuad( $ip, $hex ) {
417 $this->assertEquals( $ip, IP::hexToQuad( $hex ) );
418 }
419
420 /**
421 * Provide some IP addresses and their equivalent hex representations
422 */
423 public function provideIPsandHexes() {
424 return array(
425 array( '0.0.0.1', '00000001' ),
426 array( '255.0.0.0', 'FF000000' ),
427 array( '255.255.255.255', 'FFFFFFFF' ),
428 array( '10.188.222.255', '0ABCDEFF' ),
429 // hex not left-padded...
430 array( '0.0.0.0', '0' ),
431 array( '0.0.0.1', '1' ),
432 array( '0.0.0.255', 'FF' ),
433 array( '0.0.255.0', 'FF00' ),
434 );
435 }
436
437 /**
438 * @covers IP::hexToOctet
439 * @dataProvider provideOctetsAndHexes
440 */
441 public function testHexToOctet( $octet, $hex ) {
442 $this->assertEquals( $octet, IP::hexToOctet( $hex ) );
443 }
444
445 /**
446 * Provide some hex and octet representations of the same IPs
447 */
448 public function provideOctetsAndHexes() {
449 return array(
450 array( '0:0:0:0:0:0:0:1', '00000000000000000000000000000001' ),
451 array( '0:0:0:0:0:0:FF:3', '00000000000000000000000000FF0003' ),
452 array( '0:0:0:0:0:0:FF00:6', '000000000000000000000000FF000006' ),
453 array( '0:0:0:0:0:0:FCCF:FAFF', '000000000000000000000000FCCFFAFF' ),
454 array( 'FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF', 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF' ),
455 // hex not left-padded...
456 array( '0:0:0:0:0:0:0:0', '0' ),
457 array( '0:0:0:0:0:0:0:1', '1' ),
458 array( '0:0:0:0:0:0:0:FF', 'FF' ),
459 array( '0:0:0:0:0:0:0:FFD0', 'FFD0' ),
460 array( '0:0:0:0:0:0:FA00:0', 'FA000000' ),
461 array( '0:0:0:0:0:0:FCCF:FAFF', 'FCCFFAFF' ),
462 );
463 }
464
465 /**
466 * IP::parseCIDR() returns an array containing a signed IP address
467 * representing the network mask and the bit mask.
468 * @covers IP::parseCIDR
469 */
470 public function testCIDRParsing() {
471 $this->assertFalseCIDR( '192.0.2.0', "missing mask" );
472 $this->assertFalseCIDR( '192.0.2.0/', "missing bitmask" );
473
474 // Verify if statement
475 $this->assertFalseCIDR( '256.0.0.0/32', "invalid net" );
476 $this->assertFalseCIDR( '192.0.2.0/AA', "mask not numeric" );
477 $this->assertFalseCIDR( '192.0.2.0/-1', "mask < 0" );
478 $this->assertFalseCIDR( '192.0.2.0/33', "mask > 32" );
479
480 // Check internal logic
481 # 0 mask always result in array(0,0)
482 $this->assertEquals( array( 0, 0 ), IP::parseCIDR( '192.0.0.2/0' ) );
483 $this->assertEquals( array( 0, 0 ), IP::parseCIDR( '0.0.0.0/0' ) );
484 $this->assertEquals( array( 0, 0 ), IP::parseCIDR( '255.255.255.255/0' ) );
485
486 // @todo FIXME: Add more tests.
487
488 # This part test network shifting
489 $this->assertNet( '192.0.0.0', '192.0.0.2/24' );
490 $this->assertNet( '192.168.5.0', '192.168.5.13/24' );
491 $this->assertNet( '10.0.0.160', '10.0.0.161/28' );
492 $this->assertNet( '10.0.0.0', '10.0.0.3/28' );
493 $this->assertNet( '10.0.0.0', '10.0.0.3/30' );
494 $this->assertNet( '10.0.0.4', '10.0.0.4/30' );
495 $this->assertNet( '172.17.32.0', '172.17.35.48/21' );
496 $this->assertNet( '10.128.0.0', '10.135.0.0/9' );
497 $this->assertNet( '134.0.0.0', '134.0.5.1/8' );
498 }
499
500 /**
501 * @covers IP::canonicalize
502 */
503 public function testIPCanonicalizeOnValidIp() {
504 $this->assertEquals( '192.0.2.152', IP::canonicalize( '192.0.2.152' ),
505 'Canonicalization of a valid IP returns it unchanged' );
506 }
507
508 /**
509 * @covers IP::canonicalize
510 */
511 public function testIPCanonicalizeMappedAddress() {
512 $this->assertEquals(
513 '192.0.2.152',
514 IP::canonicalize( '::ffff:192.0.2.152' )
515 );
516 $this->assertEquals(
517 '192.0.2.152',
518 IP::canonicalize( '::192.0.2.152' )
519 );
520 }
521
522 /**
523 * Issues there are most probably from IP::toHex() or IP::parseRange()
524 * @covers IP::isInRange
525 * @dataProvider provideIPsAndRanges
526 */
527 public function testIPIsInRange( $expected, $addr, $range, $message = '' ) {
528 $this->assertEquals(
529 $expected,
530 IP::isInRange( $addr, $range ),
531 $message
532 );
533 }
534
535 /** Provider for testIPIsInRange() */
536 public static function provideIPsAndRanges() {
537 # Format: (expected boolean, address, range, optional message)
538 return array(
539 # IPv4
540 array( true, '192.0.2.0', '192.0.2.0/24', 'Network address' ),
541 array( true, '192.0.2.77', '192.0.2.0/24', 'Simple address' ),
542 array( true, '192.0.2.255', '192.0.2.0/24', 'Broadcast address' ),
543
544 array( false, '0.0.0.0', '192.0.2.0/24' ),
545 array( false, '255.255.255', '192.0.2.0/24' ),
546
547 # IPv6
548 array( false, '::1', '2001:DB8::/32' ),
549 array( false, '::', '2001:DB8::/32' ),
550 array( false, 'FE80::1', '2001:DB8::/32' ),
551
552 array( true, '2001:DB8::', '2001:DB8::/32' ),
553 array( true, '2001:0DB8::', '2001:DB8::/32' ),
554 array( true, '2001:DB8::1', '2001:DB8::/32' ),
555 array( true, '2001:0DB8::1', '2001:DB8::/32' ),
556 array( true, '2001:0DB8:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF',
557 '2001:DB8::/32' ),
558
559 array( false, '2001:0DB8:F::', '2001:DB8::/96' ),
560 );
561 }
562
563 /**
564 * Test for IP::splitHostAndPort().
565 * @dataProvider provideSplitHostAndPort
566 */
567 public function testSplitHostAndPort( $expected, $input, $description ) {
568 $this->assertEquals( $expected, IP::splitHostAndPort( $input ), $description );
569 }
570
571 /**
572 * Provider for IP::splitHostAndPort()
573 */
574 public static function provideSplitHostAndPort() {
575 return array(
576 array( false, '[', 'Unclosed square bracket' ),
577 array( false, '[::', 'Unclosed square bracket 2' ),
578 array( array( '::', false ), '::', 'Bare IPv6 0' ),
579 array( array( '::1', false ), '::1', 'Bare IPv6 1' ),
580 array( array( '::', false ), '[::]', 'Bracketed IPv6 0' ),
581 array( array( '::1', false ), '[::1]', 'Bracketed IPv6 1' ),
582 array( array( '::1', 80 ), '[::1]:80', 'Bracketed IPv6 with port' ),
583 array( false, '::x', 'Double colon but no IPv6' ),
584 array( array( 'x', 80 ), 'x:80', 'Hostname and port' ),
585 array( false, 'x:x', 'Hostname and invalid port' ),
586 array( array( 'x', false ), 'x', 'Plain hostname' )
587 );
588 }
589
590 /**
591 * Test for IP::combineHostAndPort()
592 * @dataProvider provideCombineHostAndPort
593 */
594 public function testCombineHostAndPort( $expected, $input, $description ) {
595 list( $host, $port, $defaultPort ) = $input;
596 $this->assertEquals(
597 $expected,
598 IP::combineHostAndPort( $host, $port, $defaultPort ),
599 $description );
600 }
601
602 /**
603 * Provider for IP::combineHostAndPort()
604 */
605 public static function provideCombineHostAndPort() {
606 return array(
607 array( '[::1]', array( '::1', 2, 2 ), 'IPv6 default port' ),
608 array( '[::1]:2', array( '::1', 2, 3 ), 'IPv6 non-default port' ),
609 array( 'x', array( 'x', 2, 2 ), 'Normal default port' ),
610 array( 'x:2', array( 'x', 2, 3 ), 'Normal non-default port' ),
611 );
612 }
613
614 /**
615 * Test for IP::sanitizeRange()
616 * @dataProvider provideIPCIDRs
617 */
618 public function testSanitizeRange( $input, $expected, $description ) {
619 $this->assertEquals( $expected, IP::sanitizeRange( $input ), $description );
620 }
621
622 /**
623 * Provider for IP::testSanitizeRange()
624 */
625 public static function provideIPCIDRs() {
626 return array(
627 array( '35.56.31.252/16', '35.56.0.0/16', 'IPv4 range' ),
628 array( '135.16.21.252/24', '135.16.21.0/24', 'IPv4 range' ),
629 array( '5.36.71.252/32', '5.36.71.252/32', 'IPv4 silly range' ),
630 array( '5.36.71.252', '5.36.71.252', 'IPv4 non-range' ),
631 array( '0:1:2:3:4:c5:f6:7/96', '0:1:2:3:4:C5:0:0/96', 'IPv6 range' ),
632 array( '0:1:2:3:4:5:6:7/120', '0:1:2:3:4:5:6:0/120', 'IPv6 range' ),
633 array( '0:e1:2:3:4:5:e6:7/128', '0:E1:2:3:4:5:E6:7/128', 'IPv6 silly range' ),
634 array( '0:c1:A2:3:4:5:c6:7', '0:C1:A2:3:4:5:C6:7', 'IPv6 non range' ),
635 );
636 }
637
638 /**
639 * Test for IP::prettifyIP()
640 * @dataProvider provideIPsToPrettify
641 */
642 public function testPrettifyIP( $ip, $prettified ) {
643 $this->assertEquals( $prettified, IP::prettifyIP( $ip ), "Prettify of $ip" );
644 }
645
646 /**
647 * Provider for IP::testPrettifyIP()
648 */
649 public static function provideIPsToPrettify() {
650 return array(
651 array( '0:0:0:0:0:0:0:0', '::' ),
652 array( '0:0:0::0:0:0', '::' ),
653 array( '0:0:0:1:0:0:0:0', '0:0:0:1::' ),
654 array( '0:0::f', '::f' ),
655 array( '0::0:0:0:33:fef:b', '::33:fef:b' ),
656 array( '3f:535:0:0:0:0:e:fbb', '3f:535::e:fbb' ),
657 array( '0:0:fef:0:0:0:e:fbb', '0:0:fef::e:fbb' ),
658 array( 'abbc:2004::0:0:0:0', 'abbc:2004::' ),
659 array( 'cebc:2004:f:0:0:0:0:0', 'cebc:2004:f::' ),
660 array( '0:0:0:0:0:0:0:0/16', '::/16' ),
661 array( '0:0:0::0:0:0/64', '::/64' ),
662 array( '0:0::f/52', '::f/52' ),
663 array( '::0:0:33:fef:b/52', '::33:fef:b/52' ),
664 array( '3f:535:0:0:0:0:e:fbb/48', '3f:535::e:fbb/48' ),
665 array( '0:0:fef:0:0:0:e:fbb/96', '0:0:fef::e:fbb/96' ),
666 array( 'abbc:2004:0:0::0:0/40', 'abbc:2004::/40' ),
667 array( 'aebc:2004:f:0:0:0:0:0/80', 'aebc:2004:f::/80' ),
668 );
669 }
670 }