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