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