Merge "Add SVG versions of enhanced recent changes collapse/show arrows"
[lhc/web/wiklou.git] / tests / phpunit / languages / LanguageTest.php
1 <?php
2
3 class LanguageTest extends LanguageClassesTestCase {
4 /**
5 * @covers Language::convertDoubleWidth
6 * @covers Language::normalizeForSearch
7 */
8 public function testLanguageConvertDoubleWidthToSingleWidth() {
9 $this->assertEquals(
10 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
11 $this->getLang()->normalizeForSearch(
12 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
13 ),
14 'convertDoubleWidth() with the full alphabet and digits'
15 );
16 }
17
18 /**
19 * @dataProvider provideFormattableTimes#
20 * @covers Language::formatTimePeriod
21 */
22 public function testFormatTimePeriod( $seconds, $format, $expected, $desc ) {
23 $this->assertEquals( $expected, $this->getLang()->formatTimePeriod( $seconds, $format ), $desc );
24 }
25
26 public static function provideFormattableTimes() {
27 return array(
28 array(
29 9.45,
30 array(),
31 '9.5 s',
32 'formatTimePeriod() rounding (<10s)'
33 ),
34 array(
35 9.45,
36 array( 'noabbrevs' => true ),
37 '9.5 seconds',
38 'formatTimePeriod() rounding (<10s)'
39 ),
40 array(
41 9.95,
42 array(),
43 '10 s',
44 'formatTimePeriod() rounding (<10s)'
45 ),
46 array(
47 9.95,
48 array( 'noabbrevs' => true ),
49 '10 seconds',
50 'formatTimePeriod() rounding (<10s)'
51 ),
52 array(
53 59.55,
54 array(),
55 '1 min 0 s',
56 'formatTimePeriod() rounding (<60s)'
57 ),
58 array(
59 59.55,
60 array( 'noabbrevs' => true ),
61 '1 minute 0 seconds',
62 'formatTimePeriod() rounding (<60s)'
63 ),
64 array(
65 119.55,
66 array(),
67 '2 min 0 s',
68 'formatTimePeriod() rounding (<1h)'
69 ),
70 array(
71 119.55,
72 array( 'noabbrevs' => true ),
73 '2 minutes 0 seconds',
74 'formatTimePeriod() rounding (<1h)'
75 ),
76 array(
77 3599.55,
78 array(),
79 '1 h 0 min 0 s',
80 'formatTimePeriod() rounding (<1h)'
81 ),
82 array(
83 3599.55,
84 array( 'noabbrevs' => true ),
85 '1 hour 0 minutes 0 seconds',
86 'formatTimePeriod() rounding (<1h)'
87 ),
88 array(
89 7199.55,
90 array(),
91 '2 h 0 min 0 s',
92 'formatTimePeriod() rounding (>=1h)'
93 ),
94 array(
95 7199.55,
96 array( 'noabbrevs' => true ),
97 '2 hours 0 minutes 0 seconds',
98 'formatTimePeriod() rounding (>=1h)'
99 ),
100 array(
101 7199.55,
102 'avoidseconds',
103 '2 h 0 min',
104 'formatTimePeriod() rounding (>=1h), avoidseconds'
105 ),
106 array(
107 7199.55,
108 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
109 '2 hours 0 minutes',
110 'formatTimePeriod() rounding (>=1h), avoidseconds'
111 ),
112 array(
113 7199.55,
114 'avoidminutes',
115 '2 h 0 min',
116 'formatTimePeriod() rounding (>=1h), avoidminutes'
117 ),
118 array(
119 7199.55,
120 array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ),
121 '2 hours 0 minutes',
122 'formatTimePeriod() rounding (>=1h), avoidminutes'
123 ),
124 array(
125 172799.55,
126 'avoidseconds',
127 '48 h 0 min',
128 'formatTimePeriod() rounding (=48h), avoidseconds'
129 ),
130 array(
131 172799.55,
132 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
133 '48 hours 0 minutes',
134 'formatTimePeriod() rounding (=48h), avoidseconds'
135 ),
136 array(
137 259199.55,
138 'avoidminutes',
139 '3 d 0 h',
140 'formatTimePeriod() rounding (>48h), avoidminutes'
141 ),
142 array(
143 259199.55,
144 array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ),
145 '3 days 0 hours',
146 'formatTimePeriod() rounding (>48h), avoidminutes'
147 ),
148 array(
149 176399.55,
150 'avoidseconds',
151 '2 d 1 h 0 min',
152 'formatTimePeriod() rounding (>48h), avoidseconds'
153 ),
154 array(
155 176399.55,
156 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
157 '2 days 1 hour 0 minutes',
158 'formatTimePeriod() rounding (>48h), avoidseconds'
159 ),
160 array(
161 176399.55,
162 'avoidminutes',
163 '2 d 1 h',
164 'formatTimePeriod() rounding (>48h), avoidminutes'
165 ),
166 array(
167 176399.55,
168 array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ),
169 '2 days 1 hour',
170 'formatTimePeriod() rounding (>48h), avoidminutes'
171 ),
172 array(
173 259199.55,
174 'avoidseconds',
175 '3 d 0 h 0 min',
176 'formatTimePeriod() rounding (>48h), avoidseconds'
177 ),
178 array(
179 259199.55,
180 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
181 '3 days 0 hours 0 minutes',
182 'formatTimePeriod() rounding (>48h), avoidseconds'
183 ),
184 array(
185 172801.55,
186 'avoidseconds',
187 '2 d 0 h 0 min',
188 'formatTimePeriod() rounding, (>48h), avoidseconds'
189 ),
190 array(
191 172801.55,
192 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
193 '2 days 0 hours 0 minutes',
194 'formatTimePeriod() rounding, (>48h), avoidseconds'
195 ),
196 array(
197 176460.55,
198 array(),
199 '2 d 1 h 1 min 1 s',
200 'formatTimePeriod() rounding, recursion, (>48h)'
201 ),
202 array(
203 176460.55,
204 array( 'noabbrevs' => true ),
205 '2 days 1 hour 1 minute 1 second',
206 'formatTimePeriod() rounding, recursion, (>48h)'
207 ),
208 );
209 }
210
211 /**
212 * @covers Language::truncate
213 */
214 public function testTruncate() {
215 $this->assertEquals(
216 "XXX",
217 $this->getLang()->truncate( "1234567890", 0, 'XXX' ),
218 'truncate prefix, len 0, small ellipsis'
219 );
220
221 $this->assertEquals(
222 "12345XXX",
223 $this->getLang()->truncate( "1234567890", 8, 'XXX' ),
224 'truncate prefix, small ellipsis'
225 );
226
227 $this->assertEquals(
228 "123456789",
229 $this->getLang()->truncate( "123456789", 5, 'XXXXXXXXXXXXXXX' ),
230 'truncate prefix, large ellipsis'
231 );
232
233 $this->assertEquals(
234 "XXX67890",
235 $this->getLang()->truncate( "1234567890", -8, 'XXX' ),
236 'truncate suffix, small ellipsis'
237 );
238
239 $this->assertEquals(
240 "123456789",
241 $this->getLang()->truncate( "123456789", -5, 'XXXXXXXXXXXXXXX' ),
242 'truncate suffix, large ellipsis'
243 );
244 $this->assertEquals(
245 "123XXX",
246 $this->getLang()->truncate( "123 ", 9, 'XXX' ),
247 'truncate prefix, with spaces'
248 );
249 $this->assertEquals(
250 "12345XXX",
251 $this->getLang()->truncate( "12345 8", 11, 'XXX' ),
252 'truncate prefix, with spaces and non-space ending'
253 );
254 $this->assertEquals(
255 "XXX234",
256 $this->getLang()->truncate( "1 234", -8, 'XXX' ),
257 'truncate suffix, with spaces'
258 );
259 $this->assertEquals(
260 "12345XXX",
261 $this->getLang()->truncate( "1234567890", 5, 'XXX', false ),
262 'truncate without adjustment'
263 );
264 }
265
266 /**
267 * @dataProvider provideHTMLTruncateData
268 * @covers Language::truncateHTML
269 */
270 public function testTruncateHtml( $len, $ellipsis, $input, $expected ) {
271 // Actual HTML...
272 $this->assertEquals(
273 $expected,
274 $this->getLang()->truncateHTML( $input, $len, $ellipsis )
275 );
276 }
277
278 /**
279 * @return array format is ($len, $ellipsis, $input, $expected)
280 */
281 public static function provideHTMLTruncateData() {
282 return array(
283 array( 0, 'XXX', "1234567890", "XXX" ),
284 array( 8, 'XXX', "1234567890", "12345XXX" ),
285 array( 5, 'XXXXXXXXXXXXXXX', '1234567890', "1234567890" ),
286 array( 2, '***',
287 '<p><span style="font-weight:bold;"></span></p>',
288 '<p><span style="font-weight:bold;"></span></p>',
289 ),
290 array( 2, '***',
291 '<p><span style="font-weight:bold;">123456789</span></p>',
292 '<p><span style="font-weight:bold;">***</span></p>',
293 ),
294 array( 2, '***',
295 '<p><span style="font-weight:bold;">&nbsp;23456789</span></p>',
296 '<p><span style="font-weight:bold;">***</span></p>',
297 ),
298 array( 3, '***',
299 '<p><span style="font-weight:bold;">123456789</span></p>',
300 '<p><span style="font-weight:bold;">***</span></p>',
301 ),
302 array( 4, '***',
303 '<p><span style="font-weight:bold;">123456789</span></p>',
304 '<p><span style="font-weight:bold;">1***</span></p>',
305 ),
306 array( 5, '***',
307 '<tt><span style="font-weight:bold;">123456789</span></tt>',
308 '<tt><span style="font-weight:bold;">12***</span></tt>',
309 ),
310 array( 6, '***',
311 '<p><a href="www.mediawiki.org">123456789</a></p>',
312 '<p><a href="www.mediawiki.org">123***</a></p>',
313 ),
314 array( 6, '***',
315 '<p><a href="www.mediawiki.org">12&nbsp;456789</a></p>',
316 '<p><a href="www.mediawiki.org">12&nbsp;***</a></p>',
317 ),
318 array( 7, '***',
319 '<small><span style="font-weight:bold;">123<p id="#moo">456</p>789</span></small>',
320 '<small><span style="font-weight:bold;">123<p id="#moo">4***</p></span></small>',
321 ),
322 array( 8, '***',
323 '<div><span style="font-weight:bold;">123<span>4</span>56789</span></div>',
324 '<div><span style="font-weight:bold;">123<span>4</span>5***</span></div>',
325 ),
326 array( 9, '***',
327 '<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>',
328 '<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>',
329 ),
330 array( 10, '***',
331 '<p><font style="font-weight:bold;">123456789</font></p>',
332 '<p><font style="font-weight:bold;">123456789</font></p>',
333 ),
334 );
335 }
336
337 /**
338 * Test Language::isWellFormedLanguageTag()
339 * @dataProvider provideWellFormedLanguageTags
340 * @covers Language::isWellFormedLanguageTag
341 */
342 public function testWellFormedLanguageTag( $code, $message = '' ) {
343 $this->assertTrue(
344 Language::isWellFormedLanguageTag( $code ),
345 "validating code $code $message"
346 );
347 }
348
349 /**
350 * The test cases are based on the tests in the GaBuZoMeu parser
351 * written by Stéphane Bortzmeyer <bortzmeyer@nic.fr>
352 * and distributed as free software, under the GNU General Public Licence.
353 * http://www.bortzmeyer.org/gabuzomeu-parsing-language-tags.html
354 */
355 public static function provideWellFormedLanguageTags() {
356 return array(
357 array( 'fr', 'two-letter code' ),
358 array( 'fr-latn', 'two-letter code with lower case script code' ),
359 array( 'fr-Latn-FR', 'two-letter code with title case script code and uppercase country code' ),
360 array( 'fr-Latn-419', 'two-letter code with title case script code and region number' ),
361 array( 'fr-FR', 'two-letter code with uppercase' ),
362 array( 'ax-TZ', 'Not in the registry, but well-formed' ),
363 array( 'fr-shadok', 'two-letter code with variant' ),
364 array( 'fr-y-myext-myext2', 'non-x singleton' ),
365 array( 'fra-Latn', 'ISO 639 can be 3-letters' ),
366 array( 'fra', 'three-letter language code' ),
367 array( 'fra-FX', 'three-letter language code with country code' ),
368 array( 'i-klingon', 'grandfathered with singleton' ),
369 array( 'I-kLINgon', 'tags are case-insensitive...' ),
370 array( 'no-bok', 'grandfathered without singleton' ),
371 array( 'i-enochian', 'Grandfathered' ),
372 array( 'x-fr-CH', 'private use' ),
373 array( 'es-419', 'two-letter code with region number' ),
374 array( 'en-Latn-GB-boont-r-extended-sequence-x-private', 'weird, but well-formed' ),
375 array( 'ab-x-abc-x-abc', 'anything goes after x' ),
376 array( 'ab-x-abc-a-a', 'anything goes after x, including several non-x singletons' ),
377 array( 'i-default', 'grandfathered' ),
378 array( 'abcd-Latn', 'Language of 4 chars reserved for future use' ),
379 array( 'AaBbCcDd-x-y-any-x', 'Language of 5-8 chars, registered' ),
380 array( 'de-CH-1901', 'with country and year' ),
381 array( 'en-US-x-twain', 'with country and singleton' ),
382 array( 'zh-cmn', 'three-letter variant' ),
383 array( 'zh-cmn-Hant', 'three-letter variant and script' ),
384 array( 'zh-cmn-Hant-HK', 'three-letter variant, script and country' ),
385 array( 'xr-p-lze', 'Extension' ),
386 );
387 }
388
389 /**
390 * Negative test for Language::isWellFormedLanguageTag()
391 * @dataProvider provideMalformedLanguageTags
392 * @covers Language::isWellFormedLanguageTag
393 */
394 public function testMalformedLanguageTag( $code, $message = '' ) {
395 $this->assertFalse(
396 Language::isWellFormedLanguageTag( $code ),
397 "validating that code $code is a malformed language tag - $message"
398 );
399 }
400
401 /**
402 * The test cases are based on the tests in the GaBuZoMeu parser
403 * written by Stéphane Bortzmeyer <bortzmeyer@nic.fr>
404 * and distributed as free software, under the GNU General Public Licence.
405 * http://www.bortzmeyer.org/gabuzomeu-parsing-language-tags.html
406 */
407 public static function provideMalformedLanguageTags() {
408 return array(
409 array( 'f', 'language too short' ),
410 array( 'f-Latn', 'language too short with script' ),
411 array( 'xr-lxs-qut', 'variants too short' ), # extlangS
412 array( 'fr-Latn-F', 'region too short' ),
413 array( 'a-value', 'language too short with region' ),
414 array( 'tlh-a-b-foo', 'valid three-letter with wrong variant' ),
415 array( 'i-notexist', 'grandfathered but not registered: invalid, even if we only test well-formedness' ),
416 array( 'abcdefghi-012345678', 'numbers too long' ),
417 array( 'ab-abc-abc-abc-abc', 'invalid extensions' ),
418 array( 'ab-abcd-abc', 'invalid extensions' ),
419 array( 'ab-ab-abc', 'invalid extensions' ),
420 array( 'ab-123-abc', 'invalid extensions' ),
421 array( 'a-Hant-ZH', 'short language with valid extensions' ),
422 array( 'a1-Hant-ZH', 'invalid character in language' ),
423 array( 'ab-abcde-abc', 'invalid extensions' ),
424 array( 'ab-1abc-abc', 'invalid characters in extensions' ),
425 array( 'ab-ab-abcd', 'invalid order of extensions' ),
426 array( 'ab-123-abcd', 'invalid order of extensions' ),
427 array( 'ab-abcde-abcd', 'invalid extensions' ),
428 array( 'ab-1abc-abcd', 'invalid characters in extensions' ),
429 array( 'ab-a-b', 'extensions too short' ),
430 array( 'ab-a-x', 'extensions too short, even with singleton' ),
431 array( 'ab--ab', 'two separators' ),
432 array( 'ab-abc-', 'separator in the end' ),
433 array( '-ab-abc', 'separator in the beginning' ),
434 array( 'abcd-efg', 'language too long' ),
435 array( 'aabbccddE', 'tag too long' ),
436 array( 'pa_guru', 'A tag with underscore is invalid in strict mode' ),
437 array( 'de-f', 'subtag too short' ),
438 );
439 }
440
441 /**
442 * Negative test for Language::isWellFormedLanguageTag()
443 * @covers Language::isWellFormedLanguageTag
444 */
445 public function testLenientLanguageTag() {
446 $this->assertTrue(
447 Language::isWellFormedLanguageTag( 'pa_guru', true ),
448 'pa_guru is a well-formed language tag in lenient mode'
449 );
450 }
451
452 /**
453 * Test Language::isValidBuiltInCode()
454 * @dataProvider provideLanguageCodes
455 * @covers Language::isValidBuiltInCode
456 */
457 public function testBuiltInCodeValidation( $code, $message = '' ) {
458 $this->assertTrue(
459 (bool)Language::isValidBuiltInCode( $code ),
460 "validating code $code $message"
461 );
462 }
463
464 /**
465 * @covers Language::isValidBuiltInCode
466 */
467 public function testBuiltInCodeValidationRejectUnderscore() {
468 $this->assertFalse(
469 (bool)Language::isValidBuiltInCode( 'be_tarask' ),
470 "reject underscore in language code"
471 );
472 }
473
474 public static function provideLanguageCodes() {
475 return array(
476 array( 'fr', 'Two letters, minor case' ),
477 array( 'EN', 'Two letters, upper case' ),
478 array( 'tyv', 'Three letters' ),
479 array( 'tokipona', 'long language code' ),
480 array( 'be-tarask', 'With dash' ),
481 array( 'Zh-classical', 'Begin with upper case, dash' ),
482 array( 'Be-x-old', 'With extension (two dashes)' ),
483 );
484 }
485
486 /**
487 * Test Language::isKnownLanguageTag()
488 * @dataProvider provideKnownLanguageTags
489 * @covers Language::isKnownLanguageTag
490 */
491 public function testKnownLanguageTag( $code, $message = '' ) {
492 $this->assertTrue(
493 (bool)Language::isKnownLanguageTag( $code ),
494 "validating code $code - $message"
495 );
496 }
497
498 public static function provideKnownLanguageTags() {
499 return array(
500 array( 'fr', 'simple code' ),
501 array( 'bat-smg', 'an MW legacy tag' ),
502 array( 'sgs', 'an internal standard MW name, for which a legacy tag is used externally' ),
503 );
504 }
505
506 /**
507 * @covers Language::isKnownLanguageTag
508 */
509 public function testKnownCldrLanguageTag() {
510 if ( !class_exists( 'LanguageNames' ) ) {
511 $this->markTestSkipped( 'The LanguageNames class is not available. The cldr extension is probably not installed.' );
512 }
513
514 $this->assertTrue(
515 (bool)Language::isKnownLanguageTag( 'pal' ),
516 'validating code "pal" an ancient language, which probably will not appear in Names.php, but appears in CLDR in English'
517 );
518 }
519
520 /**
521 * Negative tests for Language::isKnownLanguageTag()
522 * @dataProvider provideUnKnownLanguageTags
523 * @covers Language::isKnownLanguageTag
524 */
525 public function testUnknownLanguageTag( $code, $message = '' ) {
526 $this->assertFalse(
527 (bool)Language::isKnownLanguageTag( $code ),
528 "checking that code $code is invalid - $message"
529 );
530 }
531
532 public static function provideUnknownLanguageTags() {
533 return array(
534 array( 'mw', 'non-existent two-letter code' ),
535 array( 'foo"<bar', 'very invalid language code' ),
536 );
537 }
538
539 /**
540 * Test too short timestamp
541 * @expectedException MWException
542 * @covers Language::sprintfDate
543 */
544 public function testSprintfDateTooShortTimestamp() {
545 $this->getLang()->sprintfDate( 'xiY', '1234567890123' );
546 }
547
548 /**
549 * Test too long timestamp
550 * @expectedException MWException
551 * @covers Language::sprintfDate
552 */
553 public function testSprintfDateTooLongTimestamp() {
554 $this->getLang()->sprintfDate( 'xiY', '123456789012345' );
555 }
556
557 /**
558 * Test too short timestamp
559 * @expectedException MWException
560 * @covers Language::sprintfDate
561 */
562 public function testSprintfDateNotAllDigitTimestamp() {
563 $this->getLang()->sprintfDate( 'xiY', '-1234567890123' );
564 }
565
566 /**
567 * @dataProvider provideSprintfDateSamples
568 * @covers Language::sprintfDate
569 */
570 public function testSprintfDate( $format, $ts, $expected, $msg ) {
571 $this->assertEquals(
572 $expected,
573 $this->getLang()->sprintfDate( $format, $ts ),
574 "sprintfDate('$format', '$ts'): $msg"
575 );
576 }
577
578 /**
579 * sprintfDate should always use UTC when no zone is given.
580 * @dataProvider provideSprintfDateSamples
581 * @covers Language::sprintfDate
582 */
583 public function testSprintfDateNoZone( $format, $ts, $expected, $ignore, $msg ) {
584 $oldTZ = date_default_timezone_get();
585 $res = date_default_timezone_set( 'Asia/Seoul' );
586 if ( !$res ) {
587 $this->markTestSkipped( "Error setting Timezone" );
588 }
589
590 $this->assertEquals(
591 $expected,
592 $this->getLang()->sprintfDate( $format, $ts ),
593 "sprintfDate('$format', '$ts'): $msg"
594 );
595
596 date_default_timezone_set( $oldTZ );
597 }
598
599 /**
600 * sprintfDate should use passed timezone
601 * @dataProvider provideSprintfDateSamples
602 * @covers Language::sprintfDate
603 */
604 public function testSprintfDateTZ( $format, $ts, $ignore, $expected, $msg ) {
605 $tz = new DateTimeZone( 'Asia/Seoul' );
606 if ( !$tz ) {
607 $this->markTestSkipped( "Error getting Timezone" );
608 }
609
610 $this->assertEquals(
611 $expected,
612 $this->getLang()->sprintfDate( $format, $ts, $tz ),
613 "sprintfDate('$format', '$ts', 'Asia/Seoul'): $msg"
614 );
615 }
616
617 public static function provideSprintfDateSamples() {
618 return array(
619 array(
620 'xiY',
621 '20111212000000',
622 '1390', // note because we're testing English locale we get Latin-standard digits
623 '1390',
624 'Iranian calendar full year'
625 ),
626 array(
627 'xiy',
628 '20111212000000',
629 '90',
630 '90',
631 'Iranian calendar short year'
632 ),
633 array(
634 'o',
635 '20120101235000',
636 '2011',
637 '2011',
638 'ISO 8601 (week) year'
639 ),
640 array(
641 'W',
642 '20120101235000',
643 '52',
644 '52',
645 'Week number'
646 ),
647 array(
648 'W',
649 '20120102235000',
650 '1',
651 '1',
652 'Week number'
653 ),
654 array(
655 'o-\\WW-N',
656 '20091231235000',
657 '2009-W53-4',
658 '2009-W53-4',
659 'leap week'
660 ),
661 // What follows is mostly copied from http://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time
662 array(
663 'Y',
664 '20120102090705',
665 '2012',
666 '2012',
667 'Full year'
668 ),
669 array(
670 'y',
671 '20120102090705',
672 '12',
673 '12',
674 '2 digit year'
675 ),
676 array(
677 'L',
678 '20120102090705',
679 '1',
680 '1',
681 'Leap year'
682 ),
683 array(
684 'n',
685 '20120102090705',
686 '1',
687 '1',
688 'Month index, not zero pad'
689 ),
690 array(
691 'N',
692 '20120102090705',
693 '01',
694 '01',
695 'Month index. Zero pad'
696 ),
697 array(
698 'M',
699 '20120102090705',
700 'Jan',
701 'Jan',
702 'Month abbrev'
703 ),
704 array(
705 'F',
706 '20120102090705',
707 'January',
708 'January',
709 'Full month'
710 ),
711 array(
712 'xg',
713 '20120102090705',
714 'January',
715 'January',
716 'Genitive month name (same in EN)'
717 ),
718 array(
719 'j',
720 '20120102090705',
721 '2',
722 '2',
723 'Day of month (not zero pad)'
724 ),
725 array(
726 'd',
727 '20120102090705',
728 '02',
729 '02',
730 'Day of month (zero-pad)'
731 ),
732 array(
733 'z',
734 '20120102090705',
735 '1',
736 '1',
737 'Day of year (zero-indexed)'
738 ),
739 array(
740 'D',
741 '20120102090705',
742 'Mon',
743 'Mon',
744 'Day of week (abbrev)'
745 ),
746 array(
747 'l',
748 '20120102090705',
749 'Monday',
750 'Monday',
751 'Full day of week'
752 ),
753 array(
754 'N',
755 '20120101090705',
756 '7',
757 '7',
758 'Day of week (Mon=1, Sun=7)'
759 ),
760 array(
761 'w',
762 '20120101090705',
763 '0',
764 '0',
765 'Day of week (Sun=0, Sat=6)'
766 ),
767 array(
768 'N',
769 '20120102090705',
770 '1',
771 '1',
772 'Day of week'
773 ),
774 array(
775 'a',
776 '20120102090705',
777 'am',
778 'am',
779 'am vs pm'
780 ),
781 array(
782 'A',
783 '20120102120000',
784 'PM',
785 'PM',
786 'AM vs PM'
787 ),
788 array(
789 'a',
790 '20120102000000',
791 'am',
792 'am',
793 'AM vs PM'
794 ),
795 array(
796 'g',
797 '20120102090705',
798 '9',
799 '9',
800 '12 hour, not Zero'
801 ),
802 array(
803 'h',
804 '20120102090705',
805 '09',
806 '09',
807 '12 hour, zero padded'
808 ),
809 array(
810 'G',
811 '20120102090705',
812 '9',
813 '9',
814 '24 hour, not zero'
815 ),
816 array(
817 'H',
818 '20120102090705',
819 '09',
820 '09',
821 '24 hour, zero'
822 ),
823 array(
824 'H',
825 '20120102110705',
826 '11',
827 '11',
828 '24 hour, zero'
829 ),
830 array(
831 'i',
832 '20120102090705',
833 '07',
834 '07',
835 'Minutes'
836 ),
837 array(
838 's',
839 '20120102090705',
840 '05',
841 '05',
842 'seconds'
843 ),
844 array(
845 'U',
846 '20120102090705',
847 '1325495225',
848 '1325462825',
849 'unix time'
850 ),
851 array(
852 't',
853 '20120102090705',
854 '31',
855 '31',
856 'Days in current month'
857 ),
858 array(
859 'c',
860 '20120102090705',
861 '2012-01-02T09:07:05+00:00',
862 '2012-01-02T09:07:05+09:00',
863 'ISO 8601 timestamp'
864 ),
865 array(
866 'r',
867 '20120102090705',
868 'Mon, 02 Jan 2012 09:07:05 +0000',
869 'Mon, 02 Jan 2012 09:07:05 +0900',
870 'RFC 5322'
871 ),
872 array(
873 'e',
874 '20120102090705',
875 'UTC',
876 'Asia/Seoul',
877 'Timezone identifier'
878 ),
879 array(
880 'I',
881 '19880602090705',
882 '0',
883 '1',
884 'DST indicator'
885 ),
886 array(
887 'O',
888 '20120102090705',
889 '+0000',
890 '+0900',
891 'Timezone offset'
892 ),
893 array(
894 'P',
895 '20120102090705',
896 '+00:00',
897 '+09:00',
898 'Timezone offset with colon'
899 ),
900 array(
901 'T',
902 '20120102090705',
903 'UTC',
904 'KST',
905 'Timezone abbreviation'
906 ),
907 array(
908 'Z',
909 '20120102090705',
910 '0',
911 '32400',
912 'Timezone offset in seconds'
913 ),
914 array(
915 'xmj xmF xmn xmY',
916 '20120102090705',
917 '7 Safar 2 1433',
918 '7 Safar 2 1433',
919 'Islamic'
920 ),
921 array(
922 'xij xiF xin xiY',
923 '20120102090705',
924 '12 Dey 10 1390',
925 '12 Dey 10 1390',
926 'Iranian'
927 ),
928 array(
929 'xjj xjF xjn xjY',
930 '20120102090705',
931 '7 Tevet 4 5772',
932 '7 Tevet 4 5772',
933 'Hebrew'
934 ),
935 array(
936 'xjt',
937 '20120102090705',
938 '29',
939 '29',
940 'Hebrew number of days in month'
941 ),
942 array(
943 'xjx',
944 '20120102090705',
945 'Tevet',
946 'Tevet',
947 'Hebrew genitive month name (No difference in EN)'
948 ),
949 array(
950 'xkY',
951 '20120102090705',
952 '2555',
953 '2555',
954 'Thai year'
955 ),
956 array(
957 'xoY',
958 '20120102090705',
959 '101',
960 '101',
961 'Minguo'
962 ),
963 array(
964 'xtY',
965 '20120102090705',
966 '平成24',
967 '平成24',
968 'nengo'
969 ),
970 array(
971 'xrxkYY',
972 '20120102090705',
973 'MMDLV2012',
974 'MMDLV2012',
975 'Roman numerals'
976 ),
977 array(
978 'xhxjYY',
979 '20120102090705',
980 \'תשע"ב2012',
981 \'תשע"ב2012',
982 'Hebrew numberals'
983 ),
984 array(
985 'xnY',
986 '20120102090705',
987 '2012',
988 '2012',
989 'Raw numerals (doesn\'t mean much in EN)'
990 ),
991 array(
992 '[[Y "(yea"\\r)]] \\"xx\\"',
993 '20120102090705',
994 '[[2012 (year)]] "x"',
995 '[[2012 (year)]] "x"',
996 'Various escaping'
997 ),
998
999 );
1000 }
1001
1002 /**
1003 * @dataProvider provideFormatSizes
1004 * @covers Language::formatSize
1005 */
1006 public function testFormatSize( $size, $expected, $msg ) {
1007 $this->assertEquals(
1008 $expected,
1009 $this->getLang()->formatSize( $size ),
1010 "formatSize('$size'): $msg"
1011 );
1012 }
1013
1014 public static function provideFormatSizes() {
1015 return array(
1016 array(
1017 0,
1018 "0 B",
1019 "Zero bytes"
1020 ),
1021 array(
1022 1024,
1023 "1 KB",
1024 "1 kilobyte"
1025 ),
1026 array(
1027 1024 * 1024,
1028 "1 MB",
1029 "1,024 megabytes"
1030 ),
1031 array(
1032 1024 * 1024 * 1024,
1033 "1 GB",
1034 "1 gigabytes"
1035 ),
1036 array(
1037 pow( 1024, 4 ),
1038 "1 TB",
1039 "1 terabyte"
1040 ),
1041 array(
1042 pow( 1024, 5 ),
1043 "1 PB",
1044 "1 petabyte"
1045 ),
1046 array(
1047 pow( 1024, 6 ),
1048 "1 EB",
1049 "1,024 exabyte"
1050 ),
1051 array(
1052 pow( 1024, 7 ),
1053 "1 ZB",
1054 "1 zetabyte"
1055 ),
1056 array(
1057 pow( 1024, 8 ),
1058 "1 YB",
1059 "1 yottabyte"
1060 ),
1061 // How big!? THIS BIG!
1062 );
1063 }
1064
1065 /**
1066 * @dataProvider provideFormatBitrate
1067 * @covers Language::formatBitrate
1068 */
1069 public function testFormatBitrate( $bps, $expected, $msg ) {
1070 $this->assertEquals(
1071 $expected,
1072 $this->getLang()->formatBitrate( $bps ),
1073 "formatBitrate('$bps'): $msg"
1074 );
1075 }
1076
1077 public static function provideFormatBitrate() {
1078 return array(
1079 array(
1080 0,
1081 "0 bps",
1082 "0 bits per second"
1083 ),
1084 array(
1085 999,
1086 "999 bps",
1087 "999 bits per second"
1088 ),
1089 array(
1090 1000,
1091 "1 kbps",
1092 "1 kilobit per second"
1093 ),
1094 array(
1095 1000 * 1000,
1096 "1 Mbps",
1097 "1 megabit per second"
1098 ),
1099 array(
1100 pow( 10, 9 ),
1101 "1 Gbps",
1102 "1 gigabit per second"
1103 ),
1104 array(
1105 pow( 10, 12 ),
1106 "1 Tbps",
1107 "1 terabit per second"
1108 ),
1109 array(
1110 pow( 10, 15 ),
1111 "1 Pbps",
1112 "1 petabit per second"
1113 ),
1114 array(
1115 pow( 10, 18 ),
1116 "1 Ebps",
1117 "1 exabit per second"
1118 ),
1119 array(
1120 pow( 10, 21 ),
1121 "1 Zbps",
1122 "1 zetabit per second"
1123 ),
1124 array(
1125 pow( 10, 24 ),
1126 "1 Ybps",
1127 "1 yottabit per second"
1128 ),
1129 array(
1130 pow( 10, 27 ),
1131 "1,000 Ybps",
1132 "1,000 yottabits per second"
1133 ),
1134 );
1135 }
1136
1137 /**
1138 * @dataProvider provideFormatDuration
1139 * @covers Language::formatDuration
1140 */
1141 public function testFormatDuration( $duration, $expected, $intervals = array() ) {
1142 $this->assertEquals(
1143 $expected,
1144 $this->getLang()->formatDuration( $duration, $intervals ),
1145 "formatDuration('$duration'): $expected"
1146 );
1147 }
1148
1149 public static function provideFormatDuration() {
1150 return array(
1151 array(
1152 0,
1153 '0 seconds',
1154 ),
1155 array(
1156 1,
1157 '1 second',
1158 ),
1159 array(
1160 2,
1161 '2 seconds',
1162 ),
1163 array(
1164 60,
1165 '1 minute',
1166 ),
1167 array(
1168 2 * 60,
1169 '2 minutes',
1170 ),
1171 array(
1172 3600,
1173 '1 hour',
1174 ),
1175 array(
1176 2 * 3600,
1177 '2 hours',
1178 ),
1179 array(
1180 24 * 3600,
1181 '1 day',
1182 ),
1183 array(
1184 2 * 86400,
1185 '2 days',
1186 ),
1187 array(
1188 // ( 365 + ( 24 * 3 + 25 ) / 400 ) * 86400 = 31556952
1189 ( 365 + ( 24 * 3 + 25 ) / 400.0 ) * 86400,
1190 '1 year',
1191 ),
1192 array(
1193 2 * 31556952,
1194 '2 years',
1195 ),
1196 array(
1197 10 * 31556952,
1198 '1 decade',
1199 ),
1200 array(
1201 20 * 31556952,
1202 '2 decades',
1203 ),
1204 array(
1205 100 * 31556952,
1206 '1 century',
1207 ),
1208 array(
1209 200 * 31556952,
1210 '2 centuries',
1211 ),
1212 array(
1213 1000 * 31556952,
1214 '1 millennium',
1215 ),
1216 array(
1217 2000 * 31556952,
1218 '2 millennia',
1219 ),
1220 array(
1221 9001,
1222 '2 hours, 30 minutes and 1 second'
1223 ),
1224 array(
1225 3601,
1226 '1 hour and 1 second'
1227 ),
1228 array(
1229 31556952 + 2 * 86400 + 9000,
1230 '1 year, 2 days, 2 hours and 30 minutes'
1231 ),
1232 array(
1233 42 * 1000 * 31556952 + 42,
1234 '42 millennia and 42 seconds'
1235 ),
1236 array(
1237 60,
1238 '60 seconds',
1239 array( 'seconds' ),
1240 ),
1241 array(
1242 61,
1243 '61 seconds',
1244 array( 'seconds' ),
1245 ),
1246 array(
1247 1,
1248 '1 second',
1249 array( 'seconds' ),
1250 ),
1251 array(
1252 31556952 + 2 * 86400 + 9000,
1253 '1 year, 2 days and 150 minutes',
1254 array( 'years', 'days', 'minutes' ),
1255 ),
1256 array(
1257 42,
1258 '0 days',
1259 array( 'years', 'days' ),
1260 ),
1261 array(
1262 31556952 + 2 * 86400 + 9000,
1263 '1 year, 2 days and 150 minutes',
1264 array( 'minutes', 'days', 'years' ),
1265 ),
1266 array(
1267 42,
1268 '0 days',
1269 array( 'days', 'years' ),
1270 ),
1271 );
1272 }
1273
1274 /**
1275 * @dataProvider provideCheckTitleEncodingData
1276 * @covers Language::checkTitleEncoding
1277 */
1278 public function testCheckTitleEncoding( $s ) {
1279 $this->assertEquals(
1280 $s,
1281 $this->getLang()->checkTitleEncoding( $s ),
1282 "checkTitleEncoding('$s')"
1283 );
1284 }
1285
1286 public static function provideCheckTitleEncodingData() {
1287 return array(
1288 array( "" ),
1289 array( "United States of America" ), // 7bit ASCII
1290 array( rawurldecode( "S%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e" ) ),
1291 array(
1292 rawurldecode(
1293 "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn"
1294 )
1295 ),
1296 // The following two data sets come from bug 36839. They fail if checkTitleEncoding uses a regexp to test for
1297 // valid UTF-8 encoding and the pcre.recursion_limit is low (like, say, 1024). They succeed if checkTitleEncoding
1298 // uses mb_check_encoding for its test.
1299 array(
1300 rawurldecode(
1301 "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn%7C"
1302 . "Catherine%20Willows%7CDavid%20Hodges%7CDavid%20Phillips%7CGil%20Grissom%7CGreg%20Sanders%7CHodges%7C"
1303 . "Internet%20Movie%20Database%7CJim%20Brass%7CLady%20Heather%7C"
1304 . "Les%20Experts%20(s%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e)%7CLes%20Experts%20:%20Manhattan%7C"
1305 . "Les%20Experts%20:%20Miami%7CListe%20des%20personnages%20des%20Experts%7C"
1306 . "Liste%20des%20%C3%A9pisodes%20des%20Experts%7CMod%C3%A8le%20discussion:Palette%20Les%20Experts%7C"
1307 . "Nick%20Stokes%7CPersonnage%20de%20fiction%7CPersonnage%20fictif%7CPersonnage%20de%20fiction%7C"
1308 . "Personnages%20r%C3%A9currents%20dans%20Les%20Experts%7CRaymond%20Langston%7CRiley%20Adams%7C"
1309 . "Saison%201%20des%20Experts%7CSaison%2010%20des%20Experts%7CSaison%2011%20des%20Experts%7C"
1310 . "Saison%2012%20des%20Experts%7CSaison%202%20des%20Experts%7CSaison%203%20des%20Experts%7C"
1311 . "Saison%204%20des%20Experts%7CSaison%205%20des%20Experts%7CSaison%206%20des%20Experts%7C"
1312 . "Saison%207%20des%20Experts%7CSaison%208%20des%20Experts%7CSaison%209%20des%20Experts%7C"
1313 . "Sara%20Sidle%7CSofia%20Curtis%7CS%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e%7CWallace%20Langham%7C"
1314 . "Warrick%20Brown%7CWendy%20Simms%7C%C3%89tats-Unis"
1315 ),
1316 ),
1317 array(
1318 rawurldecode(
1319 "Mod%C3%A8le%3AArrondissements%20homonymes%7CMod%C3%A8le%3ABandeau%20standard%20pour%20page%20d'homonymie%7C"
1320 . "Mod%C3%A8le%3ABatailles%20homonymes%7CMod%C3%A8le%3ACantons%20homonymes%7C"
1321 . "Mod%C3%A8le%3ACommunes%20fran%C3%A7aises%20homonymes%7CMod%C3%A8le%3AFilms%20homonymes%7C"
1322 . "Mod%C3%A8le%3AGouvernements%20homonymes%7CMod%C3%A8le%3AGuerres%20homonymes%7CMod%C3%A8le%3AHomonymie%7C"
1323 . "Mod%C3%A8le%3AHomonymie%20bateau%7CMod%C3%A8le%3AHomonymie%20d'%C3%A9tablissements%20scolaires%20ou"
1324 . "%20universitaires%7CMod%C3%A8le%3AHomonymie%20d'%C3%AEles%7CMod%C3%A8le%3AHomonymie%20de%20clubs%20sportifs%7C"
1325 . "Mod%C3%A8le%3AHomonymie%20de%20comt%C3%A9s%7CMod%C3%A8le%3AHomonymie%20de%20monument%7C"
1326 . "Mod%C3%A8le%3AHomonymie%20de%20nom%20romain%7CMod%C3%A8le%3AHomonymie%20de%20parti%20politique%7C"
1327 . "Mod%C3%A8le%3AHomonymie%20de%20route%7CMod%C3%A8le%3AHomonymie%20dynastique%7C"
1328 . "Mod%C3%A8le%3AHomonymie%20vid%C3%A9oludique%7CMod%C3%A8le%3AHomonymie%20%C3%A9difice%20religieux%7C"
1329 . "Mod%C3%A8le%3AInternationalisation%7CMod%C3%A8le%3AIsom%C3%A9rie%7CMod%C3%A8le%3AParonymie%7C"
1330 . "Mod%C3%A8le%3APatronyme%7CMod%C3%A8le%3APatronyme%20basque%7CMod%C3%A8le%3APatronyme%20italien%7C"
1331 . "Mod%C3%A8le%3APatronymie%7CMod%C3%A8le%3APersonnes%20homonymes%7CMod%C3%A8le%3ASaints%20homonymes%7C"
1332 . "Mod%C3%A8le%3ATitres%20homonymes%7CMod%C3%A8le%3AToponymie%7CMod%C3%A8le%3AUnit%C3%A9s%20homonymes%7C"
1333 . "Mod%C3%A8le%3AVilles%20homonymes%7CMod%C3%A8le%3A%C3%89difices%20religieux%20homonymes"
1334 )
1335 )
1336 );
1337 }
1338
1339 /**
1340 * @dataProvider provideRomanNumeralsData
1341 * @covers Language::romanNumeral
1342 */
1343 public function testRomanNumerals( $num, $numerals ) {
1344 $this->assertEquals(
1345 $numerals,
1346 Language::romanNumeral( $num ),
1347 "romanNumeral('$num')"
1348 );
1349 }
1350
1351 public static function provideRomanNumeralsData() {
1352 return array(
1353 array( 1, 'I' ),
1354 array( 2, 'II' ),
1355 array( 3, 'III' ),
1356 array( 4, 'IV' ),
1357 array( 5, 'V' ),
1358 array( 6, 'VI' ),
1359 array( 7, 'VII' ),
1360 array( 8, 'VIII' ),
1361 array( 9, 'IX' ),
1362 array( 10, 'X' ),
1363 array( 20, 'XX' ),
1364 array( 30, 'XXX' ),
1365 array( 40, 'XL' ),
1366 array( 49, 'XLIX' ),
1367 array( 50, 'L' ),
1368 array( 60, 'LX' ),
1369 array( 70, 'LXX' ),
1370 array( 80, 'LXXX' ),
1371 array( 90, 'XC' ),
1372 array( 99, 'XCIX' ),
1373 array( 100, 'C' ),
1374 array( 200, 'CC' ),
1375 array( 300, 'CCC' ),
1376 array( 400, 'CD' ),
1377 array( 500, 'D' ),
1378 array( 600, 'DC' ),
1379 array( 700, 'DCC' ),
1380 array( 800, 'DCCC' ),
1381 array( 900, 'CM' ),
1382 array( 999, 'CMXCIX' ),
1383 array( 1000, 'M' ),
1384 array( 1989, 'MCMLXXXIX' ),
1385 array( 2000, 'MM' ),
1386 array( 3000, 'MMM' ),
1387 array( 4000, 'MMMM' ),
1388 array( 5000, 'MMMMM' ),
1389 array( 6000, 'MMMMMM' ),
1390 array( 7000, 'MMMMMMM' ),
1391 array( 8000, 'MMMMMMMM' ),
1392 array( 9000, 'MMMMMMMMM' ),
1393 array( 9999, 'MMMMMMMMMCMXCIX' ),
1394 array( 10000, 'MMMMMMMMMM' ),
1395 );
1396 }
1397
1398 /**
1399 * @dataProvider providePluralData
1400 * @covers Language::convertPlural
1401 */
1402 public function testConvertPlural( $expected, $number, $forms ) {
1403 $chosen = $this->getLang()->convertPlural( $number, $forms );
1404 $this->assertEquals( $expected, $chosen );
1405 }
1406
1407 public static function providePluralData() {
1408 // Params are: [expected text, number given, [the plural forms]]
1409 return array(
1410 array( 'plural', 0, array(
1411 'singular', 'plural'
1412 ) ),
1413 array( 'explicit zero', 0, array(
1414 '0=explicit zero', 'singular', 'plural'
1415 ) ),
1416 array( 'explicit one', 1, array(
1417 'singular', 'plural', '1=explicit one',
1418 ) ),
1419 array( 'singular', 1, array(
1420 'singular', 'plural', '0=explicit zero',
1421 ) ),
1422 array( 'plural', 3, array(
1423 '0=explicit zero', '1=explicit one', 'singular', 'plural'
1424 ) ),
1425 array( 'explicit eleven', 11, array(
1426 'singular', 'plural', '11=explicit eleven',
1427 ) ),
1428 array( 'plural', 12, array(
1429 'singular', 'plural', '11=explicit twelve',
1430 ) ),
1431 array( 'plural', 12, array(
1432 'singular', 'plural', '=explicit form',
1433 ) ),
1434 array( 'other', 2, array(
1435 'kissa=kala', '1=2=3', 'other',
1436 ) ),
1437 array( '', 2, array(
1438 '0=explicit zero', '1=explicit one',
1439 ) ),
1440 );
1441 }
1442
1443 /**
1444 * @covers Language::translateBlockExpiry()
1445 * @dataProvider provideTranslateBlockExpiry
1446 */
1447 public function testTranslateBlockExpiry( $expectedData, $str, $desc ) {
1448 $lang = $this->getLang();
1449 if ( is_array( $expectedData ) ) {
1450 list( $func, $arg ) = $expectedData;
1451 $expected = $lang->$func( $arg );
1452 } else {
1453 $expected = $expectedData;
1454 }
1455 $this->assertEquals( $expected, $lang->translateBlockExpiry( $str ), $desc );
1456 }
1457
1458 public static function provideTranslateBlockExpiry() {
1459 return array(
1460 array( '2 hours', '2 hours', 'simple data from ipboptions' ),
1461 array( 'indefinite', 'infinite', 'infinite from ipboptions' ),
1462 array( 'indefinite', 'infinity', 'alternative infinite from ipboptions' ),
1463 array( 'indefinite', 'indefinite', 'another alternative infinite from ipboptions' ),
1464 array( array( 'formatDuration', 1023 * 60 * 60 ), '1023 hours', 'relative' ),
1465 array( array( 'formatDuration', -1023 ), '-1023 seconds', 'negative relative' ),
1466 array( array( 'formatDuration', 0 ), 'now', 'now' ),
1467 array( array( 'timeanddate', '20120102070000' ), '2012-1-1 7:00 +1 day', 'mixed, handled as absolute' ),
1468 array( array( 'timeanddate', '19910203040506' ), '1991-2-3 4:05:06', 'absolute' ),
1469 array( array( 'timeanddate', '19700101000000' ), '1970-1-1 0:00:00', 'absolute at epoch' ),
1470 array( array( 'timeanddate', '19691231235959' ), '1969-12-31 23:59:59', 'time before epoch' ),
1471 array( 'dummy', 'dummy', 'return garbage as is' ),
1472 );
1473 }
1474
1475 /**
1476 * @covers Language::commafy()
1477 * @dataProvider provideCommafyData
1478 */
1479 public function testCommafy( $number, $numbersWithCommas ) {
1480 $this->assertEquals(
1481 $numbersWithCommas,
1482 $this->getLang()->commafy( $number ),
1483 "commafy('$number')"
1484 );
1485 }
1486
1487 public static function provideCommafyData() {
1488 return array(
1489 array( -1, '-1' ),
1490 array( 10, '10' ),
1491 array( 100, '100' ),
1492 array( 1000, '1,000' ),
1493 array( 10000, '10,000' ),
1494 array( 100000, '100,000' ),
1495 array( 1000000, '1,000,000' ),
1496 array( -1.0001, '-1.0001' ),
1497 array( 1.0001, '1.0001' ),
1498 array( 10.0001, '10.0001' ),
1499 array( 100.0001, '100.0001' ),
1500 array( 1000.0001, '1,000.0001' ),
1501 array( 10000.0001, '10,000.0001' ),
1502 array( 100000.0001, '100,000.0001' ),
1503 array( 1000000.0001, '1,000,000.0001' ),
1504 array( '200000000000000000000', '200,000,000,000,000,000,000' ),
1505 array( '-200000000000000000000', '-200,000,000,000,000,000,000' ),
1506 );
1507 }
1508
1509 /**
1510 * @covers Language::listToText
1511 */
1512 public function testListToText() {
1513 $lang = $this->getLang();
1514 $and = $lang->getMessageFromDB( 'and' );
1515 $s = $lang->getMessageFromDB( 'word-separator' );
1516 $c = $lang->getMessageFromDB( 'comma-separator' );
1517
1518 $this->assertEquals( '', $lang->listToText( array() ) );
1519 $this->assertEquals( 'a', $lang->listToText( array( 'a' ) ) );
1520 $this->assertEquals( "a{$and}{$s}b", $lang->listToText( array( 'a', 'b' ) ) );
1521 $this->assertEquals( "a{$c}b{$and}{$s}c", $lang->listToText( array( 'a', 'b', 'c' ) ) );
1522 $this->assertEquals( "a{$c}b{$c}c{$and}{$s}d", $lang->listToText( array( 'a', 'b', 'c', 'd' ) ) );
1523 }
1524
1525 /**
1526 * @dataProvider provideIsSupportedLanguage
1527 * @covers Language::isSupportedLanguage
1528 */
1529 public function testIsSupportedLanguage( $code, $expected, $comment ) {
1530 $this->assertEquals( $expected, Language::isSupportedLanguage( $code ), $comment );
1531 }
1532
1533 public static function provideIsSupportedLanguage() {
1534 return array(
1535 array( 'en', true, 'is supported language' ),
1536 array( 'fi', true, 'is supported language' ),
1537 array( 'bunny', false, 'is not supported language' ),
1538 array( 'FI', false, 'is not supported language, input should be in lower case' ),
1539 );
1540 }
1541
1542 /**
1543 * @dataProvider provideGetParentLanguage
1544 * @covers Language::getParentLanguage
1545 */
1546 public function testGetParentLanguage( $code, $expected, $comment ) {
1547 $lang = Language::factory( $code );
1548 if ( is_null( $expected ) ) {
1549 $this->assertNull( $lang->getParentLanguage(), $comment );
1550 } else {
1551 $this->assertEquals( $expected, $lang->getParentLanguage()->getCode(), $comment );
1552 }
1553 }
1554
1555 public static function provideGetParentLanguage() {
1556 return array(
1557 array( 'zh-cn', 'zh', 'zh is the parent language of zh-cn' ),
1558 array( 'zh', 'zh', 'zh is defined as the parent language of zh, because zh converter can convert zh-cn to zh' ),
1559 array( 'zh-invalid', null, 'do not be fooled by arbitrarily composed language codes' ),
1560 array( 'en-gb', null, 'en does not have converter' ),
1561 array( 'en', null, 'en does not have converter. Although FakeConverter handles en -> en conversion but it is useless' ),
1562 );
1563 }
1564
1565 /**
1566 * @dataProvider provideGetNamespaceAliases
1567 * @covers Language::getNamespaceAliases
1568 */
1569 public function testGetNamespaceAliases( $languageCode, $subset ) {
1570 $language = Language::factory( $languageCode );
1571 $aliases = $language->getNamespaceAliases();
1572 foreach ( $subset as $alias => $nsId ) {
1573 $this->assertEquals( $nsId, $aliases[$alias] );
1574 }
1575 }
1576
1577 public static function provideGetNamespaceAliases() {
1578 // TODO: Add tests for NS_PROJECT_TALK and GenderNamespaces
1579 return array(
1580 array(
1581 'zh',
1582 array(
1583 '文件' => NS_FILE,
1584 '檔案' => NS_FILE,
1585 ),
1586 ),
1587 );
1588 }
1589 }