Merge "Test improperly quoted attribute values in HTML tags and table cells"
[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 * @dataProvider provideSprintfDateSamples
454 */
455 function testSprintfDate( $format, $ts, $expected, $msg ) {
456 $this->assertEquals(
457 $expected,
458 $this->getLang()->sprintfDate( $format, $ts ),
459 "sprintfDate('$format', '$ts'): $msg"
460 );
461 }
462 /**
463 * bug 33454. sprintfDate should always use UTC.
464 * @dataProvider provideSprintfDateSamples
465 */
466 function testSprintfDateTZ( $format, $ts, $expected, $msg ) {
467 $oldTZ = date_default_timezone_get();
468 $res = date_default_timezone_set( 'Asia/Seoul' );
469 if ( !$res ) {
470 $this->markTestSkipped( "Error setting Timezone" );
471 }
472
473 $this->assertEquals(
474 $expected,
475 $this->getLang()->sprintfDate( $format, $ts ),
476 "sprintfDate('$format', '$ts'): $msg"
477 );
478
479 date_default_timezone_set( $oldTZ );
480 }
481
482 function provideSprintfDateSamples() {
483 return array(
484 array(
485 'xiY',
486 '20111212000000',
487 '1390', // note because we're testing English locale we get Latin-standard digits
488 'Iranian calendar full year'
489 ),
490 array(
491 'xiy',
492 '20111212000000',
493 '90',
494 'Iranian calendar short year'
495 ),
496 array(
497 'o',
498 '20120101235000',
499 '2011',
500 'ISO 8601 (week) year'
501 ),
502 array(
503 'W',
504 '20120101235000',
505 '52',
506 'Week number'
507 ),
508 array(
509 'W',
510 '20120102235000',
511 '1',
512 'Week number'
513 ),
514 array(
515 'o-\\WW-N',
516 '20091231235000',
517 '2009-W53-4',
518 'leap week'
519 ),
520 // What follows is mostly copied from http://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time
521 array(
522 'Y',
523 '20120102090705',
524 '2012',
525 'Full year'
526 ),
527 array(
528 'y',
529 '20120102090705',
530 '12',
531 '2 digit year'
532 ),
533 array(
534 'L',
535 '20120102090705',
536 '1',
537 'Leap year'
538 ),
539 array(
540 'n',
541 '20120102090705',
542 '1',
543 'Month index, not zero pad'
544 ),
545 array(
546 'N',
547 '20120102090705',
548 '01',
549 'Month index. Zero pad'
550 ),
551 array(
552 'M',
553 '20120102090705',
554 'Jan',
555 'Month abbrev'
556 ),
557 array(
558 'F',
559 '20120102090705',
560 'January',
561 'Full month'
562 ),
563 array(
564 'xg',
565 '20120102090705',
566 'January',
567 'Genitive month name (same in EN)'
568 ),
569 array(
570 'j',
571 '20120102090705',
572 '2',
573 'Day of month (not zero pad)'
574 ),
575 array(
576 'd',
577 '20120102090705',
578 '02',
579 'Day of month (zero-pad)'
580 ),
581 array(
582 'z',
583 '20120102090705',
584 '1',
585 'Day of year (zero-indexed)'
586 ),
587 array(
588 'D',
589 '20120102090705',
590 'Mon',
591 'Day of week (abbrev)'
592 ),
593 array(
594 'l',
595 '20120102090705',
596 'Monday',
597 'Full day of week'
598 ),
599 array(
600 'N',
601 '20120101090705',
602 '7',
603 'Day of week (Mon=1, Sun=7)'
604 ),
605 array(
606 'w',
607 '20120101090705',
608 '0',
609 'Day of week (Sun=0, Sat=6)'
610 ),
611 array(
612 'N',
613 '20120102090705',
614 '1',
615 'Day of week'
616 ),
617 array(
618 'a',
619 '20120102090705',
620 'am',
621 'am vs pm'
622 ),
623 array(
624 'A',
625 '20120102120000',
626 'PM',
627 'AM vs PM'
628 ),
629 array(
630 'a',
631 '20120102000000',
632 'am',
633 'AM vs PM'
634 ),
635 array(
636 'g',
637 '20120102090705',
638 '9',
639 '12 hour, not Zero'
640 ),
641 array(
642 'h',
643 '20120102090705',
644 '09',
645 '12 hour, zero padded'
646 ),
647 array(
648 'G',
649 '20120102090705',
650 '9',
651 '24 hour, not zero'
652 ),
653 array(
654 'H',
655 '20120102090705',
656 '09',
657 '24 hour, zero'
658 ),
659 array(
660 'H',
661 '20120102110705',
662 '11',
663 '24 hour, zero'
664 ),
665 array(
666 'i',
667 '20120102090705',
668 '07',
669 'Minutes'
670 ),
671 array(
672 's',
673 '20120102090705',
674 '05',
675 'seconds'
676 ),
677 array(
678 'U',
679 '20120102090705',
680 '1325495225',
681 'unix time'
682 ),
683 array(
684 't',
685 '20120102090705',
686 '31',
687 'Days in current month'
688 ),
689 array(
690 'c',
691 '20120102090705',
692 '2012-01-02T09:07:05+00:00',
693 'ISO 8601 timestamp'
694 ),
695 array(
696 'r',
697 '20120102090705',
698 'Mon, 02 Jan 2012 09:07:05 +0000',
699 'RFC 5322'
700 ),
701 array(
702 'xmj xmF xmn xmY',
703 '20120102090705',
704 '7 Safar 2 1433',
705 'Islamic'
706 ),
707 array(
708 'xij xiF xin xiY',
709 '20120102090705',
710 '12 Dey 10 1390',
711 'Iranian'
712 ),
713 array(
714 'xjj xjF xjn xjY',
715 '20120102090705',
716 '7 Tevet 4 5772',
717 'Hebrew'
718 ),
719 array(
720 'xjt',
721 '20120102090705',
722 '29',
723 'Hebrew number of days in month'
724 ),
725 array(
726 'xjx',
727 '20120102090705',
728 'Tevet',
729 'Hebrew genitive month name (No difference in EN)'
730 ),
731 array(
732 'xkY',
733 '20120102090705',
734 '2555',
735 'Thai year'
736 ),
737 array(
738 'xoY',
739 '20120102090705',
740 '101',
741 'Minguo'
742 ),
743 array(
744 'xtY',
745 '20120102090705',
746 '平成24',
747 'nengo'
748 ),
749 array(
750 'xrxkYY',
751 '20120102090705',
752 'MMDLV2012',
753 'Roman numerals'
754 ),
755 array(
756 'xhxjYY',
757 '20120102090705',
758 \'תשע"ב2012',
759 'Hebrew numberals'
760 ),
761 array(
762 'xnY',
763 '20120102090705',
764 '2012',
765 'Raw numerals (doesn\'t mean much in EN)'
766 ),
767 array(
768 '[[Y "(yea"\\r)]] \\"xx\\"',
769 '20120102090705',
770 '[[2012 (year)]] "x"',
771 'Various escaping'
772 ),
773
774 );
775 }
776
777 /**
778 * @dataProvider provideFormatSizes
779 */
780 function testFormatSize( $size, $expected, $msg ) {
781 $this->assertEquals(
782 $expected,
783 $this->getLang()->formatSize( $size ),
784 "formatSize('$size'): $msg"
785 );
786 }
787
788 function provideFormatSizes() {
789 return array(
790 array(
791 0,
792 "0 B",
793 "Zero bytes"
794 ),
795 array(
796 1024,
797 "1 KB",
798 "1 kilobyte"
799 ),
800 array(
801 1024 * 1024,
802 "1 MB",
803 "1,024 megabytes"
804 ),
805 array(
806 1024 * 1024 * 1024,
807 "1 GB",
808 "1 gigabytes"
809 ),
810 array(
811 pow( 1024, 4 ),
812 "1 TB",
813 "1 terabyte"
814 ),
815 array(
816 pow( 1024, 5 ),
817 "1 PB",
818 "1 petabyte"
819 ),
820 array(
821 pow( 1024, 6 ),
822 "1 EB",
823 "1,024 exabyte"
824 ),
825 array(
826 pow( 1024, 7 ),
827 "1 ZB",
828 "1 zetabyte"
829 ),
830 array(
831 pow( 1024, 8 ),
832 "1 YB",
833 "1 yottabyte"
834 ),
835 // How big!? THIS BIG!
836 );
837 }
838
839 /**
840 * @dataProvider provideFormatBitrate
841 */
842 function testFormatBitrate( $bps, $expected, $msg ) {
843 $this->assertEquals(
844 $expected,
845 $this->getLang()->formatBitrate( $bps ),
846 "formatBitrate('$bps'): $msg"
847 );
848 }
849
850 function provideFormatBitrate() {
851 return array(
852 array(
853 0,
854 "0bps",
855 "0 bits per second"
856 ),
857 array(
858 999,
859 "999bps",
860 "999 bits per second"
861 ),
862 array(
863 1000,
864 "1kbps",
865 "1 kilobit per second"
866 ),
867 array(
868 1000 * 1000,
869 "1Mbps",
870 "1 megabit per second"
871 ),
872 array(
873 pow( 10, 9 ),
874 "1Gbps",
875 "1 gigabit per second"
876 ),
877 array(
878 pow( 10, 12 ),
879 "1Tbps",
880 "1 terabit per second"
881 ),
882 array(
883 pow( 10, 15 ),
884 "1Pbps",
885 "1 petabit per second"
886 ),
887 array(
888 pow( 10, 18 ),
889 "1Ebps",
890 "1 exabit per second"
891 ),
892 array(
893 pow( 10, 21 ),
894 "1Zbps",
895 "1 zetabit per second"
896 ),
897 array(
898 pow( 10, 24 ),
899 "1Ybps",
900 "1 yottabit per second"
901 ),
902 array(
903 pow( 10, 27 ),
904 "1,000Ybps",
905 "1,000 yottabits per second"
906 ),
907 );
908 }
909
910
911
912 /**
913 * @dataProvider provideFormatDuration
914 */
915 function testFormatDuration( $duration, $expected, $intervals = array() ) {
916 $this->assertEquals(
917 $expected,
918 $this->getLang()->formatDuration( $duration, $intervals ),
919 "formatDuration('$duration'): $expected"
920 );
921 }
922
923 function provideFormatDuration() {
924 return array(
925 array(
926 0,
927 '0 seconds',
928 ),
929 array(
930 1,
931 '1 second',
932 ),
933 array(
934 2,
935 '2 seconds',
936 ),
937 array(
938 60,
939 '1 minute',
940 ),
941 array(
942 2 * 60,
943 '2 minutes',
944 ),
945 array(
946 3600,
947 '1 hour',
948 ),
949 array(
950 2 * 3600,
951 '2 hours',
952 ),
953 array(
954 24 * 3600,
955 '1 day',
956 ),
957 array(
958 2 * 86400,
959 '2 days',
960 ),
961 array(
962 // ( 365 + ( 24 * 3 + 25 ) / 400 ) * 86400 = 31556952
963 ( 365 + ( 24 * 3 + 25 ) / 400.0 ) * 86400,
964 '1 year',
965 ),
966 array(
967 2 * 31556952,
968 '2 years',
969 ),
970 array(
971 10 * 31556952,
972 '1 decade',
973 ),
974 array(
975 20 * 31556952,
976 '2 decades',
977 ),
978 array(
979 100 * 31556952,
980 '1 century',
981 ),
982 array(
983 200 * 31556952,
984 '2 centuries',
985 ),
986 array(
987 1000 * 31556952,
988 '1 millennium',
989 ),
990 array(
991 2000 * 31556952,
992 '2 millennia',
993 ),
994 array(
995 9001,
996 '2 hours, 30 minutes and 1 second'
997 ),
998 array(
999 3601,
1000 '1 hour and 1 second'
1001 ),
1002 array(
1003 31556952 + 2 * 86400 + 9000,
1004 '1 year, 2 days, 2 hours and 30 minutes'
1005 ),
1006 array(
1007 42 * 1000 * 31556952 + 42,
1008 '42 millennia and 42 seconds'
1009 ),
1010 array(
1011 60,
1012 '60 seconds',
1013 array( 'seconds' ),
1014 ),
1015 array(
1016 61,
1017 '61 seconds',
1018 array( 'seconds' ),
1019 ),
1020 array(
1021 1,
1022 '1 second',
1023 array( 'seconds' ),
1024 ),
1025 array(
1026 31556952 + 2 * 86400 + 9000,
1027 '1 year, 2 days and 150 minutes',
1028 array( 'years', 'days', 'minutes' ),
1029 ),
1030 array(
1031 42,
1032 '0 days',
1033 array( 'years', 'days' ),
1034 ),
1035 array(
1036 31556952 + 2 * 86400 + 9000,
1037 '1 year, 2 days and 150 minutes',
1038 array( 'minutes', 'days', 'years' ),
1039 ),
1040 array(
1041 42,
1042 '0 days',
1043 array( 'days', 'years' ),
1044 ),
1045 );
1046 }
1047
1048 /**
1049 * @dataProvider provideCheckTitleEncodingData
1050 */
1051 function testCheckTitleEncoding( $s ) {
1052 $this->assertEquals(
1053 $s,
1054 $this->getLang()->checkTitleEncoding($s),
1055 "checkTitleEncoding('$s')"
1056 );
1057 }
1058
1059 function provideCheckTitleEncodingData() {
1060 return array (
1061 array( "" ),
1062 array( "United States of America" ), // 7bit ASCII
1063 array( rawurldecode( "S%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e" ) ),
1064 array(
1065 rawurldecode(
1066 "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn"
1067 )
1068 ),
1069 // The following two data sets come from bug 36839. They fail if checkTitleEncoding uses a regexp to test for
1070 // valid UTF-8 encoding and the pcre.recursion_limit is low (like, say, 1024). They succeed if checkTitleEncoding
1071 // uses mb_check_encoding for its test.
1072 array(
1073 rawurldecode(
1074 "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn%7C"
1075 . "Catherine%20Willows%7CDavid%20Hodges%7CDavid%20Phillips%7CGil%20Grissom%7CGreg%20Sanders%7CHodges%7C"
1076 . "Internet%20Movie%20Database%7CJim%20Brass%7CLady%20Heather%7C"
1077 . "Les%20Experts%20(s%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e)%7CLes%20Experts%20:%20Manhattan%7C"
1078 . "Les%20Experts%20:%20Miami%7CListe%20des%20personnages%20des%20Experts%7C"
1079 . "Liste%20des%20%C3%A9pisodes%20des%20Experts%7CMod%C3%A8le%20discussion:Palette%20Les%20Experts%7C"
1080 . "Nick%20Stokes%7CPersonnage%20de%20fiction%7CPersonnage%20fictif%7CPersonnage%20de%20fiction%7C"
1081 . "Personnages%20r%C3%A9currents%20dans%20Les%20Experts%7CRaymond%20Langston%7CRiley%20Adams%7C"
1082 . "Saison%201%20des%20Experts%7CSaison%2010%20des%20Experts%7CSaison%2011%20des%20Experts%7C"
1083 . "Saison%2012%20des%20Experts%7CSaison%202%20des%20Experts%7CSaison%203%20des%20Experts%7C"
1084 . "Saison%204%20des%20Experts%7CSaison%205%20des%20Experts%7CSaison%206%20des%20Experts%7C"
1085 . "Saison%207%20des%20Experts%7CSaison%208%20des%20Experts%7CSaison%209%20des%20Experts%7C"
1086 . "Sara%20Sidle%7CSofia%20Curtis%7CS%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e%7CWallace%20Langham%7C"
1087 . "Warrick%20Brown%7CWendy%20Simms%7C%C3%89tats-Unis"
1088 ),
1089 ),
1090 array(
1091 rawurldecode(
1092 "Mod%C3%A8le%3AArrondissements%20homonymes%7CMod%C3%A8le%3ABandeau%20standard%20pour%20page%20d'homonymie%7C"
1093 . "Mod%C3%A8le%3ABatailles%20homonymes%7CMod%C3%A8le%3ACantons%20homonymes%7C"
1094 . "Mod%C3%A8le%3ACommunes%20fran%C3%A7aises%20homonymes%7CMod%C3%A8le%3AFilms%20homonymes%7C"
1095 . "Mod%C3%A8le%3AGouvernements%20homonymes%7CMod%C3%A8le%3AGuerres%20homonymes%7CMod%C3%A8le%3AHomonymie%7C"
1096 . "Mod%C3%A8le%3AHomonymie%20bateau%7CMod%C3%A8le%3AHomonymie%20d'%C3%A9tablissements%20scolaires%20ou"
1097 . "%20universitaires%7CMod%C3%A8le%3AHomonymie%20d'%C3%AEles%7CMod%C3%A8le%3AHomonymie%20de%20clubs%20sportifs%7C"
1098 . "Mod%C3%A8le%3AHomonymie%20de%20comt%C3%A9s%7CMod%C3%A8le%3AHomonymie%20de%20monument%7C"
1099 . "Mod%C3%A8le%3AHomonymie%20de%20nom%20romain%7CMod%C3%A8le%3AHomonymie%20de%20parti%20politique%7C"
1100 . "Mod%C3%A8le%3AHomonymie%20de%20route%7CMod%C3%A8le%3AHomonymie%20dynastique%7C"
1101 . "Mod%C3%A8le%3AHomonymie%20vid%C3%A9oludique%7CMod%C3%A8le%3AHomonymie%20%C3%A9difice%20religieux%7C"
1102 . "Mod%C3%A8le%3AInternationalisation%7CMod%C3%A8le%3AIsom%C3%A9rie%7CMod%C3%A8le%3AParonymie%7C"
1103 . "Mod%C3%A8le%3APatronyme%7CMod%C3%A8le%3APatronyme%20basque%7CMod%C3%A8le%3APatronyme%20italien%7C"
1104 . "Mod%C3%A8le%3APatronymie%7CMod%C3%A8le%3APersonnes%20homonymes%7CMod%C3%A8le%3ASaints%20homonymes%7C"
1105 . "Mod%C3%A8le%3ATitres%20homonymes%7CMod%C3%A8le%3AToponymie%7CMod%C3%A8le%3AUnit%C3%A9s%20homonymes%7C"
1106 . "Mod%C3%A8le%3AVilles%20homonymes%7CMod%C3%A8le%3A%C3%89difices%20religieux%20homonymes"
1107 )
1108 )
1109 );
1110 }
1111
1112 /**
1113 * @dataProvider provideRomanNumeralsData
1114 */
1115 function testRomanNumerals( $num, $numerals ) {
1116 $this->assertEquals(
1117 $numerals,
1118 Language::romanNumeral( $num ),
1119 "romanNumeral('$num')"
1120 );
1121 }
1122
1123 function provideRomanNumeralsData() {
1124 return array(
1125 array( 1, 'I' ),
1126 array( 2, 'II' ),
1127 array( 3, 'III' ),
1128 array( 4, 'IV' ),
1129 array( 5, 'V' ),
1130 array( 6, 'VI' ),
1131 array( 7, 'VII' ),
1132 array( 8, 'VIII' ),
1133 array( 9, 'IX' ),
1134 array( 10, 'X' ),
1135 array( 20, 'XX' ),
1136 array( 30, 'XXX' ),
1137 array( 40, 'XL' ),
1138 array( 49, 'XLIX' ),
1139 array( 50, 'L' ),
1140 array( 60, 'LX' ),
1141 array( 70, 'LXX' ),
1142 array( 80, 'LXXX' ),
1143 array( 90, 'XC' ),
1144 array( 99, 'XCIX' ),
1145 array( 100, 'C' ),
1146 array( 200, 'CC' ),
1147 array( 300, 'CCC' ),
1148 array( 400, 'CD' ),
1149 array( 500, 'D' ),
1150 array( 600, 'DC' ),
1151 array( 700, 'DCC' ),
1152 array( 800, 'DCCC' ),
1153 array( 900, 'CM' ),
1154 array( 999, 'CMXCIX' ),
1155 array( 1000, 'M' ),
1156 array( 1989, 'MCMLXXXIX' ),
1157 array( 2000, 'MM' ),
1158 array( 3000, 'MMM' ),
1159 array( 4000, 'MMMM' ),
1160 array( 5000, 'MMMMM' ),
1161 array( 6000, 'MMMMMM' ),
1162 array( 7000, 'MMMMMMM' ),
1163 array( 8000, 'MMMMMMMM' ),
1164 array( 9000, 'MMMMMMMMM' ),
1165 array( 9999, 'MMMMMMMMMCMXCIX'),
1166 array( 10000, 'MMMMMMMMMM' ),
1167 );
1168 }
1169
1170 /**
1171 * @dataProvider providePluralData
1172 */
1173 function testConvertPlural( $expected, $number, $forms ) {
1174 $chosen = $this->getLang()->convertPlural( $number, $forms );
1175 $this->assertEquals( $expected, $chosen );
1176 }
1177
1178 function providePluralData() {
1179 return array(
1180 array( 'explicit zero', 0, array(
1181 '0=explicit zero', 'singular', 'plural'
1182 ) ),
1183 array( 'explicit one', 1, array(
1184 'singular', 'plural', '1=explicit one',
1185 ) ),
1186 array( 'singular', 1, array(
1187 'singular', 'plural', '0=explicit zero',
1188 ) ),
1189 array( 'plural', 3, array(
1190 '0=explicit zero', '1=explicit one', 'singular', 'plural'
1191 ) ),
1192 );
1193 }
1194
1195 /**
1196 * @covers Language::translateBlockExpiry()
1197 * @dataProvider provideTranslateBlockExpiry
1198 */
1199 function testTranslateBlockExpiry( $expectedData, $str, $desc ) {
1200 $lang = $this->getLang();
1201 if ( is_array( $expectedData ) ) {
1202 list( $func, $arg ) = $expectedData;
1203 $expected = $lang->$func( $arg );
1204 } else {
1205 $expected = $expectedData;
1206 }
1207 $this->assertEquals( $expected, $lang->translateBlockExpiry( $str ), $desc );
1208 }
1209
1210 function provideTranslateBlockExpiry() {
1211 return array(
1212 array( '2 hours', '2 hours', 'simple data from ipboptions' ),
1213 array( 'indefinite', 'infinite', 'infinite from ipboptions' ),
1214 array( 'indefinite', 'infinity', 'alternative infinite from ipboptions' ),
1215 array( 'indefinite', 'indefinite', 'another alternative infinite from ipboptions' ),
1216 array( array( 'formatDuration', 1023 * 60 * 60 ), '1023 hours', 'relative' ),
1217 array( array( 'formatDuration', -1023 ), '-1023 seconds', 'negative relative' ),
1218 array( array( 'formatDuration', 0 ), 'now', 'now' ),
1219 array( array( 'timeanddate', '20120102070000' ), '2012-1-1 7:00 +1 day', 'mixed, handled as absolute' ),
1220 array( array( 'timeanddate', '19910203040506' ), '1991-2-3 4:05:06', 'absolute' ),
1221 array( array( 'timeanddate', '19700101000000' ), '1970-1-1 0:00:00', 'absolute at epoch' ),
1222 array( array( 'timeanddate', '19691231235959' ), '1969-12-31 23:59:59', 'time before epoch' ),
1223 array( 'dummy', 'dummy', 'return garbage as is' ),
1224 );
1225 }
1226
1227 /**
1228 * @covers Language::commafy()
1229 * @dataProvider provideCommafyData
1230 */
1231 function testCommafy( $number, $numbersWithCommas ) {
1232 $this->assertEquals(
1233 $numbersWithCommas,
1234 $this->getLang()->commafy( $number ),
1235 "commafy('$number')"
1236 );
1237 }
1238
1239 function provideCommafyData() {
1240 return array(
1241 array( 1, '1' ),
1242 array( 10, '10' ),
1243 array( 100, '100' ),
1244 array( 1000, '1,000' ),
1245 array( 10000, '10,000' ),
1246 array( 100000, '100,000' ),
1247 array( 1000000, '1,000,000' ),
1248 array( 1.0001, '1.0001' ),
1249 array( 10.0001, '10.0001' ),
1250 array( 100.0001, '100.0001' ),
1251 array( 1000.0001, '1,000.0001' ),
1252 array( 10000.0001, '10,000.0001' ),
1253 array( 100000.0001, '100,000.0001' ),
1254 array( 1000000.0001, '1,000,000.0001' ),
1255 );
1256 }
1257
1258 function testListToText() {
1259 $lang = $this->getLang();
1260 $and = $lang->getMessageFromDB( 'and' );
1261 $s = $lang->getMessageFromDB( 'word-separator' );
1262 $c = $lang->getMessageFromDB( 'comma-separator' );
1263
1264 $this->assertEquals( '', $lang->listToText( array( ) ) );
1265 $this->assertEquals( 'a', $lang->listToText( array( 'a' ) ) );
1266 $this->assertEquals( "a{$and}{$s}b", $lang->listToText( array( 'a', 'b' ) ) );
1267 $this->assertEquals( "a{$c}b{$and}{$s}c", $lang->listToText( array( 'a', 'b', 'c' ) ) );
1268 $this->assertEquals( "a{$c}b{$c}c{$and}{$s}d", $lang->listToText( array( 'a', 'b', 'c', 'd' ) ) );
1269 }
1270
1271 /**
1272 * @dataProvider provideIsSupportedLanguage
1273 */
1274 function testIsSupportedLanguage( $code, $expected, $comment ) {
1275 $this->assertEquals( $expected, Language::isSupportedLanguage( $code ), $comment );
1276 }
1277
1278 static function provideIsSupportedLanguage() {
1279 return array(
1280 array( 'en', true, 'is supported language' ),
1281 array( 'fi', true, 'is supported language' ),
1282 array( 'bunny', false, 'is not supported language' ),
1283 array( 'FI', false, 'is not supported language, input should be in lower case' ),
1284 );
1285 }
1286 }
1287