3 class LanguageTest
extends LanguageClassesTestCase
{
5 function testLanguageConvertDoubleWidthToSingleWidth() {
7 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
8 $this->getLang()->normalizeForSearch(
9 "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
11 'convertDoubleWidth() with the full alphabet and digits'
16 * @dataProvider provideFormattableTimes
18 function testFormatTimePeriod( $seconds, $format, $expected, $desc ) {
19 $this->assertEquals( $expected, $this->getLang()->formatTimePeriod( $seconds, $format ), $desc );
22 function provideFormattableTimes() {
28 'formatTimePeriod() rounding (<10s)'
32 array( 'noabbrevs' => true ),
34 'formatTimePeriod() rounding (<10s)'
40 'formatTimePeriod() rounding (<10s)'
44 array( 'noabbrevs' => true ),
46 'formatTimePeriod() rounding (<10s)'
52 'formatTimePeriod() rounding (<60s)'
56 array( 'noabbrevs' => true ),
58 'formatTimePeriod() rounding (<60s)'
64 'formatTimePeriod() rounding (<1h)'
68 array( 'noabbrevs' => true ),
69 '2 minutes 0 seconds',
70 'formatTimePeriod() rounding (<1h)'
76 'formatTimePeriod() rounding (<1h)'
80 array( 'noabbrevs' => true ),
81 '1 hour 0 minutes 0 seconds',
82 'formatTimePeriod() rounding (<1h)'
88 'formatTimePeriod() rounding (>=1h)'
92 array( 'noabbrevs' => true ),
93 '2 hours 0 minutes 0 seconds',
94 'formatTimePeriod() rounding (>=1h)'
100 'formatTimePeriod() rounding (>=1h), avoidseconds'
104 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
106 'formatTimePeriod() rounding (>=1h), avoidseconds'
112 'formatTimePeriod() rounding (>=1h), avoidminutes'
116 array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ),
118 'formatTimePeriod() rounding (>=1h), avoidminutes'
124 'formatTimePeriod() rounding (=48h), avoidseconds'
128 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
129 '48 hours 0 minutes',
130 'formatTimePeriod() rounding (=48h), avoidseconds'
136 'formatTimePeriod() rounding (>48h), avoidminutes'
140 array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ),
142 'formatTimePeriod() rounding (>48h), avoidminutes'
148 'formatTimePeriod() rounding (>48h), avoidseconds'
152 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
153 '2 days 1 hour 0 minutes',
154 'formatTimePeriod() rounding (>48h), avoidseconds'
160 'formatTimePeriod() rounding (>48h), avoidminutes'
164 array( 'avoid' => 'avoidminutes', 'noabbrevs' => true ),
166 'formatTimePeriod() rounding (>48h), avoidminutes'
172 'formatTimePeriod() rounding (>48h), avoidseconds'
176 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
177 '3 days 0 hours 0 minutes',
178 'formatTimePeriod() rounding (>48h), avoidseconds'
184 'formatTimePeriod() rounding, (>48h), avoidseconds'
188 array( 'avoid' => 'avoidseconds', 'noabbrevs' => true ),
189 '2 days 0 hours 0 minutes',
190 'formatTimePeriod() rounding, (>48h), avoidseconds'
196 'formatTimePeriod() rounding, recursion, (>48h)'
200 array( 'noabbrevs' => true ),
201 '2 days 1 hour 1 minute 1 second',
202 'formatTimePeriod() rounding, recursion, (>48h)'
208 function testTruncate() {
211 $this->getLang()->truncate( "1234567890", 0, 'XXX' ),
212 'truncate prefix, len 0, small ellipsis'
217 $this->getLang()->truncate( "1234567890", 8, 'XXX' ),
218 'truncate prefix, small ellipsis'
223 $this->getLang()->truncate( "123456789", 5, 'XXXXXXXXXXXXXXX' ),
224 'truncate prefix, large ellipsis'
229 $this->getLang()->truncate( "1234567890", -8, 'XXX' ),
230 'truncate suffix, small ellipsis'
235 $this->getLang()->truncate( "123456789", -5, 'XXXXXXXXXXXXXXX' ),
236 'truncate suffix, large ellipsis'
241 * @dataProvider provideHTMLTruncateData()
243 function testTruncateHtml( $len, $ellipsis, $input, $expected ) {
247 $this->getLang()->truncateHTML( $input, $len, $ellipsis )
252 * Array format is ($len, $ellipsis, $input, $expected)
254 function provideHTMLTruncateData() {
256 array( 0, 'XXX', "1234567890", "XXX" ),
257 array( 8, 'XXX', "1234567890", "12345XXX" ),
258 array( 5, 'XXXXXXXXXXXXXXX', '1234567890', "1234567890" ),
260 '<p><span style="font-weight:bold;"></span></p>',
261 '<p><span style="font-weight:bold;"></span></p>',
264 '<p><span style="font-weight:bold;">123456789</span></p>',
265 '<p><span style="font-weight:bold;">***</span></p>',
268 '<p><span style="font-weight:bold;"> 23456789</span></p>',
269 '<p><span style="font-weight:bold;">***</span></p>',
272 '<p><span style="font-weight:bold;">123456789</span></p>',
273 '<p><span style="font-weight:bold;">***</span></p>',
276 '<p><span style="font-weight:bold;">123456789</span></p>',
277 '<p><span style="font-weight:bold;">1***</span></p>',
280 '<tt><span style="font-weight:bold;">123456789</span></tt>',
281 '<tt><span style="font-weight:bold;">12***</span></tt>',
284 '<p><a href="www.mediawiki.org">123456789</a></p>',
285 '<p><a href="www.mediawiki.org">123***</a></p>',
288 '<p><a href="www.mediawiki.org">12 456789</a></p>',
289 '<p><a href="www.mediawiki.org">12 ***</a></p>',
292 '<small><span style="font-weight:bold;">123<p id="#moo">456</p>789</span></small>',
293 '<small><span style="font-weight:bold;">123<p id="#moo">4***</p></span></small>',
296 '<div><span style="font-weight:bold;">123<span>4</span>56789</span></div>',
297 '<div><span style="font-weight:bold;">123<span>4</span>5***</span></div>',
300 '<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>',
301 '<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>',
304 '<p><font style="font-weight:bold;">123456789</font></p>',
305 '<p><font style="font-weight:bold;">123456789</font></p>',
311 * Test Language::isValidBuiltInCode()
312 * @dataProvider provideLanguageCodes
314 function testBuiltInCodeValidation( $code, $message = '' ) {
316 (bool) Language
::isValidBuiltInCode( $code ),
317 "validating code $code $message"
321 function testBuiltInCodeValidationRejectUnderscore() {
323 (bool) Language
::isValidBuiltInCode( 'be_tarask' ),
324 "reject underscore in language code"
328 function provideLanguageCodes() {
330 array( 'fr' , 'Two letters, minor case' ),
331 array( 'EN' , 'Two letters, upper case' ),
332 array( 'tyv' , 'Three letters' ),
333 array( 'tokipona' , 'long language code' ),
334 array( 'be-tarask', 'With dash' ),
335 array( 'Zh-classical', 'Begin with upper case, dash' ),
336 array( 'Be-x-old', 'With extension (two dashes)' ),
341 * @dataProvider provideSprintfDateSamples
343 function testSprintfDate( $format, $ts, $expected, $msg ) {
346 $this->getLang()->sprintfDate( $format, $ts ),
347 "sprintfDate('$format', '$ts'): $msg"
351 * bug 33454. sprintfDate should always use UTC.
352 * @dataProvider provideSprintfDateSamples
354 function testSprintfDateTZ( $format, $ts, $expected, $msg ) {
355 $oldTZ = date_default_timezone_get();
356 $res = date_default_timezone_set( 'Asia/Seoul' );
358 $this->markTestSkipped( "Error setting Timezone" );
363 $this->getLang()->sprintfDate( $format, $ts ),
364 "sprintfDate('$format', '$ts'): $msg"
367 date_default_timezone_set( $oldTZ );
370 function provideSprintfDateSamples() {
375 '1390', // note because we're testing English locale we get Latin-standard digits
376 'Iranian calendar full year'
382 'Iranian calendar short year'
388 'ISO 8601 (week) year'
408 // What follows is mostly copied from http://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time
431 'Month index, not zero pad'
437 'Month index. Zero pad'
455 'Genitive month name (same in EN)'
461 'Day of month (not zero pad)'
467 'Day of month (zero-pad)'
473 'Day of year (zero-indexed)'
479 'Day of week (abbrev)'
491 'Day of week (Mon=1, Sun=7)'
497 'Day of week (Sun=0, Sat=6)'
533 '12 hour, zero padded'
575 'Days in current month'
580 '2012-01-02T09:07:05+00:00',
586 'Mon, 02 Jan 2012 09:07:05 +0000',
611 'Hebrew number of days in month'
617 'Hebrew genitive month name (No difference in EN)'
653 'Raw numerals (doesn\'t mean much in EN)'
656 '[[Y "(yea"\\r)]] \\"xx\\"',
658 '[[2012 (year)]] "x"',
666 * @dataProvider provideFormatSizes
668 function testFormatSize( $size, $expected, $msg ) {
671 $this->getLang()->formatSize( $size ),
672 "formatSize('$size'): $msg"
676 function provideFormatSizes() {
723 // How big!? THIS BIG!
728 * @dataProvider provideFormatBitrate
730 function testFormatBitrate( $bps, $expected, $msg ) {
733 $this->getLang()->formatBitrate( $bps ),
734 "formatBitrate('$bps'): $msg"
738 function provideFormatBitrate() {
748 "999 bits per second"
753 "1 kilobit per second"
758 "1 megabit per second"
763 "1 gigabit per second"
768 "1 terabit per second"
773 "1 petabit per second"
778 "1 exabit per second"
783 "1 zetabit per second"
788 "1 yottabit per second"
793 "1,000 yottabits per second"
801 * @dataProvider provideFormatDuration
803 function testFormatDuration( $duration, $expected, $intervals = array() ) {
806 $this->getLang()->formatDuration( $duration, $intervals ),
807 "formatDuration('$duration'): $expected"
811 function provideFormatDuration() {
850 // ( 365 + ( 24 * 3 + 25 ) / 400 ) * 86400 = 31556952
851 ( 365 +
( 24 * 3 +
25 ) / 400.0 ) * 86400,
884 '2 hours, 30 minutes and 1 second'
888 '1 hour and 1 second'
891 31556952 +
2 * 86400 +
9000,
892 '1 year, 2 days, 2 hours and 30 minutes'
895 42 * 1000 * 31556952 +
42,
896 '42 millennia and 42 seconds'
914 31556952 +
2 * 86400 +
9000,
915 '1 year, 2 days and 150 minutes',
916 array( 'years', 'days', 'minutes' ),
921 array( 'years', 'days' ),
924 31556952 +
2 * 86400 +
9000,
925 '1 year, 2 days and 150 minutes',
926 array( 'minutes', 'days', 'years' ),
931 array( 'days', 'years' ),
937 * @dataProvider provideCheckTitleEncodingData
939 function testCheckTitleEncoding( $s ) {
942 $this->getLang()->checkTitleEncoding($s),
943 "checkTitleEncoding('$s')"
947 function provideCheckTitleEncodingData() {
950 array( "United States of America" ), // 7bit ASCII
951 array( rawurldecode( "S%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e" ) ),
954 "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn"
957 // The following two data sets come from bug 36839. They fail if checkTitleEncoding uses a regexp to test for
958 // valid UTF-8 encoding and the pcre.recursion_limit is low (like, say, 1024). They succeed if checkTitleEncoding
959 // uses mb_check_encoding for its test.
962 "Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn%7C"
963 . "Catherine%20Willows%7CDavid%20Hodges%7CDavid%20Phillips%7CGil%20Grissom%7CGreg%20Sanders%7CHodges%7C"
964 . "Internet%20Movie%20Database%7CJim%20Brass%7CLady%20Heather%7C"
965 . "Les%20Experts%20(s%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e)%7CLes%20Experts%20:%20Manhattan%7C"
966 . "Les%20Experts%20:%20Miami%7CListe%20des%20personnages%20des%20Experts%7C"
967 . "Liste%20des%20%C3%A9pisodes%20des%20Experts%7CMod%C3%A8le%20discussion:Palette%20Les%20Experts%7C"
968 . "Nick%20Stokes%7CPersonnage%20de%20fiction%7CPersonnage%20fictif%7CPersonnage%20de%20fiction%7C"
969 . "Personnages%20r%C3%A9currents%20dans%20Les%20Experts%7CRaymond%20Langston%7CRiley%20Adams%7C"
970 . "Saison%201%20des%20Experts%7CSaison%2010%20des%20Experts%7CSaison%2011%20des%20Experts%7C"
971 . "Saison%2012%20des%20Experts%7CSaison%202%20des%20Experts%7CSaison%203%20des%20Experts%7C"
972 . "Saison%204%20des%20Experts%7CSaison%205%20des%20Experts%7CSaison%206%20des%20Experts%7C"
973 . "Saison%207%20des%20Experts%7CSaison%208%20des%20Experts%7CSaison%209%20des%20Experts%7C"
974 . "Sara%20Sidle%7CSofia%20Curtis%7CS%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e%7CWallace%20Langham%7C"
975 . "Warrick%20Brown%7CWendy%20Simms%7C%C3%89tats-Unis"
980 "Mod%C3%A8le%3AArrondissements%20homonymes%7CMod%C3%A8le%3ABandeau%20standard%20pour%20page%20d'homonymie%7C"
981 . "Mod%C3%A8le%3ABatailles%20homonymes%7CMod%C3%A8le%3ACantons%20homonymes%7C"
982 . "Mod%C3%A8le%3ACommunes%20fran%C3%A7aises%20homonymes%7CMod%C3%A8le%3AFilms%20homonymes%7C"
983 . "Mod%C3%A8le%3AGouvernements%20homonymes%7CMod%C3%A8le%3AGuerres%20homonymes%7CMod%C3%A8le%3AHomonymie%7C"
984 . "Mod%C3%A8le%3AHomonymie%20bateau%7CMod%C3%A8le%3AHomonymie%20d'%C3%A9tablissements%20scolaires%20ou"
985 . "%20universitaires%7CMod%C3%A8le%3AHomonymie%20d'%C3%AEles%7CMod%C3%A8le%3AHomonymie%20de%20clubs%20sportifs%7C"
986 . "Mod%C3%A8le%3AHomonymie%20de%20comt%C3%A9s%7CMod%C3%A8le%3AHomonymie%20de%20monument%7C"
987 . "Mod%C3%A8le%3AHomonymie%20de%20nom%20romain%7CMod%C3%A8le%3AHomonymie%20de%20parti%20politique%7C"
988 . "Mod%C3%A8le%3AHomonymie%20de%20route%7CMod%C3%A8le%3AHomonymie%20dynastique%7C"
989 . "Mod%C3%A8le%3AHomonymie%20vid%C3%A9oludique%7CMod%C3%A8le%3AHomonymie%20%C3%A9difice%20religieux%7C"
990 . "Mod%C3%A8le%3AInternationalisation%7CMod%C3%A8le%3AIsom%C3%A9rie%7CMod%C3%A8le%3AParonymie%7C"
991 . "Mod%C3%A8le%3APatronyme%7CMod%C3%A8le%3APatronyme%20basque%7CMod%C3%A8le%3APatronyme%20italien%7C"
992 . "Mod%C3%A8le%3APatronymie%7CMod%C3%A8le%3APersonnes%20homonymes%7CMod%C3%A8le%3ASaints%20homonymes%7C"
993 . "Mod%C3%A8le%3ATitres%20homonymes%7CMod%C3%A8le%3AToponymie%7CMod%C3%A8le%3AUnit%C3%A9s%20homonymes%7C"
994 . "Mod%C3%A8le%3AVilles%20homonymes%7CMod%C3%A8le%3A%C3%89difices%20religieux%20homonymes"
1001 * @dataProvider provideRomanNumeralsData
1003 function testRomanNumerals( $num, $numerals ) {
1004 $this->assertEquals(
1006 Language
::romanNumeral( $num ),
1007 "romanNumeral('$num')"
1011 function provideRomanNumeralsData() {
1026 array( 49, 'XLIX' ),
1030 array( 80, 'LXXX' ),
1032 array( 99, 'XCIX' ),
1035 array( 300, 'CCC' ),
1039 array( 700, 'DCC' ),
1040 array( 800, 'DCCC' ),
1042 array( 999, 'CMXCIX' ),
1044 array( 1989, 'MCMLXXXIX' ),
1045 array( 2000, 'MM' ),
1046 array( 3000, 'MMM' ),
1047 array( 4000, 'MMMM' ),
1048 array( 5000, 'MMMMM' ),
1049 array( 6000, 'MMMMMM' ),
1050 array( 7000, 'MMMMMMM' ),
1051 array( 8000, 'MMMMMMMM' ),
1052 array( 9000, 'MMMMMMMMM' ),
1053 array( 9999, 'MMMMMMMMMCMXCIX'),
1054 array( 10000, 'MMMMMMMMMM' ),
1059 * @dataProvider providePluralData
1061 function testConvertPlural( $expected, $number, $forms ) {
1062 $chosen = $this->getLang()->convertPlural( $number, $forms );
1063 $this->assertEquals( $expected, $chosen );
1066 function providePluralData() {
1068 array( 'explicit zero', 0, array(
1069 '0=explicit zero', 'singular', 'plural'
1071 array( 'explicit one', 1, array(
1072 'singular', 'plural', '1=explicit one',
1074 array( 'singular', 1, array(
1075 'singular', 'plural', '0=explicit zero',
1077 array( 'plural', 3, array(
1078 '0=explicit zero', '1=explicit one', 'singular', 'plural'
1084 * @covers Language::translateBlockExpiry()
1085 * @dataProvider provideTranslateBlockExpiry
1087 function testTranslateBlockExpiry( $expectedData, $str, $desc ) {
1088 $lang = $this->getLang();
1089 if ( is_array( $expectedData ) ) {
1090 list( $func, $arg ) = $expectedData;
1091 $expected = $lang->$func( $arg );
1093 $expected = $expectedData;
1095 $this->assertEquals( $expected, $lang->translateBlockExpiry( $str ), $desc );
1098 function provideTranslateBlockExpiry() {
1100 array( '2 hours', '2 hours', 'simple data from ipboptions' ),
1101 array( 'indefinite', 'infinite', 'infinite from ipboptions' ),
1102 array( 'indefinite', 'infinity', 'alternative infinite from ipboptions' ),
1103 array( 'indefinite', 'indefinite', 'another alternative infinite from ipboptions' ),
1104 array( array( 'formatDuration', 1023 * 60 * 60 ), '1023 hours', 'relative' ),
1105 array( array( 'formatDuration', -1023 ), '-1023 seconds', 'negative relative' ),
1106 array( array( 'formatDuration', 0 ), 'now', 'now' ),
1107 array( array( 'timeanddate', '20120102070000' ), '2012-1-1 7:00 +1 day', 'mixed, handled as absolute' ),
1108 array( array( 'timeanddate', '19910203040506' ), '1991-2-3 4:05:06', 'absolute' ),
1109 array( array( 'timeanddate', '19700101000000' ), '1970-1-1 0:00:00', 'absolute at epoch' ),
1110 array( array( 'timeanddate', '19691231235959' ), '1969-12-31 23:59:59', 'time before epoch' ),
1111 array( 'dummy', 'dummy', 'return garbage as is' ),
1116 * @covers Language::commafy()
1117 * @dataProvider provideCommafyData
1119 function testCommafy( $number, $numbersWithCommas ) {
1120 $this->assertEquals(
1122 $this->getLang()->commafy( $number ),
1123 "commafy('$number')"
1127 function provideCommafyData() {
1131 array( 100, '100' ),
1132 array( 1000, '1,000' ),
1133 array( 10000, '10,000' ),
1134 array( 100000, '100,000' ),
1135 array( 1000000, '1,000,000' ),
1136 array( 1.0001, '1.0001' ),
1137 array( 10.0001, '10.0001' ),
1138 array( 100.0001, '100.0001' ),
1139 array( 1000.0001, '1,000.0001' ),
1140 array( 10000.0001, '10,000.0001' ),
1141 array( 100000.0001, '100,000.0001' ),
1142 array( 1000000.0001, '1,000,000.0001' ),
1146 function testListToText() {
1147 $lang = $this->getLang();
1148 $and = $lang->getMessageFromDB( 'and' );
1149 $s = $lang->getMessageFromDB( 'word-separator' );
1150 $c = $lang->getMessageFromDB( 'comma-separator' );
1152 $this->assertEquals( '', $lang->listToText( array( ) ) );
1153 $this->assertEquals( 'a', $lang->listToText( array( 'a' ) ) );
1154 $this->assertEquals( "a{$and}{$s}b", $lang->listToText( array( 'a', 'b' ) ) );
1155 $this->assertEquals( "a{$c}b{$and}{$s}c", $lang->listToText( array( 'a', 'b', 'c' ) ) );
1156 $this->assertEquals( "a{$c}b{$c}c{$and}{$s}d", $lang->listToText( array( 'a', 'b', 'c', 'd' ) ) );
1160 * @dataProvider provideIsSupportedLanguage
1162 function testIsSupportedLanguage( $code, $expected, $comment ) {
1163 $this->assertEquals( $expected, Language
::isSupportedLanguage( $code ), $comment );
1166 static function provideIsSupportedLanguage() {
1168 array( 'en', true, 'is supported language' ),
1169 array( 'fi', true, 'is supported language' ),
1170 array( 'bunny', false, 'is not supported language' ),
1171 array( 'FI', false, 'is not supported language, input should be in lower case' ),