3 class LanguageTest
extends LanguageClassesTestCase
{
5 * @covers Language::convertDoubleWidth
6 * @covers Language::normalizeForSearch
8 public function testLanguageConvertDoubleWidthToSingleWidth() {
10 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
11 $this->getLang()->normalizeForSearch(
12 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
14 'convertDoubleWidth() with the full alphabet and digits'
19 * @dataProvider provideFormattableTimes#
20 * @covers Language::formatTimePeriod
22 public function testFormatTimePeriod( $seconds, $format, $expected, $desc ) {
23 $this->assertEquals( $expected, $this->getLang()->formatTimePeriod( $seconds, $format ), $desc );
26 public static function provideFormattableTimes() {
32 'formatTimePeriod() rounding (<10s)'
36 array( 'noabbrevs' => true ),
38 'formatTimePeriod() rounding (<10s)'
44 'formatTimePeriod() rounding (<10s)'
48 array( 'noabbrevs' => true ),
50 'formatTimePeriod() rounding (<10s)'
56 'formatTimePeriod() rounding (<60s)'
60 array( 'noabbrevs' => true ),
62 'formatTimePeriod() rounding (<60s)'
68 'formatTimePeriod() rounding (<1h)'
72 array( 'noabbrevs' => true ),
73 '2 minutes 0 seconds',
74 'formatTimePeriod() rounding (<1h)'
80 'formatTimePeriod() rounding (<1h)'
84 array( 'noabbrevs' => true ),
85 '1 hour 0 minutes 0 seconds',
86 'formatTimePeriod() rounding (<1h)'
92 'formatTimePeriod() rounding (>=1h)'
96 array( 'noabbrevs' => true ),
97 '2 hours 0 minutes 0 seconds',
98 'formatTimePeriod() rounding (>=1h)'
104 'formatTimePeriod() rounding (>=1h), avoidseconds'
108 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
110 'formatTimePeriod() rounding (>=1h), avoidseconds'
116 'formatTimePeriod() rounding (>=1h), avoidminutes'
120 array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ),
122 'formatTimePeriod() rounding (>=1h), avoidminutes'
128 'formatTimePeriod() rounding (=48h), avoidseconds'
132 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
133 '48 hours 0 minutes',
134 'formatTimePeriod() rounding (=48h), avoidseconds'
140 'formatTimePeriod() rounding (>48h), avoidminutes'
144 array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ),
146 'formatTimePeriod() rounding (>48h), avoidminutes'
152 'formatTimePeriod() rounding (>48h), avoidseconds'
156 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
157 '2 days 1 hour 0 minutes',
158 'formatTimePeriod() rounding (>48h), avoidseconds'
164 'formatTimePeriod() rounding (>48h), avoidminutes'
168 array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ),
170 'formatTimePeriod() rounding (>48h), avoidminutes'
176 'formatTimePeriod() rounding (>48h), avoidseconds'
180 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
181 '3 days 0 hours 0 minutes',
182 'formatTimePeriod() rounding (>48h), avoidseconds'
188 'formatTimePeriod() rounding, (>48h), avoidseconds'
192 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
193 '2 days 0 hours 0 minutes',
194 'formatTimePeriod() rounding, (>48h), avoidseconds'
200 'formatTimePeriod() rounding, recursion, (>48h)'
204 array( 'noabbrevs' => true ),
205 '2 days 1 hour 1 minute 1 second',
206 'formatTimePeriod() rounding, recursion, (>48h)'
212 * @covers Language::truncate
214 public function testTruncate() {
217 $this->getLang()->truncate( "1234567890", 0, 'XXX' ),
218 'truncate prefix, len 0, small ellipsis'
223 $this->getLang()->truncate( "1234567890", 8, 'XXX' ),
224 'truncate prefix, small ellipsis'
229 $this->getLang()->truncate( "123456789", 5, 'XXXXXXXXXXXXXXX' ),
230 'truncate prefix, large ellipsis'
235 $this->getLang()->truncate( "1234567890", -8, 'XXX' ),
236 'truncate suffix, small ellipsis'
241 $this->getLang()->truncate( "123456789", -5, 'XXXXXXXXXXXXXXX' ),
242 'truncate suffix, large ellipsis'
246 $this->getLang()->truncate( "123 ", 9, 'XXX' ),
247 'truncate prefix, with spaces'
251 $this->getLang()->truncate( "12345 8", 11, 'XXX' ),
252 'truncate prefix, with spaces and non-space ending'
256 $this->getLang()->truncate( "1 234", -8, 'XXX' ),
257 'truncate suffix, with spaces'
261 $this->getLang()->truncate( "1234567890", 5, 'XXX', false ),
262 'truncate without adjustment'
267 * @dataProvider provideHTMLTruncateData
268 * @covers Language::truncateHTML
270 public function testTruncateHtml( $len, $ellipsis, $input, $expected ) {
274 $this->getLang()->truncateHTML( $input, $len, $ellipsis )
279 * @return array format is ($len, $ellipsis, $input, $expected)
281 public static function provideHTMLTruncateData() {
283 array( 0, 'XXX', "1234567890", "XXX" ),
284 array( 8, 'XXX', "1234567890", "12345XXX" ),
285 array( 5, 'XXXXXXXXXXXXXXX', '1234567890', "1234567890" ),
287 '<p><span style="font-weight:bold;"></span></p>',
288 '<p><span style="font-weight:bold;"></span></p>',
291 '<p><span style="font-weight:bold;">123456789</span></p>',
292 '<p><span style="font-weight:bold;">***</span></p>',
295 '<p><span style="font-weight:bold;"> 23456789</span></p>',
296 '<p><span style="font-weight:bold;">***</span></p>',
299 '<p><span style="font-weight:bold;">123456789</span></p>',
300 '<p><span style="font-weight:bold;">***</span></p>',
303 '<p><span style="font-weight:bold;">123456789</span></p>',
304 '<p><span style="font-weight:bold;">1***</span></p>',
307 '<tt><span style="font-weight:bold;">123456789</span></tt>',
308 '<tt><span style="font-weight:bold;">12***</span></tt>',
311 '<p><a href="www.mediawiki.org">123456789</a></p>',
312 '<p><a href="www.mediawiki.org">123***</a></p>',
315 '<p><a href="www.mediawiki.org">12 456789</a></p>',
316 '<p><a href="www.mediawiki.org">12 ***</a></p>',
319 '<small><span style="font-weight:bold;">123<p id="#moo">456</p>789</span></small>',
320 '<small><span style="font-weight:bold;">123<p id="#moo">4***</p></span></small>',
323 '<div><span style="font-weight:bold;">123<span>4</span>56789</span></div>',
324 '<div><span style="font-weight:bold;">123<span>4</span>5***</span></div>',
327 '<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>',
328 '<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>',
331 '<p><font style="font-weight:bold;">123456789</font></p>',
332 '<p><font style="font-weight:bold;">123456789</font></p>',
338 * Test Language::isWellFormedLanguageTag()
339 * @dataProvider provideWellFormedLanguageTags
340 * @covers Language::isWellFormedLanguageTag
342 public function testWellFormedLanguageTag( $code, $message = '' ) {
344 Language
::isWellFormedLanguageTag( $code ),
345 "validating code $code $message"
350 * The test cases are based on the tests in the GaBuZoMeu parser
351 * written by Stéphane Bortzmeyer <bortzmeyer@nic.fr>
352 * and distributed as free software, under the GNU General Public Licence.
353 * http://www.bortzmeyer.org/gabuzomeu-parsing-language-tags.html
355 public static function provideWellFormedLanguageTags() {
357 array( 'fr', 'two-letter code' ),
358 array( 'fr-latn', 'two-letter code with lower case script code' ),
359 array( 'fr-Latn-FR', 'two-letter code with title case script code and uppercase country code' ),
360 array( 'fr-Latn-419', 'two-letter code with title case script code and region number' ),
361 array( 'fr-FR', 'two-letter code with uppercase' ),
362 array( 'ax-TZ', 'Not in the registry, but well-formed' ),
363 array( 'fr-shadok', 'two-letter code with variant' ),
364 array( 'fr-y-myext-myext2', 'non-x singleton' ),
365 array( 'fra-Latn', 'ISO 639 can be 3-letters' ),
366 array( 'fra', 'three-letter language code' ),
367 array( 'fra-FX', 'three-letter language code with country code' ),
368 array( 'i-klingon', 'grandfathered with singleton' ),
369 array( 'I-kLINgon', 'tags are case-insensitive...' ),
370 array( 'no-bok', 'grandfathered without singleton' ),
371 array( 'i-enochian', 'Grandfathered' ),
372 array( 'x-fr-CH', 'private use' ),
373 array( 'es-419', 'two-letter code with region number' ),
374 array( 'en-Latn-GB-boont-r-extended-sequence-x-private', 'weird, but well-formed' ),
375 array( 'ab-x-abc-x-abc', 'anything goes after x' ),
376 array( 'ab-x-abc-a-a', 'anything goes after x, including several non-x singletons' ),
377 array( 'i-default', 'grandfathered' ),
378 array( 'abcd-Latn', 'Language of 4 chars reserved for future use' ),
379 array( 'AaBbCcDd-x-y-any-x', 'Language of 5-8 chars, registered' ),
380 array( 'de-CH-1901', 'with country and year' ),
381 array( 'en-US-x-twain', 'with country and singleton' ),
382 array( 'zh-cmn', 'three-letter variant' ),
383 array( 'zh-cmn-Hant', 'three-letter variant and script' ),
384 array( 'zh-cmn-Hant-HK', 'three-letter variant, script and country' ),
385 array( 'xr-p-lze', 'Extension' ),
390 * Negative test for Language::isWellFormedLanguageTag()
391 * @dataProvider provideMalformedLanguageTags
392 * @covers Language::isWellFormedLanguageTag
394 public function testMalformedLanguageTag( $code, $message = '' ) {
396 Language
::isWellFormedLanguageTag( $code ),
397 "validating that code $code is a malformed language tag - $message"
402 * The test cases are based on the tests in the GaBuZoMeu parser
403 * written by Stéphane Bortzmeyer <bortzmeyer@nic.fr>
404 * and distributed as free software, under the GNU General Public Licence.
405 * http://www.bortzmeyer.org/gabuzomeu-parsing-language-tags.html
407 public static function provideMalformedLanguageTags() {
409 array( 'f', 'language too short' ),
410 array( 'f-Latn', 'language too short with script' ),
411 array( 'xr-lxs-qut', 'variants too short' ), # extlangS
412 array( 'fr-Latn-F', 'region too short' ),
413 array( 'a-value', 'language too short with region' ),
414 array( 'tlh-a-b-foo', 'valid three-letter with wrong variant' ),
415 array( 'i-notexist', 'grandfathered but not registered: invalid, even if we only test well-formedness' ),
416 array( 'abcdefghi-012345678', 'numbers too long' ),
417 array( 'ab-abc-abc-abc-abc', 'invalid extensions' ),
418 array( 'ab-abcd-abc', 'invalid extensions' ),
419 array( 'ab-ab-abc', 'invalid extensions' ),
420 array( 'ab-123-abc', 'invalid extensions' ),
421 array( 'a-Hant-ZH', 'short language with valid extensions' ),
422 array( 'a1-Hant-ZH', 'invalid character in language' ),
423 array( 'ab-abcde-abc', 'invalid extensions' ),
424 array( 'ab-1abc-abc', 'invalid characters in extensions' ),
425 array( 'ab-ab-abcd', 'invalid order of extensions' ),
426 array( 'ab-123-abcd', 'invalid order of extensions' ),
427 array( 'ab-abcde-abcd', 'invalid extensions' ),
428 array( 'ab-1abc-abcd', 'invalid characters in extensions' ),
429 array( 'ab-a-b', 'extensions too short' ),
430 array( 'ab-a-x', 'extensions too short, even with singleton' ),
431 array( 'ab--ab', 'two separators' ),
432 array( 'ab-abc-', 'separator in the end' ),
433 array( '-ab-abc', 'separator in the beginning' ),
434 array( 'abcd-efg', 'language too long' ),
435 array( 'aabbccddE', 'tag too long' ),
436 array( 'pa_guru', 'A tag with underscore is invalid in strict mode' ),
437 array( 'de-f', 'subtag too short' ),
442 * Negative test for Language::isWellFormedLanguageTag()
443 * @covers Language::isWellFormedLanguageTag
445 public function testLenientLanguageTag() {
447 Language
::isWellFormedLanguageTag( 'pa_guru', true ),
448 'pa_guru is a well-formed language tag in lenient mode'
453 * Test Language::isValidBuiltInCode()
454 * @dataProvider provideLanguageCodes
455 * @covers Language::isValidBuiltInCode
457 public function testBuiltInCodeValidation( $code, $message = '' ) {
459 (bool)Language
::isValidBuiltInCode( $code ),
460 "validating code $code $message"
465 * @covers Language::isValidBuiltInCode
467 public function testBuiltInCodeValidationRejectUnderscore() {
469 (bool)Language
::isValidBuiltInCode( 'be_tarask' ),
470 "reject underscore in language code"
474 public static function provideLanguageCodes() {
476 array( 'fr', 'Two letters, minor case' ),
477 array( 'EN', 'Two letters, upper case' ),
478 array( 'tyv', 'Three letters' ),
479 array( 'tokipona', 'long language code' ),
480 array( 'be-tarask', 'With dash' ),
481 array( 'Zh-classical', 'Begin with upper case, dash' ),
482 array( 'Be-x-old', 'With extension (two dashes)' ),
487 * Test Language::isKnownLanguageTag()
488 * @dataProvider provideKnownLanguageTags
489 * @covers Language::isKnownLanguageTag
491 public function testKnownLanguageTag( $code, $message = '' ) {
493 (bool)Language
::isKnownLanguageTag( $code ),
494 "validating code $code - $message"
498 public static function provideKnownLanguageTags() {
500 array( 'fr', 'simple code' ),
501 array( 'bat-smg', 'an MW legacy tag' ),
502 array( 'sgs', 'an internal standard MW name, for which a legacy tag is used externally' ),
507 * @covers Language::isKnownLanguageTag
509 public function testKnownCldrLanguageTag() {
510 if ( !class_exists( 'LanguageNames' ) ) {
511 $this->markTestSkipped( 'The LanguageNames class is not available. The cldr extension is probably not installed.' );
515 (bool)Language
::isKnownLanguageTag( 'pal' ),
516 'validating code "pal" an ancient language, which probably will not appear in Names.php, but appears in CLDR in English'
521 * Negative tests for Language::isKnownLanguageTag()
522 * @dataProvider provideUnKnownLanguageTags
523 * @covers Language::isKnownLanguageTag
525 public function testUnknownLanguageTag( $code, $message = '' ) {
527 (bool)Language
::isKnownLanguageTag( $code ),
528 "checking that code $code is invalid - $message"
532 public static function provideUnknownLanguageTags() {
534 array( 'mw', 'non-existent two-letter code' ),
535 array( 'foo"<bar', 'very invalid language code' ),
540 * Test too short timestamp
541 * @expectedException MWException
542 * @covers Language::sprintfDate
544 public function testSprintfDateTooShortTimestamp() {
545 $this->getLang()->sprintfDate( 'xiY', '1234567890123' );
549 * Test too long timestamp
550 * @expectedException MWException
551 * @covers Language::sprintfDate
553 public function testSprintfDateTooLongTimestamp() {
554 $this->getLang()->sprintfDate( 'xiY', '123456789012345' );
558 * Test too short timestamp
559 * @expectedException MWException
560 * @covers Language::sprintfDate
562 public function testSprintfDateNotAllDigitTimestamp() {
563 $this->getLang()->sprintfDate( 'xiY', '-1234567890123' );
567 * @dataProvider provideSprintfDateSamples
568 * @covers Language::sprintfDate
570 public function testSprintfDate( $format, $ts, $expected, $msg ) {
573 $this->getLang()->sprintfDate( $format, $ts ),
574 "sprintfDate('$format', '$ts'): $msg"
579 * sprintfDate should always use UTC when no zone is given.
580 * @dataProvider provideSprintfDateSamples
581 * @covers Language::sprintfDate
583 public function testSprintfDateNoZone( $format, $ts, $expected, $ignore, $msg ) {
584 $oldTZ = date_default_timezone_get();
585 $res = date_default_timezone_set( 'Asia/Seoul' );
587 $this->markTestSkipped( "Error setting Timezone" );
592 $this->getLang()->sprintfDate( $format, $ts ),
593 "sprintfDate('$format', '$ts'): $msg"
596 date_default_timezone_set( $oldTZ );
600 * sprintfDate should use passed timezone
601 * @dataProvider provideSprintfDateSamples
602 * @covers Language::sprintfDate
604 public function testSprintfDateTZ( $format, $ts, $ignore, $expected, $msg ) {
605 $tz = new DateTimeZone( 'Asia/Seoul' );
607 $this->markTestSkipped( "Error getting Timezone" );
612 $this->getLang()->sprintfDate( $format, $ts, $tz ),
613 "sprintfDate('$format', '$ts', 'Asia/Seoul'): $msg"
617 public static function provideSprintfDateSamples() {
622 '1390', // note because we're testing English locale we get Latin-standard digits
624 'Iranian calendar full year'
631 'Iranian calendar short year'
638 'ISO 8601 (week) year'
661 // What follows is mostly copied from http://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time
688 'Month index, not zero pad'
695 'Month index. Zero pad'
716 'Genitive month name (same in EN)'
723 'Day of month (not zero pad)'
730 'Day of month (zero-pad)'
737 'Day of year (zero-indexed)'
744 'Day of week (abbrev)'
758 'Day of week (Mon=1, Sun=7)'
765 'Day of week (Sun=0, Sat=6)'
807 '12 hour, zero padded'
856 'Days in current month'
861 '2012-01-02T09:07:05+00:00',
862 '2012-01-02T09:07:05+09:00',
868 'Mon, 02 Jan 2012 09:07:05 +0000',
869 'Mon, 02 Jan 2012 09:07:05 +0900',
877 'Timezone identifier'
898 'Timezone offset with colon'
905 'Timezone abbreviation'
912 'Timezone offset in seconds'
940 'Hebrew number of days in month'
947 'Hebrew genitive month name (No difference in EN)'
989 'Raw numerals (doesn\'t mean much in EN)'
992 '[[Y "(yea"\\r)]] \\"xx\\"',
994 '[[2012 (year)]] "x"',
995 '[[2012 (year)]] "x"',
1003 * @dataProvider provideFormatSizes
1004 * @covers Language::formatSize
1006 public function testFormatSize( $size, $expected, $msg ) {
1007 $this->assertEquals(
1009 $this->getLang()->formatSize( $size ),
1010 "formatSize('$size'): $msg"
1014 public static function provideFormatSizes() {
1061 // How big!? THIS BIG!
1066 * @dataProvider provideFormatBitrate
1067 * @covers Language::formatBitrate
1069 public function testFormatBitrate( $bps, $expected, $msg ) {
1070 $this->assertEquals(
1072 $this->getLang()->formatBitrate( $bps ),
1073 "formatBitrate('$bps'): $msg"
1077 public static function provideFormatBitrate() {
1087 "999 bits per second"
1092 "1 kilobit per second"
1097 "1 megabit per second"
1102 "1 gigabit per second"
1107 "1 terabit per second"
1112 "1 petabit per second"
1117 "1 exabit per second"
1122 "1 zetabit per second"
1127 "1 yottabit per second"
1132 "1,000 yottabits per second"
1139 * @dataProvider provideFormatDuration
1140 * @covers Language::formatDuration
1142 public function testFormatDuration( $duration, $expected, $intervals = array() ) {
1143 $this->assertEquals(
1145 $this->getLang()->formatDuration( $duration, $intervals ),
1146 "formatDuration('$duration'): $expected"
1150 public static function provideFormatDuration() {
1189 // ( 365 + ( 24 * 3 + 25 ) / 400 ) * 86400 = 31556952
1190 ( 365 +
( 24 * 3 +
25 ) / 400.0 ) * 86400,
1223 '2 hours, 30 minutes and 1 second'
1227 '1 hour and 1 second'
1230 31556952 +
2 * 86400 +
9000,
1231 '1 year, 2 days, 2 hours and 30 minutes'
1234 42 * 1000 * 31556952 +
42,
1235 '42 millennia and 42 seconds'
1253 31556952 +
2 * 86400 +
9000,
1254 '1 year, 2 days and 150 minutes',
1255 array( 'years', 'days', 'minutes' ),
1260 array( 'years', 'days' ),
1263 31556952 +
2 * 86400 +
9000,
1264 '1 year, 2 days and 150 minutes',
1265 array( 'minutes', 'days', 'years' ),
1270 array( 'days', 'years' ),
1276 * @dataProvider provideCheckTitleEncodingData
1277 * @covers Language::checkTitleEncoding
1279 public function testCheckTitleEncoding( $s ) {
1280 $this->assertEquals(
1282 $this->getLang()->checkTitleEncoding( $s ),
1283 "checkTitleEncoding('$s')"
1287 public static function provideCheckTitleEncodingData() {
1290 array( "United States of America" ), // 7bit ASCII
1291 array( rawurldecode( "S%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e" ) ),
1294 "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn"
1297 // The following two data sets come from bug 36839. They fail if checkTitleEncoding uses a regexp to test for
1298 // valid UTF-8 encoding and the pcre.recursion_limit is low (like, say, 1024). They succeed if checkTitleEncoding
1299 // uses mb_check_encoding for its test.
1302 "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn%7C"
1303 . "Catherine%20Willows%7CDavid%20Hodges%7CDavid%20Phillips%7CGil%20Grissom%7CGreg%20Sanders%7CHodges%7C"
1304 . "Internet%20Movie%20Database%7CJim%20Brass%7CLady%20Heather%7C"
1305 . "Les%20Experts%20(s%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e)%7CLes%20Experts%20:%20Manhattan%7C"
1306 . "Les%20Experts%20:%20Miami%7CListe%20des%20personnages%20des%20Experts%7C"
1307 . "Liste%20des%20%C3%A9pisodes%20des%20Experts%7CMod%C3%A8le%20discussion:Palette%20Les%20Experts%7C"
1308 . "Nick%20Stokes%7CPersonnage%20de%20fiction%7CPersonnage%20fictif%7CPersonnage%20de%20fiction%7C"
1309 . "Personnages%20r%C3%A9currents%20dans%20Les%20Experts%7CRaymond%20Langston%7CRiley%20Adams%7C"
1310 . "Saison%201%20des%20Experts%7CSaison%2010%20des%20Experts%7CSaison%2011%20des%20Experts%7C"
1311 . "Saison%2012%20des%20Experts%7CSaison%202%20des%20Experts%7CSaison%203%20des%20Experts%7C"
1312 . "Saison%204%20des%20Experts%7CSaison%205%20des%20Experts%7CSaison%206%20des%20Experts%7C"
1313 . "Saison%207%20des%20Experts%7CSaison%208%20des%20Experts%7CSaison%209%20des%20Experts%7C"
1314 . "Sara%20Sidle%7CSofia%20Curtis%7CS%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e%7CWallace%20Langham%7C"
1315 . "Warrick%20Brown%7CWendy%20Simms%7C%C3%89tats-Unis"
1320 "Mod%C3%A8le%3AArrondissements%20homonymes%7CMod%C3%A8le%3ABandeau%20standard%20pour%20page%20d'homonymie%7C"
1321 . "Mod%C3%A8le%3ABatailles%20homonymes%7CMod%C3%A8le%3ACantons%20homonymes%7C"
1322 . "Mod%C3%A8le%3ACommunes%20fran%C3%A7aises%20homonymes%7CMod%C3%A8le%3AFilms%20homonymes%7C"
1323 . "Mod%C3%A8le%3AGouvernements%20homonymes%7CMod%C3%A8le%3AGuerres%20homonymes%7CMod%C3%A8le%3AHomonymie%7C"
1324 . "Mod%C3%A8le%3AHomonymie%20bateau%7CMod%C3%A8le%3AHomonymie%20d'%C3%A9tablissements%20scolaires%20ou"
1325 . "%20universitaires%7CMod%C3%A8le%3AHomonymie%20d'%C3%AEles%7CMod%C3%A8le%3AHomonymie%20de%20clubs%20sportifs%7C"
1326 . "Mod%C3%A8le%3AHomonymie%20de%20comt%C3%A9s%7CMod%C3%A8le%3AHomonymie%20de%20monument%7C"
1327 . "Mod%C3%A8le%3AHomonymie%20de%20nom%20romain%7CMod%C3%A8le%3AHomonymie%20de%20parti%20politique%7C"
1328 . "Mod%C3%A8le%3AHomonymie%20de%20route%7CMod%C3%A8le%3AHomonymie%20dynastique%7C"
1329 . "Mod%C3%A8le%3AHomonymie%20vid%C3%A9oludique%7CMod%C3%A8le%3AHomonymie%20%C3%A9difice%20religieux%7C"
1330 . "Mod%C3%A8le%3AInternationalisation%7CMod%C3%A8le%3AIsom%C3%A9rie%7CMod%C3%A8le%3AParonymie%7C"
1331 . "Mod%C3%A8le%3APatronyme%7CMod%C3%A8le%3APatronyme%20basque%7CMod%C3%A8le%3APatronyme%20italien%7C"
1332 . "Mod%C3%A8le%3APatronymie%7CMod%C3%A8le%3APersonnes%20homonymes%7CMod%C3%A8le%3ASaints%20homonymes%7C"
1333 . "Mod%C3%A8le%3ATitres%20homonymes%7CMod%C3%A8le%3AToponymie%7CMod%C3%A8le%3AUnit%C3%A9s%20homonymes%7C"
1334 . "Mod%C3%A8le%3AVilles%20homonymes%7CMod%C3%A8le%3A%C3%89difices%20religieux%20homonymes"
1341 * @dataProvider provideRomanNumeralsData
1342 * @covers Language::romanNumeral
1344 public function testRomanNumerals( $num, $numerals ) {
1345 $this->assertEquals(
1347 Language
::romanNumeral( $num ),
1348 "romanNumeral('$num')"
1352 public static function provideRomanNumeralsData() {
1367 array( 49, 'XLIX' ),
1371 array( 80, 'LXXX' ),
1373 array( 99, 'XCIX' ),
1376 array( 300, 'CCC' ),
1380 array( 700, 'DCC' ),
1381 array( 800, 'DCCC' ),
1383 array( 999, 'CMXCIX' ),
1385 array( 1989, 'MCMLXXXIX' ),
1386 array( 2000, 'MM' ),
1387 array( 3000, 'MMM' ),
1388 array( 4000, 'MMMM' ),
1389 array( 5000, 'MMMMM' ),
1390 array( 6000, 'MMMMMM' ),
1391 array( 7000, 'MMMMMMM' ),
1392 array( 8000, 'MMMMMMMM' ),
1393 array( 9000, 'MMMMMMMMM' ),
1394 array( 9999, 'MMMMMMMMMCMXCIX' ),
1395 array( 10000, 'MMMMMMMMMM' ),
1400 * @dataProvider providePluralData
1401 * @covers Language::convertPlural
1403 public function testConvertPlural( $expected, $number, $forms ) {
1404 $chosen = $this->getLang()->convertPlural( $number, $forms );
1405 $this->assertEquals( $expected, $chosen );
1408 public static function providePluralData() {
1409 // Params are: [expected text, number given, [the plural forms]]
1411 array( 'plural', 0, array(
1412 'singular', 'plural'
1414 array( 'explicit zero', 0, array(
1415 '0=explicit zero', 'singular', 'plural'
1417 array( 'explicit one', 1, array(
1418 'singular', 'plural', '1=explicit one',
1420 array( 'singular', 1, array(
1421 'singular', 'plural', '0=explicit zero',
1423 array( 'plural', 3, array(
1424 '0=explicit zero', '1=explicit one', 'singular', 'plural'
1426 array( 'explicit eleven', 11, array(
1427 'singular', 'plural', '11=explicit eleven',
1429 array( 'plural', 12, array(
1430 'singular', 'plural', '11=explicit twelve',
1432 array( 'plural', 12, array(
1433 'singular', 'plural', '=explicit form',
1435 array( 'other', 2, array(
1436 'kissa=kala', '1=2=3', 'other',
1438 array( '', 2, array(
1439 '0=explicit zero', '1=explicit one',
1445 * @covers Language::translateBlockExpiry()
1446 * @dataProvider provideTranslateBlockExpiry
1448 public function testTranslateBlockExpiry( $expectedData, $str, $desc ) {
1449 $lang = $this->getLang();
1450 if ( is_array( $expectedData ) ) {
1451 list( $func, $arg ) = $expectedData;
1452 $expected = $lang->$func( $arg );
1454 $expected = $expectedData;
1456 $this->assertEquals( $expected, $lang->translateBlockExpiry( $str ), $desc );
1459 public static function provideTranslateBlockExpiry() {
1461 array( '2 hours', '2 hours', 'simple data from ipboptions' ),
1462 array( 'indefinite', 'infinite', 'infinite from ipboptions' ),
1463 array( 'indefinite', 'infinity', 'alternative infinite from ipboptions' ),
1464 array( 'indefinite', 'indefinite', 'another alternative infinite from ipboptions' ),
1465 array( array( 'formatDuration', 1023 * 60 * 60 ), '1023 hours', 'relative' ),
1466 array( array( 'formatDuration', -1023 ), '-1023 seconds', 'negative relative' ),
1467 array( array( 'formatDuration', 0 ), 'now', 'now' ),
1468 array( array( 'timeanddate', '20120102070000' ), '2012-1-1 7:00 +1 day', 'mixed, handled as absolute' ),
1469 array( array( 'timeanddate', '19910203040506' ), '1991-2-3 4:05:06', 'absolute' ),
1470 array( array( 'timeanddate', '19700101000000' ), '1970-1-1 0:00:00', 'absolute at epoch' ),
1471 array( array( 'timeanddate', '19691231235959' ), '1969-12-31 23:59:59', 'time before epoch' ),
1472 array( 'dummy', 'dummy', 'return garbage as is' ),
1477 * @covers Language::commafy()
1478 * @dataProvider provideCommafyData
1480 public function testCommafy( $number, $numbersWithCommas ) {
1481 $this->assertEquals(
1483 $this->getLang()->commafy( $number ),
1484 "commafy('$number')"
1488 public static function provideCommafyData() {
1492 array( 100, '100' ),
1493 array( 1000, '1,000' ),
1494 array( 10000, '10,000' ),
1495 array( 100000, '100,000' ),
1496 array( 1000000, '1,000,000' ),
1497 array( 1.0001, '1.0001' ),
1498 array( 10.0001, '10.0001' ),
1499 array( 100.0001, '100.0001' ),
1500 array( 1000.0001, '1,000.0001' ),
1501 array( 10000.0001, '10,000.0001' ),
1502 array( 100000.0001, '100,000.0001' ),
1503 array( 1000000.0001, '1,000,000.0001' ),
1508 * @covers Language::listToText
1510 public function testListToText() {
1511 $lang = $this->getLang();
1512 $and = $lang->getMessageFromDB( 'and' );
1513 $s = $lang->getMessageFromDB( 'word-separator' );
1514 $c = $lang->getMessageFromDB( 'comma-separator' );
1516 $this->assertEquals( '', $lang->listToText( array() ) );
1517 $this->assertEquals( 'a', $lang->listToText( array( 'a' ) ) );
1518 $this->assertEquals( "a{$and}{$s}b", $lang->listToText( array( 'a', 'b' ) ) );
1519 $this->assertEquals( "a{$c}b{$and}{$s}c", $lang->listToText( array( 'a', 'b', 'c' ) ) );
1520 $this->assertEquals( "a{$c}b{$c}c{$and}{$s}d", $lang->listToText( array( 'a', 'b', 'c', 'd' ) ) );
1524 * @dataProvider provideIsSupportedLanguage
1525 * @covers Language::isSupportedLanguage
1527 public function testIsSupportedLanguage( $code, $expected, $comment ) {
1528 $this->assertEquals( $expected, Language
::isSupportedLanguage( $code ), $comment );
1531 public static function provideIsSupportedLanguage() {
1533 array( 'en', true, 'is supported language' ),
1534 array( 'fi', true, 'is supported language' ),
1535 array( 'bunny', false, 'is not supported language' ),
1536 array( 'FI', false, 'is not supported language, input should be in lower case' ),
1541 * @dataProvider provideGetParentLanguage
1542 * @covers Language::getParentLanguage
1544 public function testGetParentLanguage( $code, $expected, $comment ) {
1545 $lang = Language
::factory( $code );
1546 if ( is_null( $expected ) ) {
1547 $this->assertNull( $lang->getParentLanguage(), $comment );
1549 $this->assertEquals( $expected, $lang->getParentLanguage()->getCode(), $comment );
1553 public static function provideGetParentLanguage() {
1555 array( 'zh-cn', 'zh', 'zh is the parent language of zh-cn' ),
1556 array( 'zh', 'zh', 'zh is defined as the parent language of zh, because zh converter can convert zh-cn to zh' ),
1557 array( 'zh-invalid', null, 'do not be fooled by arbitrarily composed language codes' ),
1558 array( 'en-gb', null, 'en does not have converter' ),
1559 array( 'en', null, 'en does not have converter. Although FakeConverter handles en -> en conversion but it is useless' ),
1564 * @dataProvider provideGetNamespaceAliases
1565 * @covers Language::getNamespaceAliases
1567 public function testGetNamespaceAliases( $languageCode, $subset ) {
1568 $language = Language
::factory( $languageCode );
1569 $aliases = $language->getNamespaceAliases();
1570 foreach ( $subset as $alias => $nsId ) {
1571 $this->assertEquals( $nsId, $aliases[$alias] );
1575 public static function provideGetNamespaceAliases() {
1576 // TODO: Add tests for NS_PROJECT_TALK and GenderNamespaces