3cb42f126d64c55dc3dfdf7679e4f4a34bfd6b13
[lhc/web/wiklou.git] / tests / phpunit / includes / GlobalFunctions / GlobalTest.php
1 <?php
2
3 class GlobalTest extends MediaWikiTestCase {
4 function setUp() {
5 global $wgReadOnlyFile, $wgUrlProtocols;
6 $this->originals['wgReadOnlyFile'] = $wgReadOnlyFile;
7 $this->originals['wgUrlProtocols'] = $wgUrlProtocols;
8 $wgReadOnlyFile = tempnam( wfTempDir(), "mwtest_readonly" );
9 $wgUrlProtocols[] = 'file://';
10 unlink( $wgReadOnlyFile );
11 }
12
13 function tearDown() {
14 global $wgReadOnlyFile, $wgUrlProtocols;
15 if ( file_exists( $wgReadOnlyFile ) ) {
16 unlink( $wgReadOnlyFile );
17 }
18 $wgReadOnlyFile = $this->originals['wgReadOnlyFile'];
19 $wgUrlProtocols = $this->originals['wgUrlProtocols'];
20 }
21
22 /** @dataProvider provideForWfArrayDiff2 */
23 public function testWfArrayDiff2( $a, $b, $expected ) {
24 $this->assertEquals(
25 wfArrayDiff2( $a, $b), $expected
26 );
27 }
28
29 // @todo Provide more tests
30 public function provideForWfArrayDiff2() {
31 // $a $b $expected
32 return array(
33 array(
34 array( 'a', 'b'),
35 array( 'a', 'b'),
36 array(),
37 ),
38 array(
39 array( array( 'a'), array( 'a', 'b', 'c' )),
40 array( array( 'a'), array( 'a', 'b' )),
41 array( 1 => array( 'a', 'b', 'c' ) ),
42 ),
43 );
44 }
45
46 function testRandom() {
47 # This could hypothetically fail, but it shouldn't ;)
48 $this->assertFalse(
49 wfRandom() == wfRandom() );
50 }
51
52 function testUrlencode() {
53 $this->assertEquals(
54 "%E7%89%B9%E5%88%A5:Contributions/Foobar",
55 wfUrlencode( "\xE7\x89\xB9\xE5\x88\xA5:Contributions/Foobar" ) );
56 }
57
58 function testReadOnlyEmpty() {
59 global $wgReadOnly;
60 $wgReadOnly = null;
61
62 $this->assertFalse( wfReadOnly() );
63 $this->assertFalse( wfReadOnly() );
64 }
65
66 function testReadOnlySet() {
67 global $wgReadOnly, $wgReadOnlyFile;
68
69 $f = fopen( $wgReadOnlyFile, "wt" );
70 fwrite( $f, 'Message' );
71 fclose( $f );
72 $wgReadOnly = null; # Check on $wgReadOnlyFile
73
74 $this->assertTrue( wfReadOnly() );
75 $this->assertTrue( wfReadOnly() ); # Check cached
76
77 unlink( $wgReadOnlyFile );
78 $wgReadOnly = null; # Clean cache
79
80 $this->assertFalse( wfReadOnly() );
81 $this->assertFalse( wfReadOnly() );
82 }
83
84 function testQuotedPrintable() {
85 $this->assertEquals(
86 "=?UTF-8?Q?=C4=88u=20legebla=3F?=",
87 UserMailer::quotedPrintable( "\xc4\x88u legebla?", "UTF-8" ) );
88 }
89
90 function testTime() {
91 $start = wfTime();
92 $this->assertInternalType( 'float', $start );
93 $end = wfTime();
94 $this->assertTrue( $end > $start, "Time is running backwards!" );
95 }
96
97 function dataArrayToCGI() {
98 return array(
99 array( array(), '' ), // empty
100 array( array( 'foo' => 'bar' ), 'foo=bar' ), // string test
101 array( array( 'foo' => '' ), 'foo=' ), // empty string test
102 array( array( 'foo' => 1 ), 'foo=1' ), // number test
103 array( array( 'foo' => true ), 'foo=1' ), // true test
104 array( array( 'foo' => false ), '' ), // false test
105 array( array( 'foo' => null ), '' ), // null test
106 array( array( 'foo' => 'A&B=5+6@!"\'' ), 'foo=A%26B%3D5%2B6%40%21%22%27' ), // urlencoding test
107 array( array( 'foo' => 'bar', 'baz' => 'is', 'asdf' => 'qwerty' ), 'foo=bar&baz=is&asdf=qwerty' ), // multi-item test
108 array( array( 'foo' => array( 'bar' => 'baz' ) ), 'foo%5Bbar%5D=baz' ),
109 array( array( 'foo' => array( 'bar' => 'baz', 'qwerty' => 'asdf' ) ), 'foo%5Bbar%5D=baz&foo%5Bqwerty%5D=asdf' ),
110 array( array( 'foo' => array( 'bar', 'baz' ) ), 'foo%5B0%5D=bar&foo%5B1%5D=baz' ),
111 array( array( 'foo' => array( 'bar' => array( 'bar' => 'baz' ) ) ), 'foo%5Bbar%5D%5Bbar%5D=baz' ),
112 );
113 }
114
115 /**
116 * @dataProvider dataArrayToCGI
117 */
118 function testArrayToCGI( $array, $result ) {
119 $this->assertEquals( $result, wfArrayToCGI( $array ) );
120 }
121
122
123 function testArrayToCGI2() {
124 $this->assertEquals(
125 "baz=bar&foo=bar",
126 wfArrayToCGI(
127 array( 'baz' => 'bar' ),
128 array( 'foo' => 'bar', 'baz' => 'overridden value' ) ) );
129 }
130
131 function dataCgiToArray() {
132 return array(
133 array( '', array() ), // empty
134 array( 'foo=bar', array( 'foo' => 'bar' ) ), // string
135 array( 'foo=', array( 'foo' => '' ) ), // empty string
136 array( 'foo', array( 'foo' => '' ) ), // missing =
137 array( 'foo=bar&qwerty=asdf', array( 'foo' => 'bar', 'qwerty' => 'asdf' ) ), // multiple value
138 array( 'foo=A%26B%3D5%2B6%40%21%22%27', array( 'foo' => 'A&B=5+6@!"\'' ) ), // urldecoding test
139 array( 'foo%5Bbar%5D=baz', array( 'foo' => array( 'bar' => 'baz' ) ) ),
140 array( 'foo%5Bbar%5D=baz&foo%5Bqwerty%5D=asdf', array( 'foo' => array( 'bar' => 'baz', 'qwerty' => 'asdf' ) ) ),
141 array( 'foo%5B0%5D=bar&foo%5B1%5D=baz', array( 'foo' => array( 0 => 'bar', 1 => 'baz' ) ) ),
142 array( 'foo%5Bbar%5D%5Bbar%5D=baz', array( 'foo' => array( 'bar' => array( 'bar' => 'baz' ) ) ) ),
143 );
144 }
145
146 /**
147 * @dataProvider dataCgiToArray
148 */
149 function testCgiToArray( $cgi, $result ) {
150 $this->assertEquals( $result, wfCgiToArray( $cgi ) );
151 }
152
153 function dataCgiRoundTrip() {
154 return array(
155 array( '' ),
156 array( 'foo=bar' ),
157 array( 'foo=' ),
158 array( 'foo=bar&baz=biz' ),
159 array( 'foo=A%26B%3D5%2B6%40%21%22%27' ),
160 array( 'foo%5Bbar%5D=baz' ),
161 array( 'foo%5B0%5D=bar&foo%5B1%5D=baz' ),
162 array( 'foo%5Bbar%5D%5Bbar%5D=baz' ),
163 );
164 }
165
166 /**
167 * @dataProvider dataCgiRoundTrip
168 */
169 function testCgiRoundTrip( $cgi ) {
170 $this->assertEquals( $cgi, wfArrayToCGI( wfCgiToArray( $cgi ) ) );
171 }
172
173 function testMimeTypeMatch() {
174 $this->assertEquals(
175 'text/html',
176 mimeTypeMatch( 'text/html',
177 array( 'application/xhtml+xml' => 1.0,
178 'text/html' => 0.7,
179 'text/plain' => 0.3 ) ) );
180 $this->assertEquals(
181 'text/*',
182 mimeTypeMatch( 'text/html',
183 array( 'image/*' => 1.0,
184 'text/*' => 0.5 ) ) );
185 $this->assertEquals(
186 '*/*',
187 mimeTypeMatch( 'text/html',
188 array( '*/*' => 1.0 ) ) );
189 $this->assertNull(
190 mimeTypeMatch( 'text/html',
191 array( 'image/png' => 1.0,
192 'image/svg+xml' => 0.5 ) ) );
193 }
194
195 function testNegotiateType() {
196 $this->assertEquals(
197 'text/html',
198 wfNegotiateType(
199 array( 'application/xhtml+xml' => 1.0,
200 'text/html' => 0.7,
201 'text/plain' => 0.5,
202 'text/*' => 0.2 ),
203 array( 'text/html' => 1.0 ) ) );
204 $this->assertEquals(
205 'application/xhtml+xml',
206 wfNegotiateType(
207 array( 'application/xhtml+xml' => 1.0,
208 'text/html' => 0.7,
209 'text/plain' => 0.5,
210 'text/*' => 0.2 ),
211 array( 'application/xhtml+xml' => 1.0,
212 'text/html' => 0.5 ) ) );
213 $this->assertEquals(
214 'text/html',
215 wfNegotiateType(
216 array( 'text/html' => 1.0,
217 'text/plain' => 0.5,
218 'text/*' => 0.5,
219 'application/xhtml+xml' => 0.2 ),
220 array( 'application/xhtml+xml' => 1.0,
221 'text/html' => 0.5 ) ) );
222 $this->assertEquals(
223 'text/html',
224 wfNegotiateType(
225 array( 'text/*' => 1.0,
226 'image/*' => 0.7,
227 '*/*' => 0.3 ),
228 array( 'application/xhtml+xml' => 1.0,
229 'text/html' => 0.5 ) ) );
230 $this->assertNull(
231 wfNegotiateType(
232 array( 'text/*' => 1.0 ),
233 array( 'application/xhtml+xml' => 1.0 ) ) );
234 }
235
236 function testFallbackMbstringFunctions() {
237
238 if( !extension_loaded( 'mbstring' ) ) {
239 $this->markTestSkipped( "The mb_string functions must be installed to test the fallback functions" );
240 }
241
242 $sampleUTF = "Östergötland_coat_of_arms.png";
243
244
245 //mb_substr
246 $substr_params = array(
247 array( 0, 0 ),
248 array( 5, -4 ),
249 array( 33 ),
250 array( 100, -5 ),
251 array( -8, 10 ),
252 array( 1, 1 ),
253 array( 2, -1 )
254 );
255
256 foreach( $substr_params as $param_set ) {
257 $old_param_set = $param_set;
258 array_unshift( $param_set, $sampleUTF );
259
260 $this->assertEquals(
261 MWFunction::callArray( 'mb_substr', $param_set ),
262 MWFunction::callArray( 'Fallback::mb_substr', $param_set ),
263 'Fallback mb_substr with params ' . implode( ', ', $old_param_set )
264 );
265 }
266
267
268 //mb_strlen
269 $this->assertEquals(
270 mb_strlen( $sampleUTF ),
271 Fallback::mb_strlen( $sampleUTF ),
272 'Fallback mb_strlen'
273 );
274
275
276 //mb_str(r?)pos
277 $strpos_params = array(
278 //array( 'ter' ),
279 //array( 'Ö' ),
280 //array( 'Ö', 3 ),
281 //array( 'oat_', 100 ),
282 //array( 'c', -10 ),
283 //Broken for now
284 );
285
286 foreach( $strpos_params as $param_set ) {
287 $old_param_set = $param_set;
288 array_unshift( $param_set, $sampleUTF );
289
290 $this->assertEquals(
291 MWFunction::callArray( 'mb_strpos', $param_set ),
292 MWFunction::callArray( 'Fallback::mb_strpos', $param_set ),
293 'Fallback mb_strpos with params ' . implode( ', ', $old_param_set )
294 );
295
296 $this->assertEquals(
297 MWFunction::callArray( 'mb_strrpos', $param_set ),
298 MWFunction::callArray( 'Fallback::mb_strrpos', $param_set ),
299 'Fallback mb_strrpos with params ' . implode( ', ', $old_param_set )
300 );
301 }
302
303 }
304
305
306 function testDebugFunctionTest() {
307
308 global $wgDebugLogFile, $wgOut, $wgShowDebug, $wgDebugTimestamps;
309
310 $old_log_file = $wgDebugLogFile;
311 $wgDebugLogFile = tempnam( wfTempDir(), 'mw-' );
312 # @todo FIXME: This setting should be tested
313 $wgDebugTimestamps = false;
314
315
316
317 wfDebug( "This is a normal string" );
318 $this->assertEquals( "This is a normal string", file_get_contents( $wgDebugLogFile ) );
319 unlink( $wgDebugLogFile );
320
321
322 wfDebug( "This is nöt an ASCII string" );
323 $this->assertEquals( "This is nöt an ASCII string", file_get_contents( $wgDebugLogFile ) );
324 unlink( $wgDebugLogFile );
325
326
327 wfDebug( "\00305This has böth UTF and control chars\003" );
328 $this->assertEquals( " 05This has böth UTF and control chars ", file_get_contents( $wgDebugLogFile ) );
329 unlink( $wgDebugLogFile );
330
331
332
333 $old_wgOut = $wgOut;
334 $old_wgShowDebug = $wgShowDebug;
335
336 $wgOut = new MockOutputPage;
337
338 $wgShowDebug = true;
339
340 $message = "\00305This has böth UTF and control chars\003";
341
342 wfDebug( $message );
343
344 if( $wgOut->message == "JAJA is a stupid error message. Anyway, here's your message: $message" ) {
345 $this->assertTrue( true, 'MockOutputPage called, set the proper message.' );
346 }
347 else {
348 $this->assertTrue( false, 'MockOutputPage was not called.' );
349 }
350
351 $wgOut = $old_wgOut;
352 $wgShowDebug = $old_wgShowDebug;
353 unlink( $wgDebugLogFile );
354
355
356
357 wfDebugMem();
358 $this->assertGreaterThan( 5000, preg_replace( '/\D/', '', file_get_contents( $wgDebugLogFile ) ) );
359 unlink( $wgDebugLogFile );
360
361 wfDebugMem(true);
362 $this->assertGreaterThan( 5000000, preg_replace( '/\D/', '', file_get_contents( $wgDebugLogFile ) ) );
363 unlink( $wgDebugLogFile );
364
365
366
367 $wgDebugLogFile = $old_log_file;
368
369 }
370
371 function testClientAcceptsGzipTest() {
372
373 $settings = array(
374 'gzip' => true,
375 'bzip' => false,
376 '*' => false,
377 'compress, gzip' => true,
378 'gzip;q=1.0' => true,
379 'foozip' => false,
380 'foo*zip' => false,
381 'gzip;q=abcde' => true, //is this REALLY valid?
382 'gzip;q=12345678.9' => true,
383 ' gzip' => true,
384 );
385
386 if( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) $old_server_setting = $_SERVER['HTTP_ACCEPT_ENCODING'];
387
388 foreach ( $settings as $encoding => $expect ) {
389 $_SERVER['HTTP_ACCEPT_ENCODING'] = $encoding;
390
391 $this->assertEquals( $expect, wfClientAcceptsGzip( true ),
392 "'$encoding' => " . wfBoolToStr( $expect ) );
393 }
394
395 if( isset( $old_server_setting ) ) $_SERVER['HTTP_ACCEPT_ENCODING'] = $old_server_setting;
396
397 }
398
399
400
401 function testSwapVarsTest() {
402
403
404 $var1 = 1;
405 $var2 = 2;
406
407 $this->assertEquals( $var1, 1, 'var1 is set originally' );
408 $this->assertEquals( $var2, 2, 'var1 is set originally' );
409
410 swap( $var1, $var2 );
411
412 $this->assertEquals( $var1, 2, 'var1 is swapped' );
413 $this->assertEquals( $var2, 1, 'var2 is swapped' );
414
415 }
416
417
418 function testWfPercentTest() {
419
420 $pcts = array(
421 array( 6/7, '0.86%', 2, false ),
422 array( 3/3, '1%' ),
423 array( 22/7, '3.14286%', 5 ),
424 array( 3/6, '0.5%' ),
425 array( 1/3, '0%', 0 ),
426 array( 10/3, '0%', -1 ),
427 array( 3/4/5, '0.1%', 1 ),
428 array( 6/7*8, '6.8571428571%', 10 ),
429 );
430
431 foreach( $pcts as $pct ) {
432 if( !isset( $pct[2] ) ) $pct[2] = 2;
433 if( !isset( $pct[3] ) ) $pct[3] = true;
434
435 $this->assertEquals( wfPercent( $pct[0], $pct[2], $pct[3] ), $pct[1], $pct[1] );
436 }
437
438 }
439
440
441 function testInStringTest() {
442
443 $this->assertTrue( in_string( 'foo', 'foobar' ), 'foo is in foobar' );
444 $this->assertFalse( in_string( 'Bar', 'foobar' ), 'Case-sensitive by default' );
445 $this->assertTrue( in_string( 'Foo', 'foobar', true ), 'Case-insensitive when asked' );
446
447 }
448
449 /**
450 * test @see wfShorthandToInteger()
451 * @dataProvider provideShorthand
452 */
453 public function testWfShorthandToInteger( $shorthand, $expected ) {
454 $this->assertEquals( $expected,
455 wfShorthandToInteger( $shorthand )
456 );
457 }
458
459 /** array( shorthand, expected integer ) */
460 public function provideShorthand() {
461 return array(
462 # Null, empty ...
463 array( '', -1),
464 array( ' ', -1),
465 array( null, -1),
466
467 # Failures returns 0 :(
468 array( 'ABCDEFG', 0 ),
469 array( 'Ak', 0 ),
470
471 # Int, strings with spaces
472 array( 1, 1 ),
473 array( ' 1 ', 1 ),
474 array( 1023, 1023 ),
475 array( ' 1023 ', 1023 ),
476
477 # kilo, Mega, Giga
478 array( '1k', 1024 ),
479 array( '1K', 1024 ),
480 array( '1m', 1024 * 1024 ),
481 array( '1M', 1024 * 1024 ),
482 array( '1g', 1024 * 1024 * 1024 ),
483 array( '1G', 1024 * 1024 * 1024 ),
484
485 # Negatives
486 array( -1, -1 ),
487 array( -500, -500 ),
488 array( '-500', -500 ),
489 array( '-1k', -1024 ),
490
491 # Zeroes
492 array( '0', 0 ),
493 array( '0k', 0 ),
494 array( '0M', 0 ),
495 array( '0G', 0 ),
496 array( '-0', 0 ),
497 array( '-0k', 0 ),
498 array( '-0M', 0 ),
499 array( '-0G', 0 ),
500 );
501 }
502
503 /**
504 * @dataProvider provideMakeUrlIndexes()
505 */
506 function testMakeUrlIndexes( $url, $expected ) {
507 $index = wfMakeUrlIndexes( $url );
508 $this->assertEquals( $expected, $index, "wfMakeUrlIndexes(\"$url\")" );
509 }
510
511 function provideMakeUrlIndexes() {
512 return array(
513 array(
514 // just a regular :)
515 'https://bugzilla.wikimedia.org/show_bug.cgi?id=28627',
516 array( 'https://org.wikimedia.bugzilla./show_bug.cgi?id=28627' )
517 ),
518 array(
519 // mailtos are handled special
520 // is this really right though? that final . probably belongs earlier?
521 'mailto:wiki@wikimedia.org',
522 array( 'mailto:org.wikimedia@wiki.' )
523 ),
524
525 // file URL cases per bug 28627...
526 array(
527 // three slashes: local filesystem path Unix-style
528 'file:///whatever/you/like.txt',
529 array( 'file://./whatever/you/like.txt' )
530 ),
531 array(
532 // three slashes: local filesystem path Windows-style
533 'file:///c:/whatever/you/like.txt',
534 array( 'file://./c:/whatever/you/like.txt' )
535 ),
536 array(
537 // two slashes: UNC filesystem path Windows-style
538 'file://intranet/whatever/you/like.txt',
539 array( 'file://intranet./whatever/you/like.txt' )
540 ),
541 // Multiple-slash cases that can sorta work on Mozilla
542 // if you hack it just right are kinda pathological,
543 // and unreliable cross-platform or on IE which means they're
544 // unlikely to appear on intranets.
545 //
546 // Those will survive the algorithm but with results that
547 // are less consistent.
548
549 // protocol-relative URL cases per bug 29854...
550 array(
551 '//bugzilla.wikimedia.org/show_bug.cgi?id=28627',
552 array(
553 'http://org.wikimedia.bugzilla./show_bug.cgi?id=28627',
554 'https://org.wikimedia.bugzilla./show_bug.cgi?id=28627'
555 )
556 ),
557 );
558 }
559
560 /**
561 * @dataProvider provideWfMatchesDomainList
562 */
563 function testWfMatchesDomainList( $url, $domains, $expected, $description ) {
564 $actual = wfMatchesDomainList( $url, $domains );
565 $this->assertEquals( $expected, $actual, $description );
566 }
567
568 function provideWfMatchesDomainList() {
569 $a = array();
570 $protocols = array( 'HTTP' => 'http:', 'HTTPS' => 'https:', 'protocol-relative' => '' );
571 foreach ( $protocols as $pDesc => $p ) {
572 $a = array_merge( $a, array(
573 array( "$p//www.example.com", array(), false, "No matches for empty domains array, $pDesc URL" ),
574 array( "$p//www.example.com", array( 'www.example.com' ), true, "Exact match in domains array, $pDesc URL" ),
575 array( "$p//www.example.com", array( 'example.com' ), true, "Match without subdomain in domains array, $pDesc URL" ),
576 array( "$p//www.example2.com", array( 'www.example.com', 'www.example2.com', 'www.example3.com' ), true, "Exact match with other domains in array, $pDesc URL" ),
577 array( "$p//www.example2.com", array( 'example.com', 'example2.com', 'example3,com' ), true, "Match without subdomain with other domains in array, $pDesc URL" ),
578 array( "$p//www.example4.com", array( 'example.com', 'example2.com', 'example3,com' ), false, "Domain not in array, $pDesc URL" ),
579
580 // FIXME: This is a bug in wfMatchesDomainList(). If and when this is fixed, update this test case
581 array( "$p//nds-nl.wikipedia.org", array( 'nl.wikipedia.org' ), true, "Substrings of domains match while they shouldn't, $pDesc URL" ),
582 ) );
583 }
584 return $a;
585 }
586
587 /**
588 * @dataProvider provideWfShellMaintenanceCmdList
589 */
590 function testWfShellMaintenanceCmd( $script, $parameters, $options, $expected, $description ) {
591 if( wfIsWindows() ) {
592 // Approximation that's good enough for our purposes just now
593 $expected = str_replace( "'", '"', $expected );
594 }
595 $actual = wfShellMaintenanceCmd( $script, $parameters, $options );
596 $this->assertEquals( $expected, $actual, $description );
597 }
598
599 function provideWfShellMaintenanceCmdList() {
600 global $wgPhpCli;
601 return array(
602 array( 'eval.php', array( '--help', '--test' ), array(),
603 "'$wgPhpCli' 'eval.php' '--help' '--test'",
604 "Called eval.php --help --test" ),
605 array( 'eval.php', array( '--help', '--test space' ), array('php' => 'php5'),
606 "'php5' 'eval.php' '--help' '--test space'",
607 "Called eval.php --help --test with php option" ),
608 array( 'eval.php', array( '--help', '--test', 'X' ), array('wrapper' => 'MWScript.php'),
609 "'$wgPhpCli' 'MWScript.php' 'eval.php' '--help' '--test' 'X'",
610 "Called eval.php --help --test with wrapper option" ),
611 array( 'eval.php', array( '--help', '--test', 'y' ), array('php' => 'php5', 'wrapper' => 'MWScript.php'),
612 "'php5' 'MWScript.php' 'eval.php' '--help' '--test' 'y'",
613 "Called eval.php --help --test with wrapper and php option" ),
614 );
615 }
616 /* TODO: many more! */
617 }
618
619
620 class MockOutputPage {
621
622 public $message;
623
624 function debug( $message ) {
625 $this->message = "JAJA is a stupid error message. Anyway, here's your message: $message";
626 }
627 }
628