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