Followup r105809; Split up the tests with a dataProvider and add a round trip test.
[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 testTimestamp() {
237 $t = gmmktime( 12, 34, 56, 1, 15, 2001 );
238 $this->assertEquals(
239 '20010115123456',
240 wfTimestamp( TS_MW, $t ),
241 'TS_UNIX to TS_MW' );
242 $this->assertEquals(
243 '19690115123456',
244 wfTimestamp( TS_MW, -30281104 ),
245 'Negative TS_UNIX to TS_MW' );
246 $this->assertEquals(
247 979562096,
248 wfTimestamp( TS_UNIX, $t ),
249 'TS_UNIX to TS_UNIX' );
250 $this->assertEquals(
251 '2001-01-15 12:34:56',
252 wfTimestamp( TS_DB, $t ),
253 'TS_UNIX to TS_DB' );
254 $this->assertEquals(
255 '20010115T123456Z',
256 wfTimestamp( TS_ISO_8601_BASIC, $t ),
257 'TS_ISO_8601_BASIC to TS_DB' );
258
259 $this->assertEquals(
260 '20010115123456',
261 wfTimestamp( TS_MW, '20010115123456' ),
262 'TS_MW to TS_MW' );
263 $this->assertEquals(
264 979562096,
265 wfTimestamp( TS_UNIX, '20010115123456' ),
266 'TS_MW to TS_UNIX' );
267 $this->assertEquals(
268 '2001-01-15 12:34:56',
269 wfTimestamp( TS_DB, '20010115123456' ),
270 'TS_MW to TS_DB' );
271 $this->assertEquals(
272 '20010115T123456Z',
273 wfTimestamp( TS_ISO_8601_BASIC, '20010115123456' ),
274 'TS_MW to TS_ISO_8601_BASIC' );
275
276 $this->assertEquals(
277 '20010115123456',
278 wfTimestamp( TS_MW, '2001-01-15 12:34:56' ),
279 'TS_DB to TS_MW' );
280 $this->assertEquals(
281 979562096,
282 wfTimestamp( TS_UNIX, '2001-01-15 12:34:56' ),
283 'TS_DB to TS_UNIX' );
284 $this->assertEquals(
285 '2001-01-15 12:34:56',
286 wfTimestamp( TS_DB, '2001-01-15 12:34:56' ),
287 'TS_DB to TS_DB' );
288 $this->assertEquals(
289 '20010115T123456Z',
290 wfTimestamp( TS_ISO_8601_BASIC, '2001-01-15 12:34:56' ),
291 'TS_DB to TS_ISO_8601_BASIC' );
292
293 # rfc2822 section 3.3
294
295 $this->assertEquals(
296 'Mon, 15 Jan 2001 12:34:56 GMT',
297 wfTimestamp( TS_RFC2822, '20010115123456' ),
298 'TS_MW to TS_RFC2822' );
299
300 $this->assertEquals(
301 '20010115123456',
302 wfTimestamp( TS_MW, 'Mon, 15 Jan 2001 12:34:56 GMT' ),
303 'TS_RFC2822 to TS_MW' );
304
305 $this->assertEquals(
306 '20010115123456',
307 wfTimestamp( TS_MW, ' Mon, 15 Jan 2001 12:34:56 GMT' ),
308 'TS_RFC2822 with leading space to TS_MW' );
309
310 $this->assertEquals(
311 '20010115123456',
312 wfTimestamp( TS_MW, '15 Jan 2001 12:34:56 GMT' ),
313 'TS_RFC2822 without optional day-of-week to TS_MW' );
314
315 # FWS = ([*WSP CRLF] 1*WSP) / obs-FWS ; Folding white space
316 # obs-FWS = 1*WSP *(CRLF 1*WSP) ; Section 4.2
317 $this->assertEquals(
318 '20010115123456',
319 wfTimestamp( TS_MW, 'Mon, 15 Jan 2001 12:34:56 GMT' ),
320 'TS_RFC2822 to TS_MW' );
321
322 # WSP = SP / HTAB ; rfc2234
323 $this->assertEquals(
324 '20010115123456',
325 wfTimestamp( TS_MW, "Mon, 15 Jan\x092001 12:34:56 GMT" ),
326 'TS_RFC2822 with HTAB to TS_MW' );
327
328 $this->assertEquals(
329 '20010115123456',
330 wfTimestamp( TS_MW, "Mon, 15 Jan\x09 \x09 2001 12:34:56 GMT" ),
331 'TS_RFC2822 with HTAB and SP to TS_MW' );
332
333 $this->assertEquals(
334 '19941106084937',
335 wfTimestamp( TS_MW, "Sun, 6 Nov 94 08:49:37 GMT" ),
336 'TS_RFC2822 with obsolete year to TS_MW' );
337 }
338
339 /**
340 * This test checks wfTimestamp() with values outside.
341 * It needs PHP 64 bits or PHP > 5.1.
342 * See r74778 and bug 25451
343 */
344 function testOldTimestamps() {
345 $this->assertEquals( 'Fri, 13 Dec 1901 20:45:54 GMT',
346 wfTimestamp( TS_RFC2822, '19011213204554' ),
347 'Earliest time according to php documentation' );
348
349 $this->assertEquals( 'Tue, 19 Jan 2038 03:14:07 GMT',
350 wfTimestamp( TS_RFC2822, '20380119031407' ),
351 'Latest 32 bit time' );
352
353 $this->assertEquals( '-2147483648',
354 wfTimestamp( TS_UNIX, '19011213204552' ),
355 'Earliest 32 bit unix time' );
356
357 $this->assertEquals( '2147483647',
358 wfTimestamp( TS_UNIX, '20380119031407' ),
359 'Latest 32 bit unix time' );
360
361 $this->assertEquals( 'Fri, 13 Dec 1901 20:45:52 GMT',
362 wfTimestamp( TS_RFC2822, '19011213204552' ),
363 'Earliest 32 bit time' );
364
365 $this->assertEquals( 'Fri, 13 Dec 1901 20:45:51 GMT',
366 wfTimestamp( TS_RFC2822, '19011213204551' ),
367 'Earliest 32 bit time - 1' );
368
369 $this->assertEquals( 'Tue, 19 Jan 2038 03:14:08 GMT',
370 wfTimestamp( TS_RFC2822, '20380119031408' ),
371 'Latest 32 bit time + 1' );
372
373 $this->assertEquals( '19011212000000',
374 wfTimestamp(TS_MW, '19011212000000'),
375 'Convert to itself r74778#c10645' );
376
377 $this->assertEquals( '-2147483649',
378 wfTimestamp( TS_UNIX, '19011213204551' ),
379 'Earliest 32 bit unix time - 1' );
380
381 $this->assertEquals( '2147483648',
382 wfTimestamp( TS_UNIX, '20380119031408' ),
383 'Latest 32 bit unix time + 1' );
384
385 $this->assertEquals( '19011213204551',
386 wfTimestamp( TS_MW, '-2147483649' ),
387 '1901 negative unix time to MediaWiki' );
388
389 $this->assertEquals( '18010115123456',
390 wfTimestamp( TS_MW, '-5331871504' ),
391 '1801 negative unix time to MediaWiki' );
392
393 $this->assertEquals( 'Tue, 09 Aug 0117 12:34:56 GMT',
394 wfTimestamp( TS_RFC2822, '0117-08-09 12:34:56'),
395 'Death of Roman Emperor [[Trajan]]');
396
397 /* @todo FIXME: 00 to 101 years are taken as being in [1970-2069] */
398
399 $this->assertEquals( 'Sun, 01 Jan 0101 00:00:00 GMT',
400 wfTimestamp( TS_RFC2822, '-58979923200'),
401 '1/1/101');
402
403 $this->assertEquals( 'Mon, 01 Jan 0001 00:00:00 GMT',
404 wfTimestamp( TS_RFC2822, '-62135596800'),
405 'Year 1');
406
407 /* It is not clear if we should generate a year 0 or not
408 * We are completely off RFC2822 requirement of year being
409 * 1900 or later.
410 */
411 $this->assertEquals( 'Wed, 18 Oct 0000 00:00:00 GMT',
412 wfTimestamp( TS_RFC2822, '-62142076800'),
413 'ISO 8601:2004 [[year 0]], also called [[1 BC]]');
414 }
415
416 function testHttpDate() {
417 # The Resource Loader uses wfTimestamp() to convert timestamps
418 # from If-Modified-Since header.
419 # Thus it must be able to parse all rfc2616 date formats
420 # http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1
421
422 $this->assertEquals(
423 '19941106084937',
424 wfTimestamp( TS_MW, 'Sun, 06 Nov 1994 08:49:37 GMT' ),
425 'RFC 822 date' );
426
427 $this->assertEquals(
428 '19941106084937',
429 wfTimestamp( TS_MW, 'Sunday, 06-Nov-94 08:49:37 GMT' ),
430 'RFC 850 date' );
431
432 $this->assertEquals(
433 '19941106084937',
434 wfTimestamp( TS_MW, 'Sun Nov 6 08:49:37 1994' ),
435 "ANSI C's asctime() format" );
436
437 // See http://www.squid-cache.org/mail-archive/squid-users/200307/0122.html and r77171
438 $this->assertEquals(
439 '20101122141242',
440 wfTimestamp( TS_MW, 'Mon, 22 Nov 2010 14:12:42 GMT; length=52626' ),
441 "Netscape extension to HTTP/1.0" );
442
443 }
444
445 function testTimestampParameter() {
446 // There are a number of assumptions in our codebase where wfTimestamp() should give
447 // the current date but it is not given a 0 there. See r71751 CR
448
449 $now = wfTimestamp( TS_UNIX );
450 // We check that wfTimestamp doesn't return false (error) and use a LessThan assert
451 // for the cases where the test is run in a second boundary.
452
453 $zero = wfTimestamp( TS_UNIX, 0 );
454 $this->assertNotEquals( false, $zero );
455 $this->assertLessThan( 5, $zero - $now );
456
457 $empty = wfTimestamp( TS_UNIX, '' );
458 $this->assertNotEquals( false, $empty );
459 $this->assertLessThan( 5, $empty - $now );
460
461 $null = wfTimestamp( TS_UNIX, null );
462 $this->assertNotEquals( false, $null );
463 $this->assertLessThan( 5, $null - $now );
464 }
465
466 function testBasename() {
467 $sets = array(
468 '' => '',
469 '/' => '',
470 '\\' => '',
471 '//' => '',
472 '\\\\' => '',
473 'a' => 'a',
474 'aaaa' => 'aaaa',
475 '/a' => 'a',
476 '\\a' => 'a',
477 '/aaaa' => 'aaaa',
478 '\\aaaa' => 'aaaa',
479 '/aaaa/' => 'aaaa',
480 '\\aaaa\\' => 'aaaa',
481 '\\aaaa\\' => 'aaaa',
482 '/mnt/upload3/wikipedia/en/thumb/8/8b/Zork_Grand_Inquisitor_box_cover.jpg/93px-Zork_Grand_Inquisitor_box_cover.jpg' => '93px-Zork_Grand_Inquisitor_box_cover.jpg',
483 'C:\\Progra~1\\Wikime~1\\Wikipe~1\\VIEWER.EXE' => 'VIEWER.EXE',
484 'Östergötland_coat_of_arms.png' => 'Östergötland_coat_of_arms.png',
485 );
486 foreach ( $sets as $from => $to ) {
487 $this->assertEquals( $to, wfBaseName( $from ),
488 "wfBaseName('$from') => '$to'" );
489 }
490 }
491
492
493 function testFallbackMbstringFunctions() {
494
495 if( !extension_loaded( 'mbstring' ) ) {
496 $this->markTestSkipped( "The mb_string functions must be installed to test the fallback functions" );
497 }
498
499 $sampleUTF = "Östergötland_coat_of_arms.png";
500
501
502 //mb_substr
503 $substr_params = array(
504 array( 0, 0 ),
505 array( 5, -4 ),
506 array( 33 ),
507 array( 100, -5 ),
508 array( -8, 10 ),
509 array( 1, 1 ),
510 array( 2, -1 )
511 );
512
513 foreach( $substr_params as $param_set ) {
514 $old_param_set = $param_set;
515 array_unshift( $param_set, $sampleUTF );
516
517 $this->assertEquals(
518 MWFunction::callArray( 'mb_substr', $param_set ),
519 MWFunction::callArray( 'Fallback::mb_substr', $param_set ),
520 'Fallback mb_substr with params ' . implode( ', ', $old_param_set )
521 );
522 }
523
524
525 //mb_strlen
526 $this->assertEquals(
527 mb_strlen( $sampleUTF ),
528 Fallback::mb_strlen( $sampleUTF ),
529 'Fallback mb_strlen'
530 );
531
532
533 //mb_str(r?)pos
534 $strpos_params = array(
535 //array( 'ter' ),
536 //array( 'Ö' ),
537 //array( 'Ö', 3 ),
538 //array( 'oat_', 100 ),
539 //array( 'c', -10 ),
540 //Broken for now
541 );
542
543 foreach( $strpos_params as $param_set ) {
544 $old_param_set = $param_set;
545 array_unshift( $param_set, $sampleUTF );
546
547 $this->assertEquals(
548 MWFunction::callArray( 'mb_strpos', $param_set ),
549 MWFunction::callArray( 'Fallback::mb_strpos', $param_set ),
550 'Fallback mb_strpos with params ' . implode( ', ', $old_param_set )
551 );
552
553 $this->assertEquals(
554 MWFunction::callArray( 'mb_strrpos', $param_set ),
555 MWFunction::callArray( 'Fallback::mb_strrpos', $param_set ),
556 'Fallback mb_strrpos with params ' . implode( ', ', $old_param_set )
557 );
558 }
559
560 }
561
562
563 function testDebugFunctionTest() {
564
565 global $wgDebugLogFile, $wgOut, $wgShowDebug, $wgDebugTimestamps;
566
567 $old_log_file = $wgDebugLogFile;
568 $wgDebugLogFile = tempnam( wfTempDir(), 'mw-' );
569 # @todo FIXME: This setting should be tested
570 $wgDebugTimestamps = false;
571
572
573
574 wfDebug( "This is a normal string" );
575 $this->assertEquals( "This is a normal string", file_get_contents( $wgDebugLogFile ) );
576 unlink( $wgDebugLogFile );
577
578
579 wfDebug( "This is nöt an ASCII string" );
580 $this->assertEquals( "This is nöt an ASCII string", file_get_contents( $wgDebugLogFile ) );
581 unlink( $wgDebugLogFile );
582
583
584 wfDebug( "\00305This has böth UTF and control chars\003" );
585 $this->assertEquals( " 05This has böth UTF and control chars ", file_get_contents( $wgDebugLogFile ) );
586 unlink( $wgDebugLogFile );
587
588
589
590 $old_wgOut = $wgOut;
591 $old_wgShowDebug = $wgShowDebug;
592
593 $wgOut = new MockOutputPage;
594
595 $wgShowDebug = true;
596
597 $message = "\00305This has böth UTF and control chars\003";
598
599 wfDebug( $message );
600
601 if( $wgOut->message == "JAJA is a stupid error message. Anyway, here's your message: $message" ) {
602 $this->assertTrue( true, 'MockOutputPage called, set the proper message.' );
603 }
604 else {
605 $this->assertTrue( false, 'MockOutputPage was not called.' );
606 }
607
608 $wgOut = $old_wgOut;
609 $wgShowDebug = $old_wgShowDebug;
610 unlink( $wgDebugLogFile );
611
612
613
614 wfDebugMem();
615 $this->assertGreaterThan( 5000, preg_replace( '/\D/', '', file_get_contents( $wgDebugLogFile ) ) );
616 unlink( $wgDebugLogFile );
617
618 wfDebugMem(true);
619 $this->assertGreaterThan( 5000000, preg_replace( '/\D/', '', file_get_contents( $wgDebugLogFile ) ) );
620 unlink( $wgDebugLogFile );
621
622
623
624 $wgDebugLogFile = $old_log_file;
625
626 }
627
628 function testClientAcceptsGzipTest() {
629
630 $settings = array(
631 'gzip' => true,
632 'bzip' => false,
633 '*' => false,
634 'compress, gzip' => true,
635 'gzip;q=1.0' => true,
636 'foozip' => false,
637 'foo*zip' => false,
638 'gzip;q=abcde' => true, //is this REALLY valid?
639 'gzip;q=12345678.9' => true,
640 ' gzip' => true,
641 );
642
643 if( isset( $_SERVER['HTTP_ACCEPT_ENCODING'] ) ) $old_server_setting = $_SERVER['HTTP_ACCEPT_ENCODING'];
644
645 foreach ( $settings as $encoding => $expect ) {
646 $_SERVER['HTTP_ACCEPT_ENCODING'] = $encoding;
647
648 $this->assertEquals( $expect, wfClientAcceptsGzip( true ),
649 "'$encoding' => " . wfBoolToStr( $expect ) );
650 }
651
652 if( isset( $old_server_setting ) ) $_SERVER['HTTP_ACCEPT_ENCODING'] = $old_server_setting;
653
654 }
655
656
657
658 function testSwapVarsTest() {
659
660
661 $var1 = 1;
662 $var2 = 2;
663
664 $this->assertEquals( $var1, 1, 'var1 is set originally' );
665 $this->assertEquals( $var2, 2, 'var1 is set originally' );
666
667 swap( $var1, $var2 );
668
669 $this->assertEquals( $var1, 2, 'var1 is swapped' );
670 $this->assertEquals( $var2, 1, 'var2 is swapped' );
671
672 }
673
674
675 function testWfPercentTest() {
676
677 $pcts = array(
678 array( 6/7, '0.86%', 2, false ),
679 array( 3/3, '1%' ),
680 array( 22/7, '3.14286%', 5 ),
681 array( 3/6, '0.5%' ),
682 array( 1/3, '0%', 0 ),
683 array( 10/3, '0%', -1 ),
684 array( 3/4/5, '0.1%', 1 ),
685 array( 6/7*8, '6.8571428571%', 10 ),
686 );
687
688 foreach( $pcts as $pct ) {
689 if( !isset( $pct[2] ) ) $pct[2] = 2;
690 if( !isset( $pct[3] ) ) $pct[3] = true;
691
692 $this->assertEquals( wfPercent( $pct[0], $pct[2], $pct[3] ), $pct[1], $pct[1] );
693 }
694
695 }
696
697
698 function testInStringTest() {
699
700 $this->assertTrue( in_string( 'foo', 'foobar' ), 'foo is in foobar' );
701 $this->assertFalse( in_string( 'Bar', 'foobar' ), 'Case-sensitive by default' );
702 $this->assertTrue( in_string( 'Foo', 'foobar', true ), 'Case-insensitive when asked' );
703
704 }
705
706 /**
707 * test @see wfShorthandToInteger()
708 * @dataProvider provideShorthand
709 */
710 public function testWfShorthandToInteger( $shorthand, $expected ) {
711 $this->assertEquals( $expected,
712 wfShorthandToInteger( $shorthand )
713 );
714 }
715
716 /** array( shorthand, expected integer ) */
717 public function provideShorthand() {
718 return array(
719 # Null, empty ...
720 array( '', -1),
721 array( ' ', -1),
722 array( null, -1),
723
724 # Failures returns 0 :(
725 array( 'ABCDEFG', 0 ),
726 array( 'Ak', 0 ),
727
728 # Int, strings with spaces
729 array( 1, 1 ),
730 array( ' 1 ', 1 ),
731 array( 1023, 1023 ),
732 array( ' 1023 ', 1023 ),
733
734 # kilo, Mega, Giga
735 array( '1k', 1024 ),
736 array( '1K', 1024 ),
737 array( '1m', 1024 * 1024 ),
738 array( '1M', 1024 * 1024 ),
739 array( '1g', 1024 * 1024 * 1024 ),
740 array( '1G', 1024 * 1024 * 1024 ),
741
742 # Negatives
743 array( -1, -1 ),
744 array( -500, -500 ),
745 array( '-500', -500 ),
746 array( '-1k', -1024 ),
747
748 # Zeroes
749 array( '0', 0 ),
750 array( '0k', 0 ),
751 array( '0M', 0 ),
752 array( '0G', 0 ),
753 array( '-0', 0 ),
754 array( '-0k', 0 ),
755 array( '-0M', 0 ),
756 array( '-0G', 0 ),
757 );
758 }
759
760
761 /**
762 * test @see wfBCP47().
763 * Please note the BCP explicitly state that language codes are case
764 * insensitive, there are some exceptions to the rule :)
765 * This test is used to verify our formatting against all lower and
766 * all upper cases language code.
767 *
768 * @see http://tools.ietf.org/html/bcp47
769 * @dataProvider provideLanguageCodes()
770 */
771 function testBCP47( $code, $expected ) {
772 $code = strtolower( $code );
773 $this->assertEquals( $expected, wfBCP47($code),
774 "Applying BCP47 standard to lower case '$code'"
775 );
776
777 $code = strtoupper( $code );
778 $this->assertEquals( $expected, wfBCP47($code),
779 "Applying BCP47 standard to upper case '$code'"
780 );
781 }
782
783 /**
784 * Array format is ($code, $expected)
785 */
786 function provideLanguageCodes() {
787 return array(
788 // Extracted from BCP47 (list not exhaustive)
789 # 2.1.1
790 array( 'en-ca-x-ca' , 'en-CA-x-ca' ),
791 array( 'sgn-be-fr' , 'sgn-BE-FR' ),
792 array( 'az-latn-x-latn', 'az-Latn-x-latn' ),
793 # 2.2
794 array( 'sr-Latn-RS', 'sr-Latn-RS' ),
795 array( 'az-arab-ir', 'az-Arab-IR' ),
796
797 # 2.2.5
798 array( 'sl-nedis' , 'sl-nedis' ),
799 array( 'de-ch-1996', 'de-CH-1996' ),
800
801 # 2.2.6
802 array(
803 'en-latn-gb-boont-r-extended-sequence-x-private',
804 'en-Latn-GB-boont-r-extended-sequence-x-private'
805 ),
806
807 // Examples from BCP47 Appendix A
808 # Simple language subtag:
809 array( 'DE', 'de' ),
810 array( 'fR', 'fr' ),
811 array( 'ja', 'ja' ),
812
813 # Language subtag plus script subtag:
814 array( 'zh-hans', 'zh-Hans'),
815 array( 'sr-cyrl', 'sr-Cyrl'),
816 array( 'sr-latn', 'sr-Latn'),
817
818 # Extended language subtags and their primary language subtag
819 # counterparts:
820 array( 'zh-cmn-hans-cn', 'zh-cmn-Hans-CN' ),
821 array( 'cmn-hans-cn' , 'cmn-Hans-CN' ),
822 array( 'zh-yue-hk' , 'zh-yue-HK' ),
823 array( 'yue-hk' , 'yue-HK' ),
824
825 # Language-Script-Region:
826 array( 'zh-hans-cn', 'zh-Hans-CN' ),
827 array( 'sr-latn-RS', 'sr-Latn-RS' ),
828
829 # Language-Variant:
830 array( 'sl-rozaj' , 'sl-rozaj' ),
831 array( 'sl-rozaj-biske', 'sl-rozaj-biske' ),
832 array( 'sl-nedis' , 'sl-nedis' ),
833
834 # Language-Region-Variant:
835 array( 'de-ch-1901' , 'de-CH-1901' ),
836 array( 'sl-it-nedis' , 'sl-IT-nedis' ),
837
838 # Language-Script-Region-Variant:
839 array( 'hy-latn-it-arevela', 'hy-Latn-IT-arevela' ),
840
841 # Language-Region:
842 array( 'de-de' , 'de-DE' ),
843 array( 'en-us' , 'en-US' ),
844 array( 'es-419', 'es-419'),
845
846 # Private use subtags:
847 array( 'de-ch-x-phonebk' , 'de-CH-x-phonebk' ),
848 array( 'az-arab-x-aze-derbend', 'az-Arab-x-aze-derbend' ),
849 /**
850 * Previous test does not reflect the BCP which states:
851 * az-Arab-x-AZE-derbend
852 * AZE being private, it should be lower case, hence the test above
853 * should probably be:
854 #array( 'az-arab-x-aze-derbend', 'az-Arab-x-AZE-derbend' ),
855 */
856
857 # Private use registry values:
858 array( 'x-whatever', 'x-whatever' ),
859 array( 'qaa-qaaa-qm-x-southern', 'qaa-Qaaa-QM-x-southern' ),
860 array( 'de-qaaa' , 'de-Qaaa' ),
861 array( 'sr-latn-qm', 'sr-Latn-QM' ),
862 array( 'sr-qaaa-rs', 'sr-Qaaa-RS' ),
863
864 # Tags that use extensions
865 array( 'en-us-u-islamcal', 'en-US-u-islamcal' ),
866 array( 'zh-cn-a-myext-x-private', 'zh-CN-a-myext-x-private' ),
867 array( 'en-a-myext-b-another', 'en-a-myext-b-another' ),
868
869 # Invalid:
870 // de-419-DE
871 // a-DE
872 // ar-a-aaa-b-bbb-a-ccc
873
874 /*
875 // ISO 15924 :
876 array( 'sr-Cyrl', 'sr-Cyrl' ),
877 # @todo FIXME: Fix our function?
878 array( 'SR-lATN', 'sr-Latn' ),
879 array( 'fr-latn', 'fr-Latn' ),
880 // Use lowercase for single segment
881 // ISO 3166-1-alpha-2 code
882 array( 'US', 'us' ), # USA
883 array( 'uS', 'us' ), # USA
884 array( 'Fr', 'fr' ), # France
885 array( 'va', 'va' ), # Holy See (Vatican City State)
886 */);
887 }
888
889 /**
890 * @dataProvider provideMakeUrlIndexes()
891 */
892 function testMakeUrlIndexes( $url, $expected ) {
893 $index = wfMakeUrlIndexes( $url );
894 $this->assertEquals( $expected, $index, "wfMakeUrlIndexes(\"$url\")" );
895 }
896
897 function provideMakeUrlIndexes() {
898 return array(
899 array(
900 // just a regular :)
901 'https://bugzilla.wikimedia.org/show_bug.cgi?id=28627',
902 array( 'https://org.wikimedia.bugzilla./show_bug.cgi?id=28627' )
903 ),
904 array(
905 // mailtos are handled special
906 // is this really right though? that final . probably belongs earlier?
907 'mailto:wiki@wikimedia.org',
908 array( 'mailto:org.wikimedia@wiki.' )
909 ),
910
911 // file URL cases per bug 28627...
912 array(
913 // three slashes: local filesystem path Unix-style
914 'file:///whatever/you/like.txt',
915 array( 'file://./whatever/you/like.txt' )
916 ),
917 array(
918 // three slashes: local filesystem path Windows-style
919 'file:///c:/whatever/you/like.txt',
920 array( 'file://./c:/whatever/you/like.txt' )
921 ),
922 array(
923 // two slashes: UNC filesystem path Windows-style
924 'file://intranet/whatever/you/like.txt',
925 array( 'file://intranet./whatever/you/like.txt' )
926 ),
927 // Multiple-slash cases that can sorta work on Mozilla
928 // if you hack it just right are kinda pathological,
929 // and unreliable cross-platform or on IE which means they're
930 // unlikely to appear on intranets.
931 //
932 // Those will survive the algorithm but with results that
933 // are less consistent.
934
935 // protocol-relative URL cases per bug 29854...
936 array(
937 '//bugzilla.wikimedia.org/show_bug.cgi?id=28627',
938 array(
939 'http://org.wikimedia.bugzilla./show_bug.cgi?id=28627',
940 'https://org.wikimedia.bugzilla./show_bug.cgi?id=28627'
941 )
942 ),
943 );
944 }
945
946 /**
947 * @dataProvider provideWfMatchesDomainList
948 */
949 function testWfMatchesDomainList( $url, $domains, $expected, $description ) {
950 $actual = wfMatchesDomainList( $url, $domains );
951 $this->assertEquals( $expected, $actual, $description );
952 }
953
954 function provideWfMatchesDomainList() {
955 $a = array();
956 $protocols = array( 'HTTP' => 'http:', 'HTTPS' => 'https:', 'protocol-relative' => '' );
957 foreach ( $protocols as $pDesc => $p ) {
958 $a = array_merge( $a, array(
959 array( "$p//www.example.com", array(), false, "No matches for empty domains array, $pDesc URL" ),
960 array( "$p//www.example.com", array( 'www.example.com' ), true, "Exact match in domains array, $pDesc URL" ),
961 array( "$p//www.example.com", array( 'example.com' ), true, "Match without subdomain in domains array, $pDesc URL" ),
962 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" ),
963 array( "$p//www.example2.com", array( 'example.com', 'example2.com', 'example3,com' ), true, "Match without subdomain with other domains in array, $pDesc URL" ),
964 array( "$p//www.example4.com", array( 'example.com', 'example2.com', 'example3,com' ), false, "Domain not in array, $pDesc URL" ),
965
966 // FIXME: This is a bug in wfMatchesDomainList(). If and when this is fixed, update this test case
967 array( "$p//nds-nl.wikipedia.org", array( 'nl.wikipedia.org' ), true, "Substrings of domains match while they shouldn't, $pDesc URL" ),
968 ) );
969 }
970 return $a;
971 }
972
973 /**
974 * @dataProvider provideWfShellMaintenanceCmdList
975 */
976 function testWfShellMaintenanceCmd( $script, $parameters, $options, $expected, $description ) {
977 if( wfIsWindows() ) {
978 // Approximation that's good enough for our purposes just now
979 $expected = str_replace( "'", '"', $expected );
980 }
981 $actual = wfShellMaintenanceCmd( $script, $parameters, $options );
982 $this->assertEquals( $expected, $actual, $description );
983 }
984
985 function provideWfShellMaintenanceCmdList() {
986 global $wgPhpCli;
987 return array(
988 array( 'eval.php', array( '--help', '--test' ), array(),
989 "'$wgPhpCli' 'eval.php' '--help' '--test'",
990 "Called eval.php --help --test" ),
991 array( 'eval.php', array( '--help', '--test space' ), array('php' => 'php5'),
992 "'php5' 'eval.php' '--help' '--test space'",
993 "Called eval.php --help --test with php option" ),
994 array( 'eval.php', array( '--help', '--test', 'X' ), array('wrapper' => 'MWScript.php'),
995 "'$wgPhpCli' 'MWScript.php' 'eval.php' '--help' '--test' 'X'",
996 "Called eval.php --help --test with wrapper option" ),
997 array( 'eval.php', array( '--help', '--test', 'y' ), array('php' => 'php5', 'wrapper' => 'MWScript.php'),
998 "'php5' 'MWScript.php' 'eval.php' '--help' '--test' 'y'",
999 "Called eval.php --help --test with wrapper and php option" ),
1000 );
1001 }
1002 /* TODO: many more! */
1003 }
1004
1005
1006 class MockOutputPage {
1007
1008 public $message;
1009
1010 function debug( $message ) {
1011 $this->message = "JAJA is a stupid error message. Anyway, here's your message: $message";
1012 }
1013 }
1014