Merge "Pass phpcs-strict on some test files (10/11)"
[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(
416 'i-notexist',
417 'grandfathered but not registered: invalid, even if we only test well-formedness'
418 ),
419 array( 'abcdefghi-012345678', 'numbers too long' ),
420 array( 'ab-abc-abc-abc-abc', 'invalid extensions' ),
421 array( 'ab-abcd-abc', 'invalid extensions' ),
422 array( 'ab-ab-abc', 'invalid extensions' ),
423 array( 'ab-123-abc', 'invalid extensions' ),
424 array( 'a-Hant-ZH', 'short language with valid extensions' ),
425 array( 'a1-Hant-ZH', 'invalid character in language' ),
426 array( 'ab-abcde-abc', 'invalid extensions' ),
427 array( 'ab-1abc-abc', 'invalid characters in extensions' ),
428 array( 'ab-ab-abcd', 'invalid order of extensions' ),
429 array( 'ab-123-abcd', 'invalid order of extensions' ),
430 array( 'ab-abcde-abcd', 'invalid extensions' ),
431 array( 'ab-1abc-abcd', 'invalid characters in extensions' ),
432 array( 'ab-a-b', 'extensions too short' ),
433 array( 'ab-a-x', 'extensions too short, even with singleton' ),
434 array( 'ab--ab', 'two separators' ),
435 array( 'ab-abc-', 'separator in the end' ),
436 array( '-ab-abc', 'separator in the beginning' ),
437 array( 'abcd-efg', 'language too long' ),
438 array( 'aabbccddE', 'tag too long' ),
439 array( 'pa_guru', 'A tag with underscore is invalid in strict mode' ),
440 array( 'de-f', 'subtag too short' ),
441 );
442 }
443
444 /**
445 * Negative test for Language::isWellFormedLanguageTag()
446 * @covers Language::isWellFormedLanguageTag
447 */
448 public function testLenientLanguageTag() {
449 $this->assertTrue(
450 Language::isWellFormedLanguageTag( 'pa_guru', true ),
451 'pa_guru is a well-formed language tag in lenient mode'
452 );
453 }
454
455 /**
456 * Test Language::isValidBuiltInCode()
457 * @dataProvider provideLanguageCodes
458 * @covers Language::isValidBuiltInCode
459 */
460 public function testBuiltInCodeValidation( $code, $message = '' ) {
461 $this->assertTrue(
462 (bool)Language::isValidBuiltInCode( $code ),
463 "validating code $code $message"
464 );
465 }
466
467 /**
468 * @covers Language::isValidBuiltInCode
469 */
470 public function testBuiltInCodeValidationRejectUnderscore() {
471 $this->assertFalse(
472 (bool)Language::isValidBuiltInCode( 'be_tarask' ),
473 "reject underscore in language code"
474 );
475 }
476
477 public static function provideLanguageCodes() {
478 return array(
479 array( 'fr', 'Two letters, minor case' ),
480 array( 'EN', 'Two letters, upper case' ),
481 array( 'tyv', 'Three letters' ),
482 array( 'tokipona', 'long language code' ),
483 array( 'be-tarask', 'With dash' ),
484 array( 'Zh-classical', 'Begin with upper case, dash' ),
485 array( 'Be-x-old', 'With extension (two dashes)' ),
486 );
487 }
488
489 /**
490 * Test Language::isKnownLanguageTag()
491 * @dataProvider provideKnownLanguageTags
492 * @covers Language::isKnownLanguageTag
493 */
494 public function testKnownLanguageTag( $code, $message = '' ) {
495 $this->assertTrue(
496 (bool)Language::isKnownLanguageTag( $code ),
497 "validating code $code - $message"
498 );
499 }
500
501 public static function provideKnownLanguageTags() {
502 return array(
503 array( 'fr', 'simple code' ),
504 array( 'bat-smg', 'an MW legacy tag' ),
505 array( 'sgs', 'an internal standard MW name, for which a legacy tag is used externally' ),
506 );
507 }
508
509 /**
510 * @covers Language::isKnownLanguageTag
511 */
512 public function testKnownCldrLanguageTag() {
513 if ( !class_exists( 'LanguageNames' ) ) {
514 $this->markTestSkipped( 'The LanguageNames class is not available. '
515 . 'The CLDR extension is probably not installed.' );
516 }
517
518 $this->assertTrue(
519 (bool)Language::isKnownLanguageTag( 'pal' ),
520 'validating code "pal" an ancient language, which probably will '
521 . 'not appear in Names.php, but appears in CLDR in English'
522 );
523 }
524
525 /**
526 * Negative tests for Language::isKnownLanguageTag()
527 * @dataProvider provideUnKnownLanguageTags
528 * @covers Language::isKnownLanguageTag
529 */
530 public function testUnknownLanguageTag( $code, $message = '' ) {
531 $this->assertFalse(
532 (bool)Language::isKnownLanguageTag( $code ),
533 "checking that code $code is invalid - $message"
534 );
535 }
536
537 public static function provideUnknownLanguageTags() {
538 return array(
539 array( 'mw', 'non-existent two-letter code' ),
540 array( 'foo"<bar', 'very invalid language code' ),
541 );
542 }
543
544 /**
545 * Test too short timestamp
546 * @expectedException MWException
547 * @covers Language::sprintfDate
548 */
549 public function testSprintfDateTooShortTimestamp() {
550 $this->getLang()->sprintfDate( 'xiY', '1234567890123' );
551 }
552
553 /**
554 * Test too long timestamp
555 * @expectedException MWException
556 * @covers Language::sprintfDate
557 */
558 public function testSprintfDateTooLongTimestamp() {
559 $this->getLang()->sprintfDate( 'xiY', '123456789012345' );
560 }
561
562 /**
563 * Test too short timestamp
564 * @expectedException MWException
565 * @covers Language::sprintfDate
566 */
567 public function testSprintfDateNotAllDigitTimestamp() {
568 $this->getLang()->sprintfDate( 'xiY', '-1234567890123' );
569 }
570
571 /**
572 * @dataProvider provideSprintfDateSamples
573 * @covers Language::sprintfDate
574 */
575 public function testSprintfDate( $format, $ts, $expected, $msg ) {
576 $this->assertEquals(
577 $expected,
578 $this->getLang()->sprintfDate( $format, $ts ),
579 "sprintfDate('$format', '$ts'): $msg"
580 );
581 }
582
583 /**
584 * sprintfDate should always use UTC when no zone is given.
585 * @dataProvider provideSprintfDateSamples
586 * @covers Language::sprintfDate
587 */
588 public function testSprintfDateNoZone( $format, $ts, $expected, $ignore, $msg ) {
589 $oldTZ = date_default_timezone_get();
590 $res = date_default_timezone_set( 'Asia/Seoul' );
591 if ( !$res ) {
592 $this->markTestSkipped( "Error setting Timezone" );
593 }
594
595 $this->assertEquals(
596 $expected,
597 $this->getLang()->sprintfDate( $format, $ts ),
598 "sprintfDate('$format', '$ts'): $msg"
599 );
600
601 date_default_timezone_set( $oldTZ );
602 }
603
604 /**
605 * sprintfDate should use passed timezone
606 * @dataProvider provideSprintfDateSamples
607 * @covers Language::sprintfDate
608 */
609 public function testSprintfDateTZ( $format, $ts, $ignore, $expected, $msg ) {
610 $tz = new DateTimeZone( 'Asia/Seoul' );
611 if ( !$tz ) {
612 $this->markTestSkipped( "Error getting Timezone" );
613 }
614
615 $this->assertEquals(
616 $expected,
617 $this->getLang()->sprintfDate( $format, $ts, $tz ),
618 "sprintfDate('$format', '$ts', 'Asia/Seoul'): $msg"
619 );
620 }
621
622 public static function provideSprintfDateSamples() {
623 return array(
624 array(
625 'xiY',
626 '20111212000000',
627 '1390', // note because we're testing English locale we get Latin-standard digits
628 '1390',
629 'Iranian calendar full year'
630 ),
631 array(
632 'xiy',
633 '20111212000000',
634 '90',
635 '90',
636 'Iranian calendar short year'
637 ),
638 array(
639 'o',
640 '20120101235000',
641 '2011',
642 '2011',
643 'ISO 8601 (week) year'
644 ),
645 array(
646 'W',
647 '20120101235000',
648 '52',
649 '52',
650 'Week number'
651 ),
652 array(
653 'W',
654 '20120102235000',
655 '1',
656 '1',
657 'Week number'
658 ),
659 array(
660 'o-\\WW-N',
661 '20091231235000',
662 '2009-W53-4',
663 '2009-W53-4',
664 'leap week'
665 ),
666 // What follows is mostly copied from
667 // https://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time
668 array(
669 'Y',
670 '20120102090705',
671 '2012',
672 '2012',
673 'Full year'
674 ),
675 array(
676 'y',
677 '20120102090705',
678 '12',
679 '12',
680 '2 digit year'
681 ),
682 array(
683 'L',
684 '20120102090705',
685 '1',
686 '1',
687 'Leap year'
688 ),
689 array(
690 'n',
691 '20120102090705',
692 '1',
693 '1',
694 'Month index, not zero pad'
695 ),
696 array(
697 'N',
698 '20120102090705',
699 '01',
700 '01',
701 'Month index. Zero pad'
702 ),
703 array(
704 'M',
705 '20120102090705',
706 'Jan',
707 'Jan',
708 'Month abbrev'
709 ),
710 array(
711 'F',
712 '20120102090705',
713 'January',
714 'January',
715 'Full month'
716 ),
717 array(
718 'xg',
719 '20120102090705',
720 'January',
721 'January',
722 'Genitive month name (same in EN)'
723 ),
724 array(
725 'j',
726 '20120102090705',
727 '2',
728 '2',
729 'Day of month (not zero pad)'
730 ),
731 array(
732 'd',
733 '20120102090705',
734 '02',
735 '02',
736 'Day of month (zero-pad)'
737 ),
738 array(
739 'z',
740 '20120102090705',
741 '1',
742 '1',
743 'Day of year (zero-indexed)'
744 ),
745 array(
746 'D',
747 '20120102090705',
748 'Mon',
749 'Mon',
750 'Day of week (abbrev)'
751 ),
752 array(
753 'l',
754 '20120102090705',
755 'Monday',
756 'Monday',
757 'Full day of week'
758 ),
759 array(
760 'N',
761 '20120101090705',
762 '7',
763 '7',
764 'Day of week (Mon=1, Sun=7)'
765 ),
766 array(
767 'w',
768 '20120101090705',
769 '0',
770 '0',
771 'Day of week (Sun=0, Sat=6)'
772 ),
773 array(
774 'N',
775 '20120102090705',
776 '1',
777 '1',
778 'Day of week'
779 ),
780 array(
781 'a',
782 '20120102090705',
783 'am',
784 'am',
785 'am vs pm'
786 ),
787 array(
788 'A',
789 '20120102120000',
790 'PM',
791 'PM',
792 'AM vs PM'
793 ),
794 array(
795 'a',
796 '20120102000000',
797 'am',
798 'am',
799 'AM vs PM'
800 ),
801 array(
802 'g',
803 '20120102090705',
804 '9',
805 '9',
806 '12 hour, not Zero'
807 ),
808 array(
809 'h',
810 '20120102090705',
811 '09',
812 '09',
813 '12 hour, zero padded'
814 ),
815 array(
816 'G',
817 '20120102090705',
818 '9',
819 '9',
820 '24 hour, not zero'
821 ),
822 array(
823 'H',
824 '20120102090705',
825 '09',
826 '09',
827 '24 hour, zero'
828 ),
829 array(
830 'H',
831 '20120102110705',
832 '11',
833 '11',
834 '24 hour, zero'
835 ),
836 array(
837 'i',
838 '20120102090705',
839 '07',
840 '07',
841 'Minutes'
842 ),
843 array(
844 's',
845 '20120102090705',
846 '05',
847 '05',
848 'seconds'
849 ),
850 array(
851 'U',
852 '20120102090705',
853 '1325495225',
854 '1325462825',
855 'unix time'
856 ),
857 array(
858 't',
859 '20120102090705',
860 '31',
861 '31',
862 'Days in current month'
863 ),
864 array(
865 'c',
866 '20120102090705',
867 '2012-01-02T09:07:05+00:00',
868 '2012-01-02T09:07:05+09:00',
869 'ISO 8601 timestamp'
870 ),
871 array(
872 'r',
873 '20120102090705',
874 'Mon, 02 Jan 2012 09:07:05 +0000',
875 'Mon, 02 Jan 2012 09:07:05 +0900',
876 'RFC 5322'
877 ),
878 array(
879 'e',
880 '20120102090705',
881 'UTC',
882 'Asia/Seoul',
883 'Timezone identifier'
884 ),
885 array(
886 'I',
887 '19880602090705',
888 '0',
889 '1',
890 'DST indicator'
891 ),
892 array(
893 'O',
894 '20120102090705',
895 '+0000',
896 '+0900',
897 'Timezone offset'
898 ),
899 array(
900 'P',
901 '20120102090705',
902 '+00:00',
903 '+09:00',
904 'Timezone offset with colon'
905 ),
906 array(
907 'T',
908 '20120102090705',
909 'UTC',
910 'KST',
911 'Timezone abbreviation'
912 ),
913 array(
914 'Z',
915 '20120102090705',
916 '0',
917 '32400',
918 'Timezone offset in seconds'
919 ),
920 array(
921 'xmj xmF xmn xmY',
922 '20120102090705',
923 '7 Safar 2 1433',
924 '7 Safar 2 1433',
925 'Islamic'
926 ),
927 array(
928 'xij xiF xin xiY',
929 '20120102090705',
930 '12 Dey 10 1390',
931 '12 Dey 10 1390',
932 'Iranian'
933 ),
934 array(
935 'xjj xjF xjn xjY',
936 '20120102090705',
937 '7 Tevet 4 5772',
938 '7 Tevet 4 5772',
939 'Hebrew'
940 ),
941 array(
942 'xjt',
943 '20120102090705',
944 '29',
945 '29',
946 'Hebrew number of days in month'
947 ),
948 array(
949 'xjx',
950 '20120102090705',
951 'Tevet',
952 'Tevet',
953 'Hebrew genitive month name (No difference in EN)'
954 ),
955 array(
956 'xkY',
957 '20120102090705',
958 '2555',
959 '2555',
960 'Thai year'
961 ),
962 array(
963 'xoY',
964 '20120102090705',
965 '101',
966 '101',
967 'Minguo'
968 ),
969 array(
970 'xtY',
971 '20120102090705',
972 '平成24',
973 '平成24',
974 'nengo'
975 ),
976 array(
977 'xrxkYY',
978 '20120102090705',
979 'MMDLV2012',
980 'MMDLV2012',
981 'Roman numerals'
982 ),
983 array(
984 'xhxjYY',
985 '20120102090705',
986 \'תשע"ב2012',
987 \'תשע"ב2012',
988 'Hebrew numberals'
989 ),
990 array(
991 'xnY',
992 '20120102090705',
993 '2012',
994 '2012',
995 'Raw numerals (doesn\'t mean much in EN)'
996 ),
997 array(
998 '[[Y "(yea"\\r)]] \\"xx\\"',
999 '20120102090705',
1000 '[[2012 (year)]] "x"',
1001 '[[2012 (year)]] "x"',
1002 'Various escaping'
1003 ),
1004
1005 );
1006 }
1007
1008 /**
1009 * @dataProvider provideFormatSizes
1010 * @covers Language::formatSize
1011 */
1012 public function testFormatSize( $size, $expected, $msg ) {
1013 $this->assertEquals(
1014 $expected,
1015 $this->getLang()->formatSize( $size ),
1016 "formatSize('$size'): $msg"
1017 );
1018 }
1019
1020 public static function provideFormatSizes() {
1021 return array(
1022 array(
1023 0,
1024 "0 B",
1025 "Zero bytes"
1026 ),
1027 array(
1028 1024,
1029 "1 KB",
1030 "1 kilobyte"
1031 ),
1032 array(
1033 1024 * 1024,
1034 "1 MB",
1035 "1,024 megabytes"
1036 ),
1037 array(
1038 1024 * 1024 * 1024,
1039 "1 GB",
1040 "1 gigabytes"
1041 ),
1042 array(
1043 pow( 1024, 4 ),
1044 "1 TB",
1045 "1 terabyte"
1046 ),
1047 array(
1048 pow( 1024, 5 ),
1049 "1 PB",
1050 "1 petabyte"
1051 ),
1052 array(
1053 pow( 1024, 6 ),
1054 "1 EB",
1055 "1,024 exabyte"
1056 ),
1057 array(
1058 pow( 1024, 7 ),
1059 "1 ZB",
1060 "1 zetabyte"
1061 ),
1062 array(
1063 pow( 1024, 8 ),
1064 "1 YB",
1065 "1 yottabyte"
1066 ),
1067 // How big!? THIS BIG!
1068 );
1069 }
1070
1071 /**
1072 * @dataProvider provideFormatBitrate
1073 * @covers Language::formatBitrate
1074 */
1075 public function testFormatBitrate( $bps, $expected, $msg ) {
1076 $this->assertEquals(
1077 $expected,
1078 $this->getLang()->formatBitrate( $bps ),
1079 "formatBitrate('$bps'): $msg"
1080 );
1081 }
1082
1083 public static function provideFormatBitrate() {
1084 return array(
1085 array(
1086 0,
1087 "0 bps",
1088 "0 bits per second"
1089 ),
1090 array(
1091 999,
1092 "999 bps",
1093 "999 bits per second"
1094 ),
1095 array(
1096 1000,
1097 "1 kbps",
1098 "1 kilobit per second"
1099 ),
1100 array(
1101 1000 * 1000,
1102 "1 Mbps",
1103 "1 megabit per second"
1104 ),
1105 array(
1106 pow( 10, 9 ),
1107 "1 Gbps",
1108 "1 gigabit per second"
1109 ),
1110 array(
1111 pow( 10, 12 ),
1112 "1 Tbps",
1113 "1 terabit per second"
1114 ),
1115 array(
1116 pow( 10, 15 ),
1117 "1 Pbps",
1118 "1 petabit per second"
1119 ),
1120 array(
1121 pow( 10, 18 ),
1122 "1 Ebps",
1123 "1 exabit per second"
1124 ),
1125 array(
1126 pow( 10, 21 ),
1127 "1 Zbps",
1128 "1 zetabit per second"
1129 ),
1130 array(
1131 pow( 10, 24 ),
1132 "1 Ybps",
1133 "1 yottabit per second"
1134 ),
1135 array(
1136 pow( 10, 27 ),
1137 "1,000 Ybps",
1138 "1,000 yottabits per second"
1139 ),
1140 );
1141 }
1142
1143 /**
1144 * @dataProvider provideFormatDuration
1145 * @covers Language::formatDuration
1146 */
1147 public function testFormatDuration( $duration, $expected, $intervals = array() ) {
1148 $this->assertEquals(
1149 $expected,
1150 $this->getLang()->formatDuration( $duration, $intervals ),
1151 "formatDuration('$duration'): $expected"
1152 );
1153 }
1154
1155 public static function provideFormatDuration() {
1156 return array(
1157 array(
1158 0,
1159 '0 seconds',
1160 ),
1161 array(
1162 1,
1163 '1 second',
1164 ),
1165 array(
1166 2,
1167 '2 seconds',
1168 ),
1169 array(
1170 60,
1171 '1 minute',
1172 ),
1173 array(
1174 2 * 60,
1175 '2 minutes',
1176 ),
1177 array(
1178 3600,
1179 '1 hour',
1180 ),
1181 array(
1182 2 * 3600,
1183 '2 hours',
1184 ),
1185 array(
1186 24 * 3600,
1187 '1 day',
1188 ),
1189 array(
1190 2 * 86400,
1191 '2 days',
1192 ),
1193 array(
1194 // ( 365 + ( 24 * 3 + 25 ) / 400 ) * 86400 = 31556952
1195 ( 365 + ( 24 * 3 + 25 ) / 400.0 ) * 86400,
1196 '1 year',
1197 ),
1198 array(
1199 2 * 31556952,
1200 '2 years',
1201 ),
1202 array(
1203 10 * 31556952,
1204 '1 decade',
1205 ),
1206 array(
1207 20 * 31556952,
1208 '2 decades',
1209 ),
1210 array(
1211 100 * 31556952,
1212 '1 century',
1213 ),
1214 array(
1215 200 * 31556952,
1216 '2 centuries',
1217 ),
1218 array(
1219 1000 * 31556952,
1220 '1 millennium',
1221 ),
1222 array(
1223 2000 * 31556952,
1224 '2 millennia',
1225 ),
1226 array(
1227 9001,
1228 '2 hours, 30 minutes and 1 second'
1229 ),
1230 array(
1231 3601,
1232 '1 hour and 1 second'
1233 ),
1234 array(
1235 31556952 + 2 * 86400 + 9000,
1236 '1 year, 2 days, 2 hours and 30 minutes'
1237 ),
1238 array(
1239 42 * 1000 * 31556952 + 42,
1240 '42 millennia and 42 seconds'
1241 ),
1242 array(
1243 60,
1244 '60 seconds',
1245 array( 'seconds' ),
1246 ),
1247 array(
1248 61,
1249 '61 seconds',
1250 array( 'seconds' ),
1251 ),
1252 array(
1253 1,
1254 '1 second',
1255 array( 'seconds' ),
1256 ),
1257 array(
1258 31556952 + 2 * 86400 + 9000,
1259 '1 year, 2 days and 150 minutes',
1260 array( 'years', 'days', 'minutes' ),
1261 ),
1262 array(
1263 42,
1264 '0 days',
1265 array( 'years', 'days' ),
1266 ),
1267 array(
1268 31556952 + 2 * 86400 + 9000,
1269 '1 year, 2 days and 150 minutes',
1270 array( 'minutes', 'days', 'years' ),
1271 ),
1272 array(
1273 42,
1274 '0 days',
1275 array( 'days', 'years' ),
1276 ),
1277 );
1278 }
1279
1280 /**
1281 * @dataProvider provideCheckTitleEncodingData
1282 * @covers Language::checkTitleEncoding
1283 */
1284 public function testCheckTitleEncoding( $s ) {
1285 $this->assertEquals(
1286 $s,
1287 $this->getLang()->checkTitleEncoding( $s ),
1288 "checkTitleEncoding('$s')"
1289 );
1290 }
1291
1292 public static function provideCheckTitleEncodingData() {
1293 // @codingStandardsIgnoreStart Ignore Generic.Files.LineLength.TooLong
1294 return array(
1295 array( "" ),
1296 array( "United States of America" ), // 7bit ASCII
1297 array( rawurldecode( "S%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e" ) ),
1298 array(
1299 rawurldecode(
1300 "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn"
1301 )
1302 ),
1303 // The following two data sets come from bug 36839. They fail if checkTitleEncoding uses a regexp to test for
1304 // valid UTF-8 encoding and the pcre.recursion_limit is low (like, say, 1024). They succeed if checkTitleEncoding
1305 // uses mb_check_encoding for its test.
1306 array(
1307 rawurldecode(
1308 "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn%7C"
1309 . "Catherine%20Willows%7CDavid%20Hodges%7CDavid%20Phillips%7CGil%20Grissom%7CGreg%20Sanders%7CHodges%7C"
1310 . "Internet%20Movie%20Database%7CJim%20Brass%7CLady%20Heather%7C"
1311 . "Les%20Experts%20(s%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e)%7CLes%20Experts%20:%20Manhattan%7C"
1312 . "Les%20Experts%20:%20Miami%7CListe%20des%20personnages%20des%20Experts%7C"
1313 . "Liste%20des%20%C3%A9pisodes%20des%20Experts%7CMod%C3%A8le%20discussion:Palette%20Les%20Experts%7C"
1314 . "Nick%20Stokes%7CPersonnage%20de%20fiction%7CPersonnage%20fictif%7CPersonnage%20de%20fiction%7C"
1315 . "Personnages%20r%C3%A9currents%20dans%20Les%20Experts%7CRaymond%20Langston%7CRiley%20Adams%7C"
1316 . "Saison%201%20des%20Experts%7CSaison%2010%20des%20Experts%7CSaison%2011%20des%20Experts%7C"
1317 . "Saison%2012%20des%20Experts%7CSaison%202%20des%20Experts%7CSaison%203%20des%20Experts%7C"
1318 . "Saison%204%20des%20Experts%7CSaison%205%20des%20Experts%7CSaison%206%20des%20Experts%7C"
1319 . "Saison%207%20des%20Experts%7CSaison%208%20des%20Experts%7CSaison%209%20des%20Experts%7C"
1320 . "Sara%20Sidle%7CSofia%20Curtis%7CS%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e%7CWallace%20Langham%7C"
1321 . "Warrick%20Brown%7CWendy%20Simms%7C%C3%89tats-Unis"
1322 ),
1323 ),
1324 array(
1325 rawurldecode(
1326 "Mod%C3%A8le%3AArrondissements%20homonymes%7CMod%C3%A8le%3ABandeau%20standard%20pour%20page%20d'homonymie%7C"
1327 . "Mod%C3%A8le%3ABatailles%20homonymes%7CMod%C3%A8le%3ACantons%20homonymes%7C"
1328 . "Mod%C3%A8le%3ACommunes%20fran%C3%A7aises%20homonymes%7CMod%C3%A8le%3AFilms%20homonymes%7C"
1329 . "Mod%C3%A8le%3AGouvernements%20homonymes%7CMod%C3%A8le%3AGuerres%20homonymes%7CMod%C3%A8le%3AHomonymie%7C"
1330 . "Mod%C3%A8le%3AHomonymie%20bateau%7CMod%C3%A8le%3AHomonymie%20d'%C3%A9tablissements%20scolaires%20ou"
1331 . "%20universitaires%7CMod%C3%A8le%3AHomonymie%20d'%C3%AEles%7CMod%C3%A8le%3AHomonymie%20de%20clubs%20sportifs%7C"
1332 . "Mod%C3%A8le%3AHomonymie%20de%20comt%C3%A9s%7CMod%C3%A8le%3AHomonymie%20de%20monument%7C"
1333 . "Mod%C3%A8le%3AHomonymie%20de%20nom%20romain%7CMod%C3%A8le%3AHomonymie%20de%20parti%20politique%7C"
1334 . "Mod%C3%A8le%3AHomonymie%20de%20route%7CMod%C3%A8le%3AHomonymie%20dynastique%7C"
1335 . "Mod%C3%A8le%3AHomonymie%20vid%C3%A9oludique%7CMod%C3%A8le%3AHomonymie%20%C3%A9difice%20religieux%7C"
1336 . "Mod%C3%A8le%3AInternationalisation%7CMod%C3%A8le%3AIsom%C3%A9rie%7CMod%C3%A8le%3AParonymie%7C"
1337 . "Mod%C3%A8le%3APatronyme%7CMod%C3%A8le%3APatronyme%20basque%7CMod%C3%A8le%3APatronyme%20italien%7C"
1338 . "Mod%C3%A8le%3APatronymie%7CMod%C3%A8le%3APersonnes%20homonymes%7CMod%C3%A8le%3ASaints%20homonymes%7C"
1339 . "Mod%C3%A8le%3ATitres%20homonymes%7CMod%C3%A8le%3AToponymie%7CMod%C3%A8le%3AUnit%C3%A9s%20homonymes%7C"
1340 . "Mod%C3%A8le%3AVilles%20homonymes%7CMod%C3%A8le%3A%C3%89difices%20religieux%20homonymes"
1341 )
1342 )
1343 );
1344 // @codingStandardsIgnoreEnd
1345 }
1346
1347 /**
1348 * @dataProvider provideRomanNumeralsData
1349 * @covers Language::romanNumeral
1350 */
1351 public function testRomanNumerals( $num, $numerals ) {
1352 $this->assertEquals(
1353 $numerals,
1354 Language::romanNumeral( $num ),
1355 "romanNumeral('$num')"
1356 );
1357 }
1358
1359 public static function provideRomanNumeralsData() {
1360 return array(
1361 array( 1, 'I' ),
1362 array( 2, 'II' ),
1363 array( 3, 'III' ),
1364 array( 4, 'IV' ),
1365 array( 5, 'V' ),
1366 array( 6, 'VI' ),
1367 array( 7, 'VII' ),
1368 array( 8, 'VIII' ),
1369 array( 9, 'IX' ),
1370 array( 10, 'X' ),
1371 array( 20, 'XX' ),
1372 array( 30, 'XXX' ),
1373 array( 40, 'XL' ),
1374 array( 49, 'XLIX' ),
1375 array( 50, 'L' ),
1376 array( 60, 'LX' ),
1377 array( 70, 'LXX' ),
1378 array( 80, 'LXXX' ),
1379 array( 90, 'XC' ),
1380 array( 99, 'XCIX' ),
1381 array( 100, 'C' ),
1382 array( 200, 'CC' ),
1383 array( 300, 'CCC' ),
1384 array( 400, 'CD' ),
1385 array( 500, 'D' ),
1386 array( 600, 'DC' ),
1387 array( 700, 'DCC' ),
1388 array( 800, 'DCCC' ),
1389 array( 900, 'CM' ),
1390 array( 999, 'CMXCIX' ),
1391 array( 1000, 'M' ),
1392 array( 1989, 'MCMLXXXIX' ),
1393 array( 2000, 'MM' ),
1394 array( 3000, 'MMM' ),
1395 array( 4000, 'MMMM' ),
1396 array( 5000, 'MMMMM' ),
1397 array( 6000, 'MMMMMM' ),
1398 array( 7000, 'MMMMMMM' ),
1399 array( 8000, 'MMMMMMMM' ),
1400 array( 9000, 'MMMMMMMMM' ),
1401 array( 9999, 'MMMMMMMMMCMXCIX' ),
1402 array( 10000, 'MMMMMMMMMM' ),
1403 );
1404 }
1405
1406 /**
1407 * @dataProvider providePluralData
1408 * @covers Language::convertPlural
1409 */
1410 public function testConvertPlural( $expected, $number, $forms ) {
1411 $chosen = $this->getLang()->convertPlural( $number, $forms );
1412 $this->assertEquals( $expected, $chosen );
1413 }
1414
1415 public static function providePluralData() {
1416 // Params are: [expected text, number given, [the plural forms]]
1417 return array(
1418 array( 'plural', 0, array(
1419 'singular', 'plural'
1420 ) ),
1421 array( 'explicit zero', 0, array(
1422 '0=explicit zero', 'singular', 'plural'
1423 ) ),
1424 array( 'explicit one', 1, array(
1425 'singular', 'plural', '1=explicit one',
1426 ) ),
1427 array( 'singular', 1, array(
1428 'singular', 'plural', '0=explicit zero',
1429 ) ),
1430 array( 'plural', 3, array(
1431 '0=explicit zero', '1=explicit one', 'singular', 'plural'
1432 ) ),
1433 array( 'explicit eleven', 11, array(
1434 'singular', 'plural', '11=explicit eleven',
1435 ) ),
1436 array( 'plural', 12, array(
1437 'singular', 'plural', '11=explicit twelve',
1438 ) ),
1439 array( 'plural', 12, array(
1440 'singular', 'plural', '=explicit form',
1441 ) ),
1442 array( 'other', 2, array(
1443 'kissa=kala', '1=2=3', 'other',
1444 ) ),
1445 array( '', 2, array(
1446 '0=explicit zero', '1=explicit one',
1447 ) ),
1448 );
1449 }
1450
1451 /**
1452 * @covers Language::translateBlockExpiry()
1453 * @dataProvider provideTranslateBlockExpiry
1454 */
1455 public function testTranslateBlockExpiry( $expectedData, $str, $desc ) {
1456 $lang = $this->getLang();
1457 if ( is_array( $expectedData ) ) {
1458 list( $func, $arg ) = $expectedData;
1459 $expected = $lang->$func( $arg );
1460 } else {
1461 $expected = $expectedData;
1462 }
1463 $this->assertEquals( $expected, $lang->translateBlockExpiry( $str ), $desc );
1464 }
1465
1466 public static function provideTranslateBlockExpiry() {
1467 return array(
1468 array( '2 hours', '2 hours', 'simple data from ipboptions' ),
1469 array( 'indefinite', 'infinite', 'infinite from ipboptions' ),
1470 array( 'indefinite', 'infinity', 'alternative infinite from ipboptions' ),
1471 array( 'indefinite', 'indefinite', 'another alternative infinite from ipboptions' ),
1472 array( array( 'formatDuration', 1023 * 60 * 60 ), '1023 hours', 'relative' ),
1473 array( array( 'formatDuration', -1023 ), '-1023 seconds', 'negative relative' ),
1474 array( array( 'formatDuration', 0 ), 'now', 'now' ),
1475 array(
1476 array( 'timeanddate', '20120102070000' ),
1477 '2012-1-1 7:00 +1 day',
1478 'mixed, handled as absolute'
1479 ),
1480 array( array( 'timeanddate', '19910203040506' ), '1991-2-3 4:05:06', 'absolute' ),
1481 array( array( 'timeanddate', '19700101000000' ), '1970-1-1 0:00:00', 'absolute at epoch' ),
1482 array( array( 'timeanddate', '19691231235959' ), '1969-12-31 23:59:59', 'time before epoch' ),
1483 array( 'dummy', 'dummy', 'return garbage as is' ),
1484 );
1485 }
1486
1487 /**
1488 * @covers Language::commafy()
1489 * @dataProvider provideCommafyData
1490 */
1491 public function testCommafy( $number, $numbersWithCommas ) {
1492 $this->assertEquals(
1493 $numbersWithCommas,
1494 $this->getLang()->commafy( $number ),
1495 "commafy('$number')"
1496 );
1497 }
1498
1499 public static function provideCommafyData() {
1500 return array(
1501 array( -1, '-1' ),
1502 array( 10, '10' ),
1503 array( 100, '100' ),
1504 array( 1000, '1,000' ),
1505 array( 10000, '10,000' ),
1506 array( 100000, '100,000' ),
1507 array( 1000000, '1,000,000' ),
1508 array( -1.0001, '-1.0001' ),
1509 array( 1.0001, '1.0001' ),
1510 array( 10.0001, '10.0001' ),
1511 array( 100.0001, '100.0001' ),
1512 array( 1000.0001, '1,000.0001' ),
1513 array( 10000.0001, '10,000.0001' ),
1514 array( 100000.0001, '100,000.0001' ),
1515 array( 1000000.0001, '1,000,000.0001' ),
1516 array( '200000000000000000000', '200,000,000,000,000,000,000' ),
1517 array( '-200000000000000000000', '-200,000,000,000,000,000,000' ),
1518 );
1519 }
1520
1521 /**
1522 * @covers Language::listToText
1523 */
1524 public function testListToText() {
1525 $lang = $this->getLang();
1526 $and = $lang->getMessageFromDB( 'and' );
1527 $s = $lang->getMessageFromDB( 'word-separator' );
1528 $c = $lang->getMessageFromDB( 'comma-separator' );
1529
1530 $this->assertEquals( '', $lang->listToText( array() ) );
1531 $this->assertEquals( 'a', $lang->listToText( array( 'a' ) ) );
1532 $this->assertEquals( "a{$and}{$s}b", $lang->listToText( array( 'a', 'b' ) ) );
1533 $this->assertEquals( "a{$c}b{$and}{$s}c", $lang->listToText( array( 'a', 'b', 'c' ) ) );
1534 $this->assertEquals( "a{$c}b{$c}c{$and}{$s}d", $lang->listToText( array( 'a', 'b', 'c', 'd' ) ) );
1535 }
1536
1537 /**
1538 * @dataProvider provideIsSupportedLanguage
1539 * @covers Language::isSupportedLanguage
1540 */
1541 public function testIsSupportedLanguage( $code, $expected, $comment ) {
1542 $this->assertEquals( $expected, Language::isSupportedLanguage( $code ), $comment );
1543 }
1544
1545 public static function provideIsSupportedLanguage() {
1546 return array(
1547 array( 'en', true, 'is supported language' ),
1548 array( 'fi', true, 'is supported language' ),
1549 array( 'bunny', false, 'is not supported language' ),
1550 array( 'FI', false, 'is not supported language, input should be in lower case' ),
1551 );
1552 }
1553
1554 /**
1555 * @dataProvider provideGetParentLanguage
1556 * @covers Language::getParentLanguage
1557 */
1558 public function testGetParentLanguage( $code, $expected, $comment ) {
1559 $lang = Language::factory( $code );
1560 if ( is_null( $expected ) ) {
1561 $this->assertNull( $lang->getParentLanguage(), $comment );
1562 } else {
1563 $this->assertEquals( $expected, $lang->getParentLanguage()->getCode(), $comment );
1564 }
1565 }
1566
1567 public static function provideGetParentLanguage() {
1568 return array(
1569 array( 'zh-cn', 'zh', 'zh is the parent language of zh-cn' ),
1570 array( 'zh', 'zh', 'zh is defined as the parent language of zh, '
1571 . 'because zh converter can convert zh-cn to zh' ),
1572 array( 'zh-invalid', null, 'do not be fooled by arbitrarily composed language codes' ),
1573 array( 'en-gb', null, 'en does not have converter' ),
1574 array( 'en', null, 'en does not have converter. Although FakeConverter '
1575 . 'handles en -> en conversion but it is useless' ),
1576 );
1577 }
1578
1579 /**
1580 * @dataProvider provideGetNamespaceAliases
1581 * @covers Language::getNamespaceAliases
1582 */
1583 public function testGetNamespaceAliases( $languageCode, $subset ) {
1584 $language = Language::factory( $languageCode );
1585 $aliases = $language->getNamespaceAliases();
1586 foreach ( $subset as $alias => $nsId ) {
1587 $this->assertEquals( $nsId, $aliases[$alias] );
1588 }
1589 }
1590
1591 public static function provideGetNamespaceAliases() {
1592 // TODO: Add tests for NS_PROJECT_TALK and GenderNamespaces
1593 return array(
1594 array(
1595 'zh',
1596 array(
1597 '文件' => NS_FILE,
1598 '檔案' => NS_FILE,
1599 ),
1600 ),
1601 );
1602 }
1603 }