MediaWiki
REL1_21
|
00001 <?php 00002 00003 class LanguageTest extends LanguageClassesTestCase { 00004 00005 function testLanguageConvertDoubleWidthToSingleWidth() { 00006 $this->assertEquals( 00007 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz", 00008 $this->getLang()->normalizeForSearch( 00009 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" 00010 ), 00011 'convertDoubleWidth() with the full alphabet and digits' 00012 ); 00013 } 00014 00018 function testFormatTimePeriod( $seconds, $format, $expected, $desc ) { 00019 $this->assertEquals( $expected, $this->getLang()->formatTimePeriod( $seconds, $format ), $desc ); 00020 } 00021 00022 function provideFormattableTimes() { 00023 return array( 00024 array( 00025 9.45, 00026 array(), 00027 '9.5 s', 00028 'formatTimePeriod() rounding (<10s)' 00029 ), 00030 array( 00031 9.45, 00032 array( 'noabbrevs' => true ), 00033 '9.5 seconds', 00034 'formatTimePeriod() rounding (<10s)' 00035 ), 00036 array( 00037 9.95, 00038 array(), 00039 '10 s', 00040 'formatTimePeriod() rounding (<10s)' 00041 ), 00042 array( 00043 9.95, 00044 array( 'noabbrevs' => true ), 00045 '10 seconds', 00046 'formatTimePeriod() rounding (<10s)' 00047 ), 00048 array( 00049 59.55, 00050 array(), 00051 '1 min 0 s', 00052 'formatTimePeriod() rounding (<60s)' 00053 ), 00054 array( 00055 59.55, 00056 array( 'noabbrevs' => true ), 00057 '1 minute 0 seconds', 00058 'formatTimePeriod() rounding (<60s)' 00059 ), 00060 array( 00061 119.55, 00062 array(), 00063 '2 min 0 s', 00064 'formatTimePeriod() rounding (<1h)' 00065 ), 00066 array( 00067 119.55, 00068 array( 'noabbrevs' => true ), 00069 '2 minutes 0 seconds', 00070 'formatTimePeriod() rounding (<1h)' 00071 ), 00072 array( 00073 3599.55, 00074 array(), 00075 '1 h 0 min 0 s', 00076 'formatTimePeriod() rounding (<1h)' 00077 ), 00078 array( 00079 3599.55, 00080 array( 'noabbrevs' => true ), 00081 '1 hour 0 minutes 0 seconds', 00082 'formatTimePeriod() rounding (<1h)' 00083 ), 00084 array( 00085 7199.55, 00086 array(), 00087 '2 h 0 min 0 s', 00088 'formatTimePeriod() rounding (>=1h)' 00089 ), 00090 array( 00091 7199.55, 00092 array( 'noabbrevs' => true ), 00093 '2 hours 0 minutes 0 seconds', 00094 'formatTimePeriod() rounding (>=1h)' 00095 ), 00096 array( 00097 7199.55, 00098 'avoidseconds', 00099 '2 h 0 min', 00100 'formatTimePeriod() rounding (>=1h), avoidseconds' 00101 ), 00102 array( 00103 7199.55, 00104 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ), 00105 '2 hours 0 minutes', 00106 'formatTimePeriod() rounding (>=1h), avoidseconds' 00107 ), 00108 array( 00109 7199.55, 00110 'avoidminutes', 00111 '2 h 0 min', 00112 'formatTimePeriod() rounding (>=1h), avoidminutes' 00113 ), 00114 array( 00115 7199.55, 00116 array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ), 00117 '2 hours 0 minutes', 00118 'formatTimePeriod() rounding (>=1h), avoidminutes' 00119 ), 00120 array( 00121 172799.55, 00122 'avoidseconds', 00123 '48 h 0 min', 00124 'formatTimePeriod() rounding (=48h), avoidseconds' 00125 ), 00126 array( 00127 172799.55, 00128 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ), 00129 '48 hours 0 minutes', 00130 'formatTimePeriod() rounding (=48h), avoidseconds' 00131 ), 00132 array( 00133 259199.55, 00134 'avoidminutes', 00135 '3 d 0 h', 00136 'formatTimePeriod() rounding (>48h), avoidminutes' 00137 ), 00138 array( 00139 259199.55, 00140 array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ), 00141 '3 days 0 hours', 00142 'formatTimePeriod() rounding (>48h), avoidminutes' 00143 ), 00144 array( 00145 176399.55, 00146 'avoidseconds', 00147 '2 d 1 h 0 min', 00148 'formatTimePeriod() rounding (>48h), avoidseconds' 00149 ), 00150 array( 00151 176399.55, 00152 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ), 00153 '2 days 1 hour 0 minutes', 00154 'formatTimePeriod() rounding (>48h), avoidseconds' 00155 ), 00156 array( 00157 176399.55, 00158 'avoidminutes', 00159 '2 d 1 h', 00160 'formatTimePeriod() rounding (>48h), avoidminutes' 00161 ), 00162 array( 00163 176399.55, 00164 array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ), 00165 '2 days 1 hour', 00166 'formatTimePeriod() rounding (>48h), avoidminutes' 00167 ), 00168 array( 00169 259199.55, 00170 'avoidseconds', 00171 '3 d 0 h 0 min', 00172 'formatTimePeriod() rounding (>48h), avoidseconds' 00173 ), 00174 array( 00175 259199.55, 00176 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ), 00177 '3 days 0 hours 0 minutes', 00178 'formatTimePeriod() rounding (>48h), avoidseconds' 00179 ), 00180 array( 00181 172801.55, 00182 'avoidseconds', 00183 '2 d 0 h 0 min', 00184 'formatTimePeriod() rounding, (>48h), avoidseconds' 00185 ), 00186 array( 00187 172801.55, 00188 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ), 00189 '2 days 0 hours 0 minutes', 00190 'formatTimePeriod() rounding, (>48h), avoidseconds' 00191 ), 00192 array( 00193 176460.55, 00194 array(), 00195 '2 d 1 h 1 min 1 s', 00196 'formatTimePeriod() rounding, recursion, (>48h)' 00197 ), 00198 array( 00199 176460.55, 00200 array( 'noabbrevs' => true ), 00201 '2 days 1 hour 1 minute 1 second', 00202 'formatTimePeriod() rounding, recursion, (>48h)' 00203 ), 00204 ); 00205 00206 } 00207 00208 function testTruncate() { 00209 $this->assertEquals( 00210 "XXX", 00211 $this->getLang()->truncate( "1234567890", 0, 'XXX' ), 00212 'truncate prefix, len 0, small ellipsis' 00213 ); 00214 00215 $this->assertEquals( 00216 "12345XXX", 00217 $this->getLang()->truncate( "1234567890", 8, 'XXX' ), 00218 'truncate prefix, small ellipsis' 00219 ); 00220 00221 $this->assertEquals( 00222 "123456789", 00223 $this->getLang()->truncate( "123456789", 5, 'XXXXXXXXXXXXXXX' ), 00224 'truncate prefix, large ellipsis' 00225 ); 00226 00227 $this->assertEquals( 00228 "XXX67890", 00229 $this->getLang()->truncate( "1234567890", -8, 'XXX' ), 00230 'truncate suffix, small ellipsis' 00231 ); 00232 00233 $this->assertEquals( 00234 "123456789", 00235 $this->getLang()->truncate( "123456789", -5, 'XXXXXXXXXXXXXXX' ), 00236 'truncate suffix, large ellipsis' 00237 ); 00238 } 00239 00243 function testTruncateHtml( $len, $ellipsis, $input, $expected ) { 00244 // Actual HTML... 00245 $this->assertEquals( 00246 $expected, 00247 $this->getLang()->truncateHTML( $input, $len, $ellipsis ) 00248 ); 00249 } 00250 00254 function provideHTMLTruncateData() { 00255 return array( 00256 array( 0, 'XXX', "1234567890", "XXX" ), 00257 array( 8, 'XXX', "1234567890", "12345XXX" ), 00258 array( 5, 'XXXXXXXXXXXXXXX', '1234567890', "1234567890" ), 00259 array( 2, '***', 00260 '<p><span style="font-weight:bold;"></span></p>', 00261 '<p><span style="font-weight:bold;"></span></p>', 00262 ), 00263 array( 2, '***', 00264 '<p><span style="font-weight:bold;">123456789</span></p>', 00265 '<p><span style="font-weight:bold;">***</span></p>', 00266 ), 00267 array( 2, '***', 00268 '<p><span style="font-weight:bold;"> 23456789</span></p>', 00269 '<p><span style="font-weight:bold;">***</span></p>', 00270 ), 00271 array( 3, '***', 00272 '<p><span style="font-weight:bold;">123456789</span></p>', 00273 '<p><span style="font-weight:bold;">***</span></p>', 00274 ), 00275 array( 4, '***', 00276 '<p><span style="font-weight:bold;">123456789</span></p>', 00277 '<p><span style="font-weight:bold;">1***</span></p>', 00278 ), 00279 array( 5, '***', 00280 '<tt><span style="font-weight:bold;">123456789</span></tt>', 00281 '<tt><span style="font-weight:bold;">12***</span></tt>', 00282 ), 00283 array( 6, '***', 00284 '<p><a href="www.mediawiki.org">123456789</a></p>', 00285 '<p><a href="www.mediawiki.org">123***</a></p>', 00286 ), 00287 array( 6, '***', 00288 '<p><a href="www.mediawiki.org">12 456789</a></p>', 00289 '<p><a href="www.mediawiki.org">12 ***</a></p>', 00290 ), 00291 array( 7, '***', 00292 '<small><span style="font-weight:bold;">123<p id="#moo">456</p>789</span></small>', 00293 '<small><span style="font-weight:bold;">123<p id="#moo">4***</p></span></small>', 00294 ), 00295 array( 8, '***', 00296 '<div><span style="font-weight:bold;">123<span>4</span>56789</span></div>', 00297 '<div><span style="font-weight:bold;">123<span>4</span>5***</span></div>', 00298 ), 00299 array( 9, '***', 00300 '<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>', 00301 '<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>', 00302 ), 00303 array( 10, '***', 00304 '<p><font style="font-weight:bold;">123456789</font></p>', 00305 '<p><font style="font-weight:bold;">123456789</font></p>', 00306 ), 00307 ); 00308 } 00309 00314 function testWellFormedLanguageTag( $code, $message = '' ) { 00315 $this->assertTrue( 00316 Language::isWellFormedLanguageTag( $code ), 00317 "validating code $code $message" 00318 ); 00319 } 00320 00327 function provideWellFormedLanguageTags() { 00328 return array( 00329 array( 'fr', 'two-letter code' ), 00330 array( 'fr-latn', 'two-letter code with lower case script code' ), 00331 array( 'fr-Latn-FR', 'two-letter code with title case script code and uppercase country code' ), 00332 array( 'fr-Latn-419', 'two-letter code with title case script code and region number' ), 00333 array( 'fr-FR', 'two-letter code with uppercase' ), 00334 array( 'ax-TZ', 'Not in the registry, but well-formed' ), 00335 array( 'fr-shadok', 'two-letter code with variant' ), 00336 array( 'fr-y-myext-myext2', 'non-x singleton' ), 00337 array( 'fra-Latn', 'ISO 639 can be 3-letters' ), 00338 array( 'fra', 'three-letter language code' ), 00339 array( 'fra-FX', 'three-letter language code with country code' ), 00340 array( 'i-klingon', 'grandfathered with singleton' ), 00341 array( 'I-kLINgon', 'tags are case-insensitive...' ), 00342 array( 'no-bok', 'grandfathered without singleton' ), 00343 array( 'i-enochian', 'Grandfathered' ), 00344 array( 'x-fr-CH', 'private use' ), 00345 array( 'es-419', 'two-letter code with region number' ), 00346 array( 'en-Latn-GB-boont-r-extended-sequence-x-private', 'weird, but well-formed' ), 00347 array( 'ab-x-abc-x-abc', 'anything goes after x' ), 00348 array( 'ab-x-abc-a-a', 'anything goes after x, including several non-x singletons' ), 00349 array( 'i-default', 'grandfathered' ), 00350 array( 'abcd-Latn', 'Language of 4 chars reserved for future use' ), 00351 array( 'AaBbCcDd-x-y-any-x', 'Language of 5-8 chars, registered' ), 00352 array( 'de-CH-1901', 'with country and year' ), 00353 array( 'en-US-x-twain', 'with country and singleton' ), 00354 array( 'zh-cmn', 'three-letter variant' ), 00355 array( 'zh-cmn-Hant', 'three-letter variant and script' ), 00356 array( 'zh-cmn-Hant-HK', 'three-letter variant, script and country' ), 00357 array( 'xr-p-lze', 'Extension' ), 00358 ); 00359 } 00360 00365 function testMalformedLanguageTag( $code, $message = '' ) { 00366 $this->assertFalse( 00367 Language::isWellFormedLanguageTag( $code ), 00368 "validating that code $code is a malformed language tag - $message" 00369 ); 00370 } 00371 00378 function provideMalformedLanguageTags() { 00379 return array( 00380 array( 'f', 'language too short' ), 00381 array( 'f-Latn', 'language too short with script' ), 00382 array( 'xr-lxs-qut', 'variants too short' ), # extlangS 00383 array( 'fr-Latn-F', 'region too short' ), 00384 array( 'a-value', 'language too short with region' ), 00385 array( 'tlh-a-b-foo', 'valid three-letter with wrong variant' ), 00386 array( 'i-notexist', 'grandfathered but not registered: invalid, even if we only test well-formedness' ), 00387 array( 'abcdefghi-012345678', 'numbers too long' ), 00388 array( 'ab-abc-abc-abc-abc', 'invalid extensions' ), 00389 array( 'ab-abcd-abc', 'invalid extensions' ), 00390 array( 'ab-ab-abc', 'invalid extensions' ), 00391 array( 'ab-123-abc', 'invalid extensions' ), 00392 array( 'a-Hant-ZH', 'short language with valid extensions' ), 00393 array( 'a1-Hant-ZH', 'invalid character in language' ), 00394 array( 'ab-abcde-abc', 'invalid extensions' ), 00395 array( 'ab-1abc-abc', 'invalid characters in extensions' ), 00396 array( 'ab-ab-abcd', 'invalid order of extensions' ), 00397 array( 'ab-123-abcd', 'invalid order of extensions' ), 00398 array( 'ab-abcde-abcd', 'invalid extensions' ), 00399 array( 'ab-1abc-abcd', 'invalid characters in extensions' ), 00400 array( 'ab-a-b', 'extensions too short' ), 00401 array( 'ab-a-x', 'extensions too short, even with singleton' ), 00402 array( 'ab--ab', 'two separators' ), 00403 array( 'ab-abc-', 'separator in the end' ), 00404 array( '-ab-abc', 'separator in the beginning' ), 00405 array( 'abcd-efg', 'language too long' ), 00406 array( 'aabbccddE', 'tag too long' ), 00407 array( 'pa_guru', 'A tag with underscore is invalid in strict mode' ), 00408 array( 'de-f', 'subtag too short' ), 00409 ); 00410 } 00411 00415 function testLenientLanguageTag() { 00416 $this->assertTrue( 00417 Language::isWellFormedLanguageTag( 'pa_guru', true ), 00418 'pa_guru is a well-formed language tag in lenient mode' 00419 ); 00420 } 00421 00426 function testBuiltInCodeValidation( $code, $message = '' ) { 00427 $this->assertTrue( 00428 (bool)Language::isValidBuiltInCode( $code ), 00429 "validating code $code $message" 00430 ); 00431 } 00432 00433 function testBuiltInCodeValidationRejectUnderscore() { 00434 $this->assertFalse( 00435 (bool)Language::isValidBuiltInCode( 'be_tarask' ), 00436 "reject underscore in language code" 00437 ); 00438 } 00439 00440 function provideLanguageCodes() { 00441 return array( 00442 array( 'fr', 'Two letters, minor case' ), 00443 array( 'EN', 'Two letters, upper case' ), 00444 array( 'tyv', 'Three letters' ), 00445 array( 'tokipona', 'long language code' ), 00446 array( 'be-tarask', 'With dash' ), 00447 array( 'Zh-classical', 'Begin with upper case, dash' ), 00448 array( 'Be-x-old', 'With extension (two dashes)' ), 00449 ); 00450 } 00451 00456 function testKnownLanguageTag( $code, $message = '' ) { 00457 $this->assertTrue( 00458 (bool)Language::isKnownLanguageTag( $code ), 00459 "validating code $code - $message" 00460 ); 00461 } 00462 00463 function provideKnownLanguageTags() { 00464 return array( 00465 array( 'fr', 'simple code' ), 00466 array( 'bat-smg', 'an MW legacy tag' ), 00467 array( 'sgs', 'an internal standard MW name, for which a legacy tag is used externally' ), 00468 ); 00469 } 00470 00474 function testKnownCldrLanguageTag() { 00475 if ( !class_exists( 'LanguageNames' ) ) { 00476 $this->markTestSkipped( 'The LanguageNames class is not available. The cldr extension is probably not installed.' ); 00477 } 00478 00479 $this->assertTrue( 00480 (bool)Language::isKnownLanguageTag( 'pal' ), 00481 'validating code "pal" an ancient language, which probably will not appear in Names.php, but appears in CLDR in English' 00482 ); 00483 } 00484 00489 function testUnknownLanguageTag( $code, $message = '' ) { 00490 $this->assertFalse( 00491 (bool)Language::isKnownLanguageTag( $code ), 00492 "checking that code $code is invalid - $message" 00493 ); 00494 } 00495 00496 function provideUnknownLanguageTags() { 00497 return array( 00498 array( 'mw', 'non-existent two-letter code' ), 00499 ); 00500 } 00501 00505 function testSprintfDate( $format, $ts, $expected, $msg ) { 00506 $this->assertEquals( 00507 $expected, 00508 $this->getLang()->sprintfDate( $format, $ts ), 00509 "sprintfDate('$format', '$ts'): $msg" 00510 ); 00511 } 00512 00517 function testSprintfDateTZ( $format, $ts, $expected, $msg ) { 00518 $oldTZ = date_default_timezone_get(); 00519 $res = date_default_timezone_set( 'Asia/Seoul' ); 00520 if ( !$res ) { 00521 $this->markTestSkipped( "Error setting Timezone" ); 00522 } 00523 00524 $this->assertEquals( 00525 $expected, 00526 $this->getLang()->sprintfDate( $format, $ts ), 00527 "sprintfDate('$format', '$ts'): $msg" 00528 ); 00529 00530 date_default_timezone_set( $oldTZ ); 00531 } 00532 00533 function provideSprintfDateSamples() { 00534 return array( 00535 array( 00536 'xiY', 00537 '20111212000000', 00538 '1390', // note because we're testing English locale we get Latin-standard digits 00539 'Iranian calendar full year' 00540 ), 00541 array( 00542 'xiy', 00543 '20111212000000', 00544 '90', 00545 'Iranian calendar short year' 00546 ), 00547 array( 00548 'o', 00549 '20120101235000', 00550 '2011', 00551 'ISO 8601 (week) year' 00552 ), 00553 array( 00554 'W', 00555 '20120101235000', 00556 '52', 00557 'Week number' 00558 ), 00559 array( 00560 'W', 00561 '20120102235000', 00562 '1', 00563 'Week number' 00564 ), 00565 array( 00566 'o-\\WW-N', 00567 '20091231235000', 00568 '2009-W53-4', 00569 'leap week' 00570 ), 00571 // What follows is mostly copied from http://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time 00572 array( 00573 'Y', 00574 '20120102090705', 00575 '2012', 00576 'Full year' 00577 ), 00578 array( 00579 'y', 00580 '20120102090705', 00581 '12', 00582 '2 digit year' 00583 ), 00584 array( 00585 'L', 00586 '20120102090705', 00587 '1', 00588 'Leap year' 00589 ), 00590 array( 00591 'n', 00592 '20120102090705', 00593 '1', 00594 'Month index, not zero pad' 00595 ), 00596 array( 00597 'N', 00598 '20120102090705', 00599 '01', 00600 'Month index. Zero pad' 00601 ), 00602 array( 00603 'M', 00604 '20120102090705', 00605 'Jan', 00606 'Month abbrev' 00607 ), 00608 array( 00609 'F', 00610 '20120102090705', 00611 'January', 00612 'Full month' 00613 ), 00614 array( 00615 'xg', 00616 '20120102090705', 00617 'January', 00618 'Genitive month name (same in EN)' 00619 ), 00620 array( 00621 'j', 00622 '20120102090705', 00623 '2', 00624 'Day of month (not zero pad)' 00625 ), 00626 array( 00627 'd', 00628 '20120102090705', 00629 '02', 00630 'Day of month (zero-pad)' 00631 ), 00632 array( 00633 'z', 00634 '20120102090705', 00635 '1', 00636 'Day of year (zero-indexed)' 00637 ), 00638 array( 00639 'D', 00640 '20120102090705', 00641 'Mon', 00642 'Day of week (abbrev)' 00643 ), 00644 array( 00645 'l', 00646 '20120102090705', 00647 'Monday', 00648 'Full day of week' 00649 ), 00650 array( 00651 'N', 00652 '20120101090705', 00653 '7', 00654 'Day of week (Mon=1, Sun=7)' 00655 ), 00656 array( 00657 'w', 00658 '20120101090705', 00659 '0', 00660 'Day of week (Sun=0, Sat=6)' 00661 ), 00662 array( 00663 'N', 00664 '20120102090705', 00665 '1', 00666 'Day of week' 00667 ), 00668 array( 00669 'a', 00670 '20120102090705', 00671 'am', 00672 'am vs pm' 00673 ), 00674 array( 00675 'A', 00676 '20120102120000', 00677 'PM', 00678 'AM vs PM' 00679 ), 00680 array( 00681 'a', 00682 '20120102000000', 00683 'am', 00684 'AM vs PM' 00685 ), 00686 array( 00687 'g', 00688 '20120102090705', 00689 '9', 00690 '12 hour, not Zero' 00691 ), 00692 array( 00693 'h', 00694 '20120102090705', 00695 '09', 00696 '12 hour, zero padded' 00697 ), 00698 array( 00699 'G', 00700 '20120102090705', 00701 '9', 00702 '24 hour, not zero' 00703 ), 00704 array( 00705 'H', 00706 '20120102090705', 00707 '09', 00708 '24 hour, zero' 00709 ), 00710 array( 00711 'H', 00712 '20120102110705', 00713 '11', 00714 '24 hour, zero' 00715 ), 00716 array( 00717 'i', 00718 '20120102090705', 00719 '07', 00720 'Minutes' 00721 ), 00722 array( 00723 's', 00724 '20120102090705', 00725 '05', 00726 'seconds' 00727 ), 00728 array( 00729 'U', 00730 '20120102090705', 00731 '1325495225', 00732 'unix time' 00733 ), 00734 array( 00735 't', 00736 '20120102090705', 00737 '31', 00738 'Days in current month' 00739 ), 00740 array( 00741 'c', 00742 '20120102090705', 00743 '2012-01-02T09:07:05+00:00', 00744 'ISO 8601 timestamp' 00745 ), 00746 array( 00747 'r', 00748 '20120102090705', 00749 'Mon, 02 Jan 2012 09:07:05 +0000', 00750 'RFC 5322' 00751 ), 00752 array( 00753 'xmj xmF xmn xmY', 00754 '20120102090705', 00755 '7 Safar 2 1433', 00756 'Islamic' 00757 ), 00758 array( 00759 'xij xiF xin xiY', 00760 '20120102090705', 00761 '12 Dey 10 1390', 00762 'Iranian' 00763 ), 00764 array( 00765 'xjj xjF xjn xjY', 00766 '20120102090705', 00767 '7 Tevet 4 5772', 00768 'Hebrew' 00769 ), 00770 array( 00771 'xjt', 00772 '20120102090705', 00773 '29', 00774 'Hebrew number of days in month' 00775 ), 00776 array( 00777 'xjx', 00778 '20120102090705', 00779 'Tevet', 00780 'Hebrew genitive month name (No difference in EN)' 00781 ), 00782 array( 00783 'xkY', 00784 '20120102090705', 00785 '2555', 00786 'Thai year' 00787 ), 00788 array( 00789 'xoY', 00790 '20120102090705', 00791 '101', 00792 'Minguo' 00793 ), 00794 array( 00795 'xtY', 00796 '20120102090705', 00797 '平成24', 00798 'nengo' 00799 ), 00800 array( 00801 'xrxkYY', 00802 '20120102090705', 00803 'MMDLV2012', 00804 'Roman numerals' 00805 ), 00806 array( 00807 'xhxjYY', 00808 '20120102090705', 00809 'ה\'תשע"ב2012', 00810 'Hebrew numberals' 00811 ), 00812 array( 00813 'xnY', 00814 '20120102090705', 00815 '2012', 00816 'Raw numerals (doesn\'t mean much in EN)' 00817 ), 00818 array( 00819 '[[Y "(yea"\\r)]] \\"xx\\"', 00820 '20120102090705', 00821 '[[2012 (year)]] "x"', 00822 'Various escaping' 00823 ), 00824 00825 ); 00826 } 00827 00831 function testFormatSize( $size, $expected, $msg ) { 00832 $this->assertEquals( 00833 $expected, 00834 $this->getLang()->formatSize( $size ), 00835 "formatSize('$size'): $msg" 00836 ); 00837 } 00838 00839 function provideFormatSizes() { 00840 return array( 00841 array( 00842 0, 00843 "0 B", 00844 "Zero bytes" 00845 ), 00846 array( 00847 1024, 00848 "1 KB", 00849 "1 kilobyte" 00850 ), 00851 array( 00852 1024 * 1024, 00853 "1 MB", 00854 "1,024 megabytes" 00855 ), 00856 array( 00857 1024 * 1024 * 1024, 00858 "1 GB", 00859 "1 gigabytes" 00860 ), 00861 array( 00862 pow( 1024, 4 ), 00863 "1 TB", 00864 "1 terabyte" 00865 ), 00866 array( 00867 pow( 1024, 5 ), 00868 "1 PB", 00869 "1 petabyte" 00870 ), 00871 array( 00872 pow( 1024, 6 ), 00873 "1 EB", 00874 "1,024 exabyte" 00875 ), 00876 array( 00877 pow( 1024, 7 ), 00878 "1 ZB", 00879 "1 zetabyte" 00880 ), 00881 array( 00882 pow( 1024, 8 ), 00883 "1 YB", 00884 "1 yottabyte" 00885 ), 00886 // How big!? THIS BIG! 00887 ); 00888 } 00889 00893 function testFormatBitrate( $bps, $expected, $msg ) { 00894 $this->assertEquals( 00895 $expected, 00896 $this->getLang()->formatBitrate( $bps ), 00897 "formatBitrate('$bps'): $msg" 00898 ); 00899 } 00900 00901 function provideFormatBitrate() { 00902 return array( 00903 array( 00904 0, 00905 "0 bps", 00906 "0 bits per second" 00907 ), 00908 array( 00909 999, 00910 "999 bps", 00911 "999 bits per second" 00912 ), 00913 array( 00914 1000, 00915 "1 kbps", 00916 "1 kilobit per second" 00917 ), 00918 array( 00919 1000 * 1000, 00920 "1 Mbps", 00921 "1 megabit per second" 00922 ), 00923 array( 00924 pow( 10, 9 ), 00925 "1 Gbps", 00926 "1 gigabit per second" 00927 ), 00928 array( 00929 pow( 10, 12 ), 00930 "1 Tbps", 00931 "1 terabit per second" 00932 ), 00933 array( 00934 pow( 10, 15 ), 00935 "1 Pbps", 00936 "1 petabit per second" 00937 ), 00938 array( 00939 pow( 10, 18 ), 00940 "1 Ebps", 00941 "1 exabit per second" 00942 ), 00943 array( 00944 pow( 10, 21 ), 00945 "1 Zbps", 00946 "1 zetabit per second" 00947 ), 00948 array( 00949 pow( 10, 24 ), 00950 "1 Ybps", 00951 "1 yottabit per second" 00952 ), 00953 array( 00954 pow( 10, 27 ), 00955 "1,000 Ybps", 00956 "1,000 yottabits per second" 00957 ), 00958 ); 00959 } 00960 00961 00965 function testFormatDuration( $duration, $expected, $intervals = array() ) { 00966 $this->assertEquals( 00967 $expected, 00968 $this->getLang()->formatDuration( $duration, $intervals ), 00969 "formatDuration('$duration'): $expected" 00970 ); 00971 } 00972 00973 function provideFormatDuration() { 00974 return array( 00975 array( 00976 0, 00977 '0 seconds', 00978 ), 00979 array( 00980 1, 00981 '1 second', 00982 ), 00983 array( 00984 2, 00985 '2 seconds', 00986 ), 00987 array( 00988 60, 00989 '1 minute', 00990 ), 00991 array( 00992 2 * 60, 00993 '2 minutes', 00994 ), 00995 array( 00996 3600, 00997 '1 hour', 00998 ), 00999 array( 01000 2 * 3600, 01001 '2 hours', 01002 ), 01003 array( 01004 24 * 3600, 01005 '1 day', 01006 ), 01007 array( 01008 2 * 86400, 01009 '2 days', 01010 ), 01011 array( 01012 // ( 365 + ( 24 * 3 + 25 ) / 400 ) * 86400 = 31556952 01013 ( 365 + ( 24 * 3 + 25 ) / 400.0 ) * 86400, 01014 '1 year', 01015 ), 01016 array( 01017 2 * 31556952, 01018 '2 years', 01019 ), 01020 array( 01021 10 * 31556952, 01022 '1 decade', 01023 ), 01024 array( 01025 20 * 31556952, 01026 '2 decades', 01027 ), 01028 array( 01029 100 * 31556952, 01030 '1 century', 01031 ), 01032 array( 01033 200 * 31556952, 01034 '2 centuries', 01035 ), 01036 array( 01037 1000 * 31556952, 01038 '1 millennium', 01039 ), 01040 array( 01041 2000 * 31556952, 01042 '2 millennia', 01043 ), 01044 array( 01045 9001, 01046 '2 hours, 30 minutes and 1 second' 01047 ), 01048 array( 01049 3601, 01050 '1 hour and 1 second' 01051 ), 01052 array( 01053 31556952 + 2 * 86400 + 9000, 01054 '1 year, 2 days, 2 hours and 30 minutes' 01055 ), 01056 array( 01057 42 * 1000 * 31556952 + 42, 01058 '42 millennia and 42 seconds' 01059 ), 01060 array( 01061 60, 01062 '60 seconds', 01063 array( 'seconds' ), 01064 ), 01065 array( 01066 61, 01067 '61 seconds', 01068 array( 'seconds' ), 01069 ), 01070 array( 01071 1, 01072 '1 second', 01073 array( 'seconds' ), 01074 ), 01075 array( 01076 31556952 + 2 * 86400 + 9000, 01077 '1 year, 2 days and 150 minutes', 01078 array( 'years', 'days', 'minutes' ), 01079 ), 01080 array( 01081 42, 01082 '0 days', 01083 array( 'years', 'days' ), 01084 ), 01085 array( 01086 31556952 + 2 * 86400 + 9000, 01087 '1 year, 2 days and 150 minutes', 01088 array( 'minutes', 'days', 'years' ), 01089 ), 01090 array( 01091 42, 01092 '0 days', 01093 array( 'days', 'years' ), 01094 ), 01095 ); 01096 } 01097 01101 function testCheckTitleEncoding( $s ) { 01102 $this->assertEquals( 01103 $s, 01104 $this->getLang()->checkTitleEncoding( $s ), 01105 "checkTitleEncoding('$s')" 01106 ); 01107 } 01108 01109 function provideCheckTitleEncodingData() { 01110 return array( 01111 array( "" ), 01112 array( "United States of America" ), // 7bit ASCII 01113 array( rawurldecode( "S%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e" ) ), 01114 array( 01115 rawurldecode( 01116 "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn" 01117 ) 01118 ), 01119 // The following two data sets come from bug 36839. They fail if checkTitleEncoding uses a regexp to test for 01120 // valid UTF-8 encoding and the pcre.recursion_limit is low (like, say, 1024). They succeed if checkTitleEncoding 01121 // uses mb_check_encoding for its test. 01122 array( 01123 rawurldecode( 01124 "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn%7C" 01125 . "Catherine%20Willows%7CDavid%20Hodges%7CDavid%20Phillips%7CGil%20Grissom%7CGreg%20Sanders%7CHodges%7C" 01126 . "Internet%20Movie%20Database%7CJim%20Brass%7CLady%20Heather%7C" 01127 . "Les%20Experts%20(s%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e)%7CLes%20Experts%20:%20Manhattan%7C" 01128 . "Les%20Experts%20:%20Miami%7CListe%20des%20personnages%20des%20Experts%7C" 01129 . "Liste%20des%20%C3%A9pisodes%20des%20Experts%7CMod%C3%A8le%20discussion:Palette%20Les%20Experts%7C" 01130 . "Nick%20Stokes%7CPersonnage%20de%20fiction%7CPersonnage%20fictif%7CPersonnage%20de%20fiction%7C" 01131 . "Personnages%20r%C3%A9currents%20dans%20Les%20Experts%7CRaymond%20Langston%7CRiley%20Adams%7C" 01132 . "Saison%201%20des%20Experts%7CSaison%2010%20des%20Experts%7CSaison%2011%20des%20Experts%7C" 01133 . "Saison%2012%20des%20Experts%7CSaison%202%20des%20Experts%7CSaison%203%20des%20Experts%7C" 01134 . "Saison%204%20des%20Experts%7CSaison%205%20des%20Experts%7CSaison%206%20des%20Experts%7C" 01135 . "Saison%207%20des%20Experts%7CSaison%208%20des%20Experts%7CSaison%209%20des%20Experts%7C" 01136 . "Sara%20Sidle%7CSofia%20Curtis%7CS%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e%7CWallace%20Langham%7C" 01137 . "Warrick%20Brown%7CWendy%20Simms%7C%C3%89tats-Unis" 01138 ), 01139 ), 01140 array( 01141 rawurldecode( 01142 "Mod%C3%A8le%3AArrondissements%20homonymes%7CMod%C3%A8le%3ABandeau%20standard%20pour%20page%20d'homonymie%7C" 01143 . "Mod%C3%A8le%3ABatailles%20homonymes%7CMod%C3%A8le%3ACantons%20homonymes%7C" 01144 . "Mod%C3%A8le%3ACommunes%20fran%C3%A7aises%20homonymes%7CMod%C3%A8le%3AFilms%20homonymes%7C" 01145 . "Mod%C3%A8le%3AGouvernements%20homonymes%7CMod%C3%A8le%3AGuerres%20homonymes%7CMod%C3%A8le%3AHomonymie%7C" 01146 . "Mod%C3%A8le%3AHomonymie%20bateau%7CMod%C3%A8le%3AHomonymie%20d'%C3%A9tablissements%20scolaires%20ou" 01147 . "%20universitaires%7CMod%C3%A8le%3AHomonymie%20d'%C3%AEles%7CMod%C3%A8le%3AHomonymie%20de%20clubs%20sportifs%7C" 01148 . "Mod%C3%A8le%3AHomonymie%20de%20comt%C3%A9s%7CMod%C3%A8le%3AHomonymie%20de%20monument%7C" 01149 . "Mod%C3%A8le%3AHomonymie%20de%20nom%20romain%7CMod%C3%A8le%3AHomonymie%20de%20parti%20politique%7C" 01150 . "Mod%C3%A8le%3AHomonymie%20de%20route%7CMod%C3%A8le%3AHomonymie%20dynastique%7C" 01151 . "Mod%C3%A8le%3AHomonymie%20vid%C3%A9oludique%7CMod%C3%A8le%3AHomonymie%20%C3%A9difice%20religieux%7C" 01152 . "Mod%C3%A8le%3AInternationalisation%7CMod%C3%A8le%3AIsom%C3%A9rie%7CMod%C3%A8le%3AParonymie%7C" 01153 . "Mod%C3%A8le%3APatronyme%7CMod%C3%A8le%3APatronyme%20basque%7CMod%C3%A8le%3APatronyme%20italien%7C" 01154 . "Mod%C3%A8le%3APatronymie%7CMod%C3%A8le%3APersonnes%20homonymes%7CMod%C3%A8le%3ASaints%20homonymes%7C" 01155 . "Mod%C3%A8le%3ATitres%20homonymes%7CMod%C3%A8le%3AToponymie%7CMod%C3%A8le%3AUnit%C3%A9s%20homonymes%7C" 01156 . "Mod%C3%A8le%3AVilles%20homonymes%7CMod%C3%A8le%3A%C3%89difices%20religieux%20homonymes" 01157 ) 01158 ) 01159 ); 01160 } 01161 01165 function testRomanNumerals( $num, $numerals ) { 01166 $this->assertEquals( 01167 $numerals, 01168 Language::romanNumeral( $num ), 01169 "romanNumeral('$num')" 01170 ); 01171 } 01172 01173 function provideRomanNumeralsData() { 01174 return array( 01175 array( 1, 'I' ), 01176 array( 2, 'II' ), 01177 array( 3, 'III' ), 01178 array( 4, 'IV' ), 01179 array( 5, 'V' ), 01180 array( 6, 'VI' ), 01181 array( 7, 'VII' ), 01182 array( 8, 'VIII' ), 01183 array( 9, 'IX' ), 01184 array( 10, 'X' ), 01185 array( 20, 'XX' ), 01186 array( 30, 'XXX' ), 01187 array( 40, 'XL' ), 01188 array( 49, 'XLIX' ), 01189 array( 50, 'L' ), 01190 array( 60, 'LX' ), 01191 array( 70, 'LXX' ), 01192 array( 80, 'LXXX' ), 01193 array( 90, 'XC' ), 01194 array( 99, 'XCIX' ), 01195 array( 100, 'C' ), 01196 array( 200, 'CC' ), 01197 array( 300, 'CCC' ), 01198 array( 400, 'CD' ), 01199 array( 500, 'D' ), 01200 array( 600, 'DC' ), 01201 array( 700, 'DCC' ), 01202 array( 800, 'DCCC' ), 01203 array( 900, 'CM' ), 01204 array( 999, 'CMXCIX' ), 01205 array( 1000, 'M' ), 01206 array( 1989, 'MCMLXXXIX' ), 01207 array( 2000, 'MM' ), 01208 array( 3000, 'MMM' ), 01209 array( 4000, 'MMMM' ), 01210 array( 5000, 'MMMMM' ), 01211 array( 6000, 'MMMMMM' ), 01212 array( 7000, 'MMMMMMM' ), 01213 array( 8000, 'MMMMMMMM' ), 01214 array( 9000, 'MMMMMMMMM' ), 01215 array( 9999, 'MMMMMMMMMCMXCIX' ), 01216 array( 10000, 'MMMMMMMMMM' ), 01217 ); 01218 } 01219 01223 function testConvertPlural( $expected, $number, $forms ) { 01224 $chosen = $this->getLang()->convertPlural( $number, $forms ); 01225 $this->assertEquals( $expected, $chosen ); 01226 } 01227 01228 function providePluralData() { 01229 // Params are: [expected text, number given, [the plural forms]] 01230 return array( 01231 array( 'plural', 0, array( 01232 'singular', 'plural' 01233 ) ), 01234 array( 'explicit zero', 0, array( 01235 '0=explicit zero', 'singular', 'plural' 01236 ) ), 01237 array( 'explicit one', 1, array( 01238 'singular', 'plural', '1=explicit one', 01239 ) ), 01240 array( 'singular', 1, array( 01241 'singular', 'plural', '0=explicit zero', 01242 ) ), 01243 array( 'plural', 3, array( 01244 '0=explicit zero', '1=explicit one', 'singular', 'plural' 01245 ) ), 01246 array( 'explicit eleven', 11, array( 01247 'singular', 'plural', '11=explicit eleven', 01248 ) ), 01249 array( 'plural', 12, array( 01250 'singular', 'plural', '11=explicit twelve', 01251 ) ), 01252 array( 'plural', 12, array( 01253 'singular', 'plural', '=explicit form', 01254 ) ), 01255 array( 'other', 2, array( 01256 'kissa=kala', '1=2=3', 'other', 01257 ) ), 01258 ); 01259 } 01260 01265 function testTranslateBlockExpiry( $expectedData, $str, $desc ) { 01266 $lang = $this->getLang(); 01267 if ( is_array( $expectedData ) ) { 01268 list( $func, $arg ) = $expectedData; 01269 $expected = $lang->$func( $arg ); 01270 } else { 01271 $expected = $expectedData; 01272 } 01273 $this->assertEquals( $expected, $lang->translateBlockExpiry( $str ), $desc ); 01274 } 01275 01276 function provideTranslateBlockExpiry() { 01277 return array( 01278 array( '2 hours', '2 hours', 'simple data from ipboptions' ), 01279 array( 'indefinite', 'infinite', 'infinite from ipboptions' ), 01280 array( 'indefinite', 'infinity', 'alternative infinite from ipboptions' ), 01281 array( 'indefinite', 'indefinite', 'another alternative infinite from ipboptions' ), 01282 array( array( 'formatDuration', 1023 * 60 * 60 ), '1023 hours', 'relative' ), 01283 array( array( 'formatDuration', -1023 ), '-1023 seconds', 'negative relative' ), 01284 array( array( 'formatDuration', 0 ), 'now', 'now' ), 01285 array( array( 'timeanddate', '20120102070000' ), '2012-1-1 7:00 +1 day', 'mixed, handled as absolute' ), 01286 array( array( 'timeanddate', '19910203040506' ), '1991-2-3 4:05:06', 'absolute' ), 01287 array( array( 'timeanddate', '19700101000000' ), '1970-1-1 0:00:00', 'absolute at epoch' ), 01288 array( array( 'timeanddate', '19691231235959' ), '1969-12-31 23:59:59', 'time before epoch' ), 01289 array( 'dummy', 'dummy', 'return garbage as is' ), 01290 ); 01291 } 01292 01297 function testCommafy( $number, $numbersWithCommas ) { 01298 $this->assertEquals( 01299 $numbersWithCommas, 01300 $this->getLang()->commafy( $number ), 01301 "commafy('$number')" 01302 ); 01303 } 01304 01305 function provideCommafyData() { 01306 return array( 01307 array( 1, '1' ), 01308 array( 10, '10' ), 01309 array( 100, '100' ), 01310 array( 1000, '1,000' ), 01311 array( 10000, '10,000' ), 01312 array( 100000, '100,000' ), 01313 array( 1000000, '1,000,000' ), 01314 array( 1.0001, '1.0001' ), 01315 array( 10.0001, '10.0001' ), 01316 array( 100.0001, '100.0001' ), 01317 array( 1000.0001, '1,000.0001' ), 01318 array( 10000.0001, '10,000.0001' ), 01319 array( 100000.0001, '100,000.0001' ), 01320 array( 1000000.0001, '1,000,000.0001' ), 01321 ); 01322 } 01323 01324 function testListToText() { 01325 $lang = $this->getLang(); 01326 $and = $lang->getMessageFromDB( 'and' ); 01327 $s = $lang->getMessageFromDB( 'word-separator' ); 01328 $c = $lang->getMessageFromDB( 'comma-separator' ); 01329 01330 $this->assertEquals( '', $lang->listToText( array() ) ); 01331 $this->assertEquals( 'a', $lang->listToText( array( 'a' ) ) ); 01332 $this->assertEquals( "a{$and}{$s}b", $lang->listToText( array( 'a', 'b' ) ) ); 01333 $this->assertEquals( "a{$c}b{$and}{$s}c", $lang->listToText( array( 'a', 'b', 'c' ) ) ); 01334 $this->assertEquals( "a{$c}b{$c}c{$and}{$s}d", $lang->listToText( array( 'a', 'b', 'c', 'd' ) ) ); 01335 } 01336 01340 function testIsSupportedLanguage( $code, $expected, $comment ) { 01341 $this->assertEquals( $expected, Language::isSupportedLanguage( $code ), $comment ); 01342 } 01343 01344 static function provideIsSupportedLanguage() { 01345 return array( 01346 array( 'en', true, 'is supported language' ), 01347 array( 'fi', true, 'is supported language' ), 01348 array( 'bunny', false, 'is not supported language' ), 01349 array( 'FI', false, 'is not supported language, input should be in lower case' ), 01350 ); 01351 } 01352 }