Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4111938
LanguageIntegrationTest.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
60 KB
Referenced Files
None
Subscribers
None
LanguageIntegrationTest.php
View Options
<?php
use
MediaWiki\Config\HashConfig
;
use
MediaWiki\Config\MultiConfig
;
use
MediaWiki\Config\ServiceOptions
;
use
MediaWiki\HookContainer\HookContainer
;
use
MediaWiki\Language\Language
;
use
MediaWiki\Languages\LanguageConverterFactory
;
use
MediaWiki\Languages\LanguageFallback
;
use
MediaWiki\Languages\LanguageNameUtils
;
use
MediaWiki\MainConfigNames
;
use
MediaWiki\MediaWikiServices
;
use
MediaWiki\Registration\ExtensionRegistry
;
use
MediaWiki\Tests\Unit\DummyServicesTrait
;
use
MediaWiki\Title\NamespaceInfo
;
use
MediaWiki\User\UserIdentityValue
;
use
Wikimedia\TestingAccessWrapper
;
/**
* @group Language
* @covers \MediaWiki\Language\Language
* @covers \MediaWiki\Languages\LanguageNameUtils
*/
class
LanguageIntegrationTest
extends
LanguageClassesTestCase
{
use
DummyServicesTrait
;
use
LanguageNameUtilsTestTrait
;
private
function
newLanguage
(
$class
=
Language
::
class
,
$code
=
'en'
)
{
// Needed to support the setMwGlobals calls for the various tests, but this should
// probably be changed to have the configuration injected into this method instead
// at some point
$config
=
$this
->
getServiceContainer
()->
getMainConfig
();
return
new
$class
(
$code
,
$this
->
createNoOpMock
(
NamespaceInfo
::
class
),
$this
->
createNoOpMock
(
LocalisationCache
::
class
),
$this
->
createNoOpMock
(
LanguageNameUtils
::
class
),
$this
->
createNoOpMock
(
LanguageFallback
::
class
),
$this
->
createNoOpMock
(
LanguageConverterFactory
::
class
),
$this
->
createHookContainer
(),
$config
);
}
protected
function
setUp
():
void
{
parent
::
setUp
();
$this
->
overrideConfigValue
(
MainConfigNames
::
UsePigLatinVariant
,
true
);
}
public
function
testLanguageConvertDoubleWidthToSingleWidth
()
{
$this
->
assertSame
(
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
,
$this
->
getLang
()->
normalizeForSearch
(
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
),
'convertDoubleWidth() with the full alphabet and digits'
);
}
/**
* @dataProvider provideFormattableTimes
*/
public
function
testFormatTimePeriod
(
$seconds
,
$format
,
$expected
,
$desc
)
{
$this
->
assertEquals
(
$expected
,
$this
->
getLang
()->
formatTimePeriod
(
$seconds
,
$format
),
$desc
);
}
public
static
function
provideFormattableTimes
()
{
return
[
[
9.45
,
[],
'9.5 s'
,
'formatTimePeriod() rounding (<10s)'
],
[
9.45
,
[
'noabbrevs'
=>
true
],
'9.5 seconds'
,
'formatTimePeriod() rounding (<10s)'
],
[
9.95
,
[],
'10 s'
,
'formatTimePeriod() rounding (<10s)'
],
[
9.95
,
[
'noabbrevs'
=>
true
],
'10 seconds'
,
'formatTimePeriod() rounding (<10s)'
],
[
59.55
,
[],
'1 min 0 s'
,
'formatTimePeriod() rounding (<60s)'
],
[
59.55
,
[
'noabbrevs'
=>
true
],
'1 minute 0 seconds'
,
'formatTimePeriod() rounding (<60s)'
],
[
119.55
,
[],
'2 min 0 s'
,
'formatTimePeriod() rounding (<1h)'
],
[
119.55
,
[
'noabbrevs'
=>
true
],
'2 minutes 0 seconds'
,
'formatTimePeriod() rounding (<1h)'
],
[
3599.55
,
[],
'1 h 0 min 0 s'
,
'formatTimePeriod() rounding (<1h)'
],
[
3599.55
,
[
'noabbrevs'
=>
true
],
'1 hour 0 minutes 0 seconds'
,
'formatTimePeriod() rounding (<1h)'
],
[
7199.55
,
[],
'2 h 0 min 0 s'
,
'formatTimePeriod() rounding (>=1h)'
],
[
7199.55
,
[
'noabbrevs'
=>
true
],
'2 hours 0 minutes 0 seconds'
,
'formatTimePeriod() rounding (>=1h)'
],
[
7199.55
,
'avoidseconds'
,
'2 h 0 min'
,
'formatTimePeriod() rounding (>=1h), avoidseconds'
],
[
7199.55
,
[
'avoid'
=>
'avoidseconds'
,
'noabbrevs'
=>
true
],
'2 hours 0 minutes'
,
'formatTimePeriod() rounding (>=1h), avoidseconds'
],
[
7199.55
,
'avoidminutes'
,
'2 h 0 min'
,
'formatTimePeriod() rounding (>=1h), avoidminutes'
],
[
7199.55
,
[
'avoid'
=>
'avoidminutes'
,
'noabbrevs'
=>
true
],
'2 hours 0 minutes'
,
'formatTimePeriod() rounding (>=1h), avoidminutes'
],
[
172799.55
,
'avoidseconds'
,
'48 h 0 min'
,
'formatTimePeriod() rounding (=48h), avoidseconds'
],
[
172799.55
,
[
'avoid'
=>
'avoidseconds'
,
'noabbrevs'
=>
true
],
'48 hours 0 minutes'
,
'formatTimePeriod() rounding (=48h), avoidseconds'
],
[
259199.55
,
'avoidhours'
,
'3 d'
,
'formatTimePeriod() rounding (>48h), avoidhours'
],
[
259199.55
,
[
'avoid'
=>
'avoidhours'
,
'noabbrevs'
=>
true
],
'3 days'
,
'formatTimePeriod() rounding (>48h), avoidhours'
],
[
259199.55
,
'avoidminutes'
,
'3 d 0 h'
,
'formatTimePeriod() rounding (>48h), avoidminutes'
],
[
259199.55
,
[
'avoid'
=>
'avoidminutes'
,
'noabbrevs'
=>
true
],
'3 days 0 hours'
,
'formatTimePeriod() rounding (>48h), avoidminutes'
],
[
176399.55
,
'avoidseconds'
,
'2 d 1 h 0 min'
,
'formatTimePeriod() rounding (>48h), avoidseconds'
],
[
176399.55
,
[
'avoid'
=>
'avoidseconds'
,
'noabbrevs'
=>
true
],
'2 days 1 hour 0 minutes'
,
'formatTimePeriod() rounding (>48h), avoidseconds'
],
[
176399.55
,
'avoidminutes'
,
'2 d 1 h'
,
'formatTimePeriod() rounding (>48h), avoidminutes'
],
[
176399.55
,
[
'avoid'
=>
'avoidminutes'
,
'noabbrevs'
=>
true
],
'2 days 1 hour'
,
'formatTimePeriod() rounding (>48h), avoidminutes'
],
[
259199.55
,
'avoidseconds'
,
'3 d 0 h 0 min'
,
'formatTimePeriod() rounding (>48h), avoidseconds'
],
[
259199.55
,
[
'avoid'
=>
'avoidseconds'
,
'noabbrevs'
=>
true
],
'3 days 0 hours 0 minutes'
,
'formatTimePeriod() rounding (>48h), avoidseconds'
],
[
172801.55
,
'avoidseconds'
,
'2 d 0 h 0 min'
,
'formatTimePeriod() rounding, (>48h), avoidseconds'
],
[
172801.55
,
[
'avoid'
=>
'avoidseconds'
,
'noabbrevs'
=>
true
],
'2 days 0 hours 0 minutes'
,
'formatTimePeriod() rounding, (>48h), avoidseconds'
],
[
176460.55
,
[],
'2 d 1 h 1 min 1 s'
,
'formatTimePeriod() rounding, recursion, (>48h)'
],
[
176460.55
,
[
'noabbrevs'
=>
true
],
'2 days 1 hour 1 minute 1 second'
,
'formatTimePeriod() rounding, recursion, (>48h)'
],
];
}
public
function
testTruncateForDatabase
()
{
$this
->
assertEquals
(
"XXX"
,
$this
->
getLang
()->
truncateForDatabase
(
"1234567890"
,
0
,
'XXX'
),
'truncate prefix, len 0, small ellipsis'
);
$this
->
assertEquals
(
"12345XXX"
,
$this
->
getLang
()->
truncateForDatabase
(
"1234567890"
,
8
,
'XXX'
),
'truncate prefix, small ellipsis'
);
$this
->
assertSame
(
"123456789"
,
$this
->
getLang
()->
truncateForDatabase
(
"123456789"
,
5
,
'XXXXXXXXXXXXXXX'
),
'truncate prefix, large ellipsis'
);
$this
->
assertEquals
(
"XXX67890"
,
$this
->
getLang
()->
truncateForDatabase
(
"1234567890"
,
-
8
,
'XXX'
),
'truncate suffix, small ellipsis'
);
$this
->
assertSame
(
"123456789"
,
$this
->
getLang
()->
truncateForDatabase
(
"123456789"
,
-
5
,
'XXXXXXXXXXXXXXX'
),
'truncate suffix, large ellipsis'
);
$this
->
assertEquals
(
"123XXX"
,
$this
->
getLang
()->
truncateForDatabase
(
"123 "
,
9
,
'XXX'
),
'truncate prefix, with spaces'
);
$this
->
assertEquals
(
"12345XXX"
,
$this
->
getLang
()->
truncateForDatabase
(
"12345 8"
,
11
,
'XXX'
),
'truncate prefix, with spaces and non-space ending'
);
$this
->
assertEquals
(
"XXX234"
,
$this
->
getLang
()->
truncateForDatabase
(
"1 234"
,
-
8
,
'XXX'
),
'truncate suffix, with spaces'
);
$this
->
assertEquals
(
"12345XXX"
,
$this
->
getLang
()->
truncateForDatabase
(
"1234567890"
,
5
,
'XXX'
,
false
),
'truncate without adjustment'
);
$this
->
assertEquals
(
"泰乐菌..."
,
$this
->
getLang
()->
truncateForDatabase
(
"泰乐菌素123456789"
,
11
,
'...'
,
false
),
'truncate does not chop Unicode characters in half'
);
$this
->
assertEquals
(
"
\n
泰乐菌..."
,
$this
->
getLang
()->
truncateForDatabase
(
"
\n
泰乐菌素123456789"
,
12
,
'...'
,
false
),
'truncate does not chop Unicode characters in half if there is a preceding newline'
);
}
/**
* @dataProvider provideTruncateData
*/
public
function
testTruncateForVisual
(
$expected
,
$string
,
$length
,
$ellipsis
=
'...'
,
$adjustLength
=
true
)
{
$this
->
assertEquals
(
$expected
,
$this
->
getLang
()->
truncateForVisual
(
$string
,
$length
,
$ellipsis
,
$adjustLength
)
);
}
/**
* @return array Format is ($expected, $string, $length, $ellipsis, $adjustLength)
*/
public
static
function
provideTruncateData
()
{
return
[
[
"XXX"
,
"тестирам да ли ради"
,
0
,
"XXX"
],
[
"testnXXX"
,
"testni scenarij"
,
8
,
"XXX"
],
[
"حالة اختبار"
,
"حالة اختبار"
,
5
,
"XXXXXXXXXXXXXXX"
],
[
"XXXедент"
,
"прецедент"
,
-
8
,
"XXX"
],
[
"XXപിൾ"
,
"ആപ്പിൾ"
,
-
5
,
"XX"
],
[
"神秘XXX"
,
"神秘 "
,
9
,
"XXX"
],
[
"ΔημιουργXXX"
,
"Δημιουργία Σύμπαντος"
,
11
,
"XXX"
],
[
"XXXの家です"
,
"地球は私たちの唯 の家です"
,
-
8
,
"XXX"
],
[
"زندگیXXX"
,
"زندگی زیباست"
,
6
,
"XXX"
,
false
],
[
"ცხოვრება..."
,
"ცხოვრება არის საოცარი"
,
8
,
"..."
,
false
],
[
"
\n
ທ່ານ..."
,
"
\n
ທ່ານບໍ່ຮູ້ຫນັງສື"
,
5
,
"..."
,
false
],
];
}
/**
* @dataProvider provideHTMLTruncateData
*/
public
function
testTruncateHtml
(
$len
,
$ellipsis
,
$input
,
$expected
)
{
// Actual HTML...
$this
->
assertEquals
(
$expected
,
$this
->
getLang
()->
truncateHtml
(
$input
,
$len
,
$ellipsis
)
);
}
/**
* @return array Format is ($len, $ellipsis, $input, $expected)
*/
public
static
function
provideHTMLTruncateData
()
{
return
[
[
0
,
'XXX'
,
"1234567890"
,
"XXX"
],
[
8
,
'XXX'
,
"1234567890"
,
"12345XXX"
],
[
5
,
'XXXXXXXXXXXXXXX'
,
'1234567890'
,
"1234567890"
],
[
2
,
'***'
,
'<p><span style="font-weight:bold;"></span></p>'
,
'<p><span style="font-weight:bold;"></span></p>'
,
],
[
2
,
'***'
,
'<p><span style="font-weight:bold;">123456789</span></p>'
,
'<p><span style="font-weight:bold;">***</span></p>'
,
],
[
2
,
'***'
,
'<p><span style="font-weight:bold;"> 23456789</span></p>'
,
'<p><span style="font-weight:bold;">***</span></p>'
,
],
[
3
,
'***'
,
'<p><span style="font-weight:bold;">123456789</span></p>'
,
'<p><span style="font-weight:bold;">***</span></p>'
,
],
[
4
,
'***'
,
'<p><span style="font-weight:bold;">123456789</span></p>'
,
'<p><span style="font-weight:bold;">1***</span></p>'
,
],
[
5
,
'***'
,
'<tt><span style="font-weight:bold;">123456789</span></tt>'
,
'<tt><span style="font-weight:bold;">12***</span></tt>'
,
],
[
6
,
'***'
,
'<p><a href="www.mediawiki.org">123456789</a></p>'
,
'<p><a href="www.mediawiki.org">123***</a></p>'
,
],
[
6
,
'***'
,
'<p><a href="www.mediawiki.org">12 456789</a></p>'
,
'<p><a href="www.mediawiki.org">12 ***</a></p>'
,
],
[
7
,
'***'
,
'<small><span style="font-weight:bold;">123<p id="#moo">456</p>789</span></small>'
,
'<small><span style="font-weight:bold;">123<p id="#moo">4***</p></span></small>'
,
],
[
8
,
'***'
,
'<div><span style="font-weight:bold;">123<span>4</span>56789</span></div>'
,
'<div><span style="font-weight:bold;">123<span>4</span>5***</span></div>'
,
],
[
9
,
'***'
,
'<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>'
,
'<p><table style="font-weight:bold;"><tr><td>123456789</td></tr></table></p>'
,
],
[
10
,
'***'
,
'<p><font style="font-weight:bold;">123456789</font></p>'
,
'<p><font style="font-weight:bold;">123456789</font></p>'
,
],
[
10
,
'***'
,
'<p><font style="font-weight:bold;">123456789</font'
,
'<p><font style="font-weight:bold;">123456789</font</p>'
,
],
];
}
/**
* Test too short timestamp
*/
public
function
testSprintfDateTooShortTimestamp
()
{
$this
->
expectException
(
InvalidArgumentException
::
class
);
$this
->
getLang
()->
sprintfDate
(
'xiY'
,
'1234567890123'
);
}
/**
* Test too long timestamp
*/
public
function
testSprintfDateTooLongTimestamp
()
{
$this
->
expectException
(
InvalidArgumentException
::
class
);
$this
->
getLang
()->
sprintfDate
(
'xiY'
,
'123456789012345'
);
}
/**
* Test too short timestamp
*/
public
function
testSprintfDateNotAllDigitTimestamp
()
{
$this
->
expectException
(
InvalidArgumentException
::
class
);
$this
->
getLang
()->
sprintfDate
(
'xiY'
,
'-1234567890123'
);
}
/**
* @dataProvider provideSprintfDateSamples
*/
public
function
testSprintfDate
(
$format
,
$ts
,
$expected
,
$msg
)
{
$ttl
=
null
;
$this
->
assertSame
(
$expected
,
$this
->
getLang
()->
sprintfDate
(
$format
,
$ts
,
null
,
$ttl
),
"sprintfDate('$format', '$ts'): $msg"
);
if
(
$ttl
)
{
$dt
=
new
DateTime
(
$ts
);
$lastValidTS
=
$dt
->
add
(
new
DateInterval
(
'PT'
.
(
$ttl
-
1
)
.
'S'
)
)->
format
(
'YmdHis'
);
$this
->
assertSame
(
$expected
,
$this
->
getLang
()->
sprintfDate
(
$format
,
$lastValidTS
,
null
),
"sprintfDate('$format', '$ts'): TTL $ttl too high (output was different at $lastValidTS)"
);
}
else
{
// advance the time enough to make all of the possible outputs different (except possibly L)
$dt
=
new
DateTime
(
$ts
);
$newTS
=
$dt
->
add
(
new
DateInterval
(
'P1Y1M8DT13H1M1S'
)
)->
format
(
'YmdHis'
);
$this
->
assertSame
(
$expected
,
$this
->
getLang
()->
sprintfDate
(
$format
,
$newTS
,
null
),
"sprintfDate('$format', '$ts'): Missing TTL (output was different at $newTS)"
);
}
}
/**
* sprintfDate should always use UTC when no zone is given.
* @dataProvider provideSprintfDateSamples
*/
public
function
testSprintfDateNoZone
(
$format
,
$ts
,
$expected
,
$ignore
,
$msg
)
{
$oldTZ
=
date_default_timezone_get
();
$res
=
date_default_timezone_set
(
'Asia/Seoul'
);
if
(
!
$res
)
{
$this
->
markTestSkipped
(
"Error setting Timezone"
);
}
$this
->
assertEquals
(
$expected
,
$this
->
getLang
()->
sprintfDate
(
$format
,
$ts
),
"sprintfDate('$format', '$ts'): $msg"
);
date_default_timezone_set
(
$oldTZ
);
}
/**
* sprintfDate should use passed timezone
* @dataProvider provideSprintfDateSamples
*/
public
function
testSprintfDateTZ
(
$format
,
$ts
,
$ignore
,
$expected
,
$msg
)
{
$tz
=
new
DateTimeZone
(
'Asia/Seoul'
);
if
(
!
$tz
)
{
$this
->
markTestSkipped
(
"Error getting Timezone"
);
}
$this
->
assertEquals
(
$expected
,
$this
->
getLang
()->
sprintfDate
(
$format
,
$ts
,
$tz
),
"sprintfDate('$format', '$ts', 'Asia/Seoul'): $msg"
);
}
/**
* sprintfDate should only calculate a TTL if the caller is going to use it.
*/
public
function
testSprintfDateNoTtlIfNotNeeded
()
{
$noTtl
=
'unused'
;
// Value used to represent that the caller didn't pass a variable in.
$ttl
=
null
;
$this
->
getLang
()->
sprintfDate
(
'YmdHis'
,
wfTimestampNow
(),
null
,
$noTtl
);
$this
->
getLang
()->
sprintfDate
(
'YmdHis'
,
wfTimestampNow
(),
null
,
$ttl
);
$this
->
assertSame
(
'unused'
,
$noTtl
,
'If the caller does not set the $ttl variable, do not compute it.'
);
$this
->
assertIsInt
(
$ttl
,
'TTL should have been computed.'
);
}
public
static
function
provideSprintfDateSamples
()
{
return
[
[
'xiY'
,
'20111212000000'
,
'1390'
,
// note because we're testing English locale we get Latin-standard digits
'1390'
,
'Iranian calendar full year'
],
[
'xiy'
,
'20111212000000'
,
'90'
,
'90'
,
'Iranian calendar short year'
],
[
'o'
,
'20120101235000'
,
'2011'
,
'2011'
,
'ISO 8601 (week) year'
],
[
'W'
,
'20120101235000'
,
'52'
,
'52'
,
'Week number'
],
[
'W'
,
'20120102235000'
,
'01'
,
'01'
,
'Week number'
],
[
'o-
\\
WW-N'
,
'20091231235000'
,
'2009-W53-4'
,
'2009-W53-4'
,
'leap week'
],
// What follows is mostly copied from
// https://www.mediawiki.org/wiki/Help:Extension:ParserFunctions#.23time
[
'Y'
,
'20120102090705'
,
'2012'
,
'2012'
,
'Full year'
],
[
'y'
,
'20120102090705'
,
'12'
,
'12'
,
'2 digit year'
],
[
'L'
,
'20120102090705'
,
'1'
,
'1'
,
'Leap year'
],
[
'n'
,
'20120102090705'
,
'1'
,
'1'
,
'Month index, not zero pad'
],
[
'N'
,
'20120102090705'
,
'1'
,
'1'
,
'Day of the week'
],
[
'M'
,
'20120102090705'
,
'Jan'
,
'Jan'
,
'Month abbrev'
],
[
'F'
,
'20120102090705'
,
'January'
,
'January'
,
'Full month'
],
[
'xg'
,
'20120102090705'
,
'January'
,
'January'
,
'Genitive month name (same in EN)'
],
[
'j'
,
'20120102090705'
,
'2'
,
'2'
,
'Day of month (not zero pad)'
],
[
'd'
,
'20120102090705'
,
'02'
,
'02'
,
'Day of month (zero-pad)'
],
[
'z'
,
'20120102090705'
,
'1'
,
'1'
,
'Day of year (zero-indexed)'
],
[
'D'
,
'20120102090705'
,
'Mon'
,
'Mon'
,
'Day of week (abbrev)'
],
[
'l'
,
'20120102090705'
,
'Monday'
,
'Monday'
,
'Full day of week'
],
[
'N'
,
'20120101090705'
,
'7'
,
'7'
,
'Day of week (Mon=1, Sun=7)'
],
[
'w'
,
'20120101090705'
,
'0'
,
'0'
,
'Day of week (Sun=0, Sat=6)'
],
[
'N'
,
'20120102090705'
,
'1'
,
'1'
,
'Day of week'
],
[
'a'
,
'20120102090705'
,
'am'
,
'am'
,
'am vs pm'
],
[
'A'
,
'20120102120000'
,
'PM'
,
'PM'
,
'AM vs PM'
],
[
'a'
,
'20120102000000'
,
'am'
,
'am'
,
'AM vs PM'
],
[
'g'
,
'20120102090705'
,
'9'
,
'9'
,
'12 hour, not Zero'
],
[
'h'
,
'20120102090705'
,
'09'
,
'09'
,
'12 hour, zero padded'
],
[
'G'
,
'20120102090705'
,
'9'
,
'9'
,
'24 hour, not zero'
],
[
'H'
,
'20120102090705'
,
'09'
,
'09'
,
'24 hour, zero'
],
[
'H'
,
'20120102110705'
,
'11'
,
'11'
,
'24 hour, zero'
],
[
'i'
,
'20120102090705'
,
'07'
,
'07'
,
'Minutes'
],
[
's'
,
'20120102090705'
,
'05'
,
'05'
,
'seconds'
],
[
'U'
,
'20120102090705'
,
'1325495225'
,
'1325462825'
,
'unix time'
],
[
't'
,
'20120102090705'
,
'31'
,
'31'
,
'Days in current month'
],
[
'c'
,
'20120102090705'
,
'2012-01-02T09:07:05+00:00'
,
'2012-01-02T09:07:05+09:00'
,
'ISO 8601 timestamp'
],
[
'r'
,
'20120102090705'
,
'Mon, 02 Jan 2012 09:07:05 +0000'
,
'Mon, 02 Jan 2012 09:07:05 +0900'
,
'RFC 5322'
],
[
'e'
,
'20120102090705'
,
'UTC'
,
'Asia/Seoul'
,
'Timezone identifier'
],
[
'I'
,
'19880602090705'
,
'0'
,
'1'
,
'DST indicator'
],
[
'O'
,
'20120102090705'
,
'+0000'
,
'+0900'
,
'Timezone offset'
],
[
'P'
,
'20120102090705'
,
'+00:00'
,
'+09:00'
,
'Timezone offset with colon'
],
[
'T'
,
'20120102090705'
,
'UTC'
,
'KST'
,
'Timezone abbreviation'
],
[
'Z'
,
'20120102090705'
,
'0'
,
'32400'
,
'Timezone offset in seconds'
],
[
'xmj xmF xmn xmY'
,
'20120102090705'
,
'7 Safar 2 1433'
,
'7 Safar 2 1433'
,
'Islamic'
],
[
'xij xiF xin xiY'
,
'20120102090705'
,
'12 Dey 10 1390'
,
'12 Dey 10 1390'
,
'Iranian'
],
[
'xjj xjF xjn xjY'
,
'20120102090705'
,
'7 Tevet 4 5772'
,
'7 Tevet 4 5772'
,
'Hebrew'
],
[
'xjt'
,
'20120102090705'
,
'29'
,
'29'
,
'Hebrew number of days in month'
],
[
'xjx'
,
'20120102090705'
,
'Tevet'
,
'Tevet'
,
'Hebrew genitive month name (No difference in EN)'
],
[
'xkY'
,
'20120102090705'
,
'2555'
,
'2555'
,
'Thai year'
],
[
'xkY'
,
'19410101090705'
,
'2484'
,
'2484'
,
'Thai year'
],
[
'xoY'
,
'20120102090705'
,
'101'
,
'101'
,
'Minguo'
],
[
'xtY'
,
'18660101000000'
,
'西暦1866'
,
'西暦1866'
,
'nengo - before meiji'
],
[
'xtY'
,
'18670101000000'
,
'西暦1867'
,
'西暦1867'
,
'nengo - before meiji'
],
[
'xtY'
,
'18721231235959'
,
'西暦1872'
,
'西暦1872'
,
'nengo - meiji, but Lunisolar calendar'
],
[
'xtY'
,
'18730101000000'
,
'明治6'
,
'明治6'
,
'nengo - meiji 6th'
],
[
'xtY'
,
'19120729235959'
,
'明治45'
,
'明治45'
,
'nengo - meiji 45th last day'
],
[
'xtY'
,
'19120730000000'
,
'大正元'
,
'大正元'
,
'nengo - taisho first day'
],
[
'xtY'
,
'19130101000000'
,
'大正2'
,
'大正2'
,
'nengo - taisho 2nd'
],
[
'xtY'
,
'19261224235959'
,
'大正15'
,
'大正15'
,
'nengo - taisho last day'
],
[
'xtY'
,
'19261225000000'
,
'昭和元'
,
'昭和元'
,
'nengo - first day of Showa'
],
[
'xtY'
,
'19270101000000'
,
'昭和2'
,
'昭和2'
,
'nengo - second year of Showa'
],
[
'xtY'
,
'19890107235959'
,
'昭和64'
,
'昭和64'
,
'nengo - last day of Showa'
],
[
'xtY'
,
'19890108000000'
,
'平成元'
,
'平成元'
,
'nengo - first day of Heisei'
],
[
'xtY'
,
'19900101000000'
,
'平成2'
,
'平成2'
,
'nengo - second year of Heisei'
],
[
'xtY'
,
'20190430235959'
,
'平成31'
,
'平成31'
,
'nengo - last day of Heisei'
],
[
'xtY'
,
'20190501000000'
,
'令和元'
,
'令和元'
,
'nengo - first day of Reiwa'
],
[
'xtY'
,
'20200501000000'
,
'令和2'
,
'令和2'
,
'nengo - second year of Reiwa'
],
[
'xrxkYY'
,
'20120102090705'
,
'MMDLV2012'
,
'MMDLV2012'
,
'Roman numerals'
],
[
'xhxjYY'
,
'20120102090705'
,
'ה
\'
תשע"ב2012'
,
'ה
\'
תשע"ב2012'
,
'Hebrew numberals'
],
[
'xnY'
,
'20120102090705'
,
'2012'
,
'2012'
,
'Raw numerals (doesn
\'
t mean much in EN)'
],
[
'[[Y "(yea"
\\
r)]]
\\
"xx
\\
"'
,
'20120102090705'
,
'[[2012 (year)]] "x"'
,
'[[2012 (year)]] "x"'
,
'Various escaping'
],
];
}
/**
* @dataProvider provideFormatSizes
*/
public
function
testFormatSize
(
$size
,
$expected
,
$msg
)
{
$this
->
assertEquals
(
$expected
,
$this
->
getLang
()->
formatSize
(
$size
),
"formatSize('$size'): $msg"
);
}
public
static
function
provideFormatSizes
()
{
return
[
[
0
,
"0 bytes"
,
"Zero bytes"
],
[
1024
,
"1 KB"
,
"1 kilobyte"
],
[
1024
*
1024
,
"1 MB"
,
"1 megabyte"
],
[
1024
*
1024
*
1024
,
"1 GB"
,
"1 gigabyte"
],
[
1024
**
4
,
"1 TB"
,
"1 terabyte"
],
[
1024
**
5
,
"1 PB"
,
"1 petabyte"
],
[
1024
**
6
,
"1 EB"
,
"1 exabyte"
],
[
1024
**
7
,
"1 ZB"
,
"1 zettabyte"
],
[
1024
**
8
,
"1 YB"
,
"1 yottabyte"
],
[
1024
**
9
,
"1 RB"
,
"1 ronnabyte"
],
[
1024
**
10
,
"1 QB"
,
"1 quettabyte"
],
[
1024
**
11
,
"1,024 QB"
,
"1,024 quettabytes"
],
// How big!? THIS BIG!
];
}
/**
* @dataProvider provideFormatBitrate
*/
public
function
testFormatBitrate
(
$bps
,
$expected
,
$msg
)
{
$this
->
assertEquals
(
$expected
,
$this
->
getLang
()->
formatBitrate
(
$bps
),
"formatBitrate('$bps'): $msg"
);
}
public
static
function
provideFormatBitrate
()
{
return
[
[
0
,
"0 bps"
,
"0 bits per second"
],
[
999
,
"999 bps"
,
"999 bits per second"
],
[
1000
,
"1 kbps"
,
"1 kilobit per second"
],
[
1000
*
1000
,
"1 Mbps"
,
"1 megabit per second"
],
[
10
**
9
,
"1 Gbps"
,
"1 gigabit per second"
],
[
10
**
12
,
"1 Tbps"
,
"1 terabit per second"
],
[
10
**
15
,
"1 Pbps"
,
"1 petabit per second"
],
[
10
**
18
,
"1 Ebps"
,
"1 exabit per second"
],
[
10
**
21
,
"1 Zbps"
,
"1 zettabit per second"
],
[
10
**
24
,
"1 Ybps"
,
"1 yottabit per second"
],
[
10
**
27
,
"1 Rbps"
,
"1 ronnabits per second"
],
[
10
**
30
,
"1 Qbps"
,
"1 quettabit per second"
],
[
10
**
33
,
"1,000 Qbps"
,
"1,000 quettabits per second"
],
];
}
/**
* @dataProvider provideFormatDuration
*/
public
function
testFormatDuration
(
$duration
,
$expected
,
$intervals
=
[]
)
{
$this
->
assertEquals
(
$expected
,
$this
->
getLang
()->
formatDuration
(
$duration
,
$intervals
),
"formatDuration('$duration'): $expected"
);
}
public
static
function
provideFormatDuration
()
{
return
[
[
0
,
'0 seconds'
,
],
[
1
,
'1 second'
,
],
[
2
,
'2 seconds'
,
],
[
60
,
'1 minute'
,
],
[
2
*
60
,
'2 minutes'
,
],
[
3600
,
'1 hour'
,
],
[
2
*
3600
,
'2 hours'
,
],
[
24
*
3600
,
'1 day'
,
],
[
2
*
86400
,
'2 days'
,
],
[
365.2425
*
24
*
3600
/
12
,
'1 month'
,
[
'months'
,
'days'
]
],
[
365.2425
*
24
*
3600
/
12
*
2
,
'2 months'
,
[
'months'
,
'days'
]
],
[
(
365.2425
*
24
*
3600
/
12
*
2
)
+
24
*
3600
,
'2 months and 1 day'
,
[
'months'
,
'days'
]
],
[
// ( 365 + ( 24 * 3 + 25 ) / 400 ) * 86400 = 31556952
(
365
+
(
24
*
3
+
25
)
/
400.0
)
*
86400
,
'1 year'
,
[
'months'
,
'years'
]
],
[
2
*
31556952
,
'2 years'
,
],
[
10
*
31556952
,
'1 decade'
,
],
[
20
*
31556952
,
'2 decades'
,
],
[
100
*
31556952
,
'1 century'
,
],
[
200
*
31556952
,
'2 centuries'
,
],
[
1000
*
31556952
,
'1 millennium'
,
],
[
2000
*
31556952
,
'2 millennia'
,
],
[
9001
,
'2 hours, 30 minutes and 1 second'
],
[
3601
,
'1 hour and 1 second'
],
[
31556952
+
2
*
86400
+
9000
,
'1 year, 2 days, 2 hours and 30 minutes'
],
[
42
*
1000
*
31556952
+
42
,
'42 millennia and 42 seconds'
],
[
60
,
'60 seconds'
,
[
'seconds'
],
],
[
61
,
'61 seconds'
,
[
'seconds'
],
],
[
1
,
'1 second'
,
[
'seconds'
],
],
[
31556952
+
2
*
86400
+
9000
,
'1 year, 2 days and 150 minutes'
,
[
'years'
,
'days'
,
'minutes'
],
],
[
42
,
'0 days'
,
[
'years'
,
'days'
],
],
[
31556952
+
2
*
86400
+
9000
,
'1 year, 2 days and 150 minutes'
,
[
'minutes'
,
'days'
,
'years'
],
],
[
42
,
'0 days'
,
[
'days'
,
'years'
],
],
[
(
new
DateTime
(
'2025-05-03 20:00:00'
)
)->
getTimestamp
()
-
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
'11 months'
,
[
'months'
],
],
[
(
new
DateTime
(
'2025-05-03 20:00:00'
)
)->
getTimestamp
()
-
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
'11 months, 30 days, 4 hours, 39 minutes and 54 seconds'
,
[
'years'
,
'months'
,
'days'
,
'hours'
,
'minutes'
,
'seconds'
],
],
];
}
/**
* @dataProvider provideFormatDurationBetweenTimestamps
*/
public
function
testFormatDurationBetweenTimestamps
(
int
$timestamp1
,
int
$timestamp2
,
?
int
$precision
,
string
$expected
):
void
{
$this
->
assertSame
(
$expected
,
$this
->
getLang
()->
formatDurationBetweenTimestamps
(
$timestamp1
,
$timestamp2
,
$precision
)
);
$this
->
assertSame
(
$expected
,
$this
->
getLang
()->
formatDurationBetweenTimestamps
(
$timestamp2
,
$timestamp1
,
$precision
)
);
}
public
function
provideFormatDurationBetweenTimestamps
():
array
{
return
[
// most test cases ported from provideFormatDuration()
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
null
,
'0 seconds'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-05-03 20:00:01'
)
)->
getTimestamp
(),
null
,
'1 second'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-05-03 20:00:02'
)
)->
getTimestamp
(),
null
,
'2 seconds'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-05-03 20:01:00'
)
)->
getTimestamp
(),
null
,
'1 minute'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-05-03 20:02:00'
)
)->
getTimestamp
(),
null
,
'2 minutes'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-05-03 21:00:00'
)
)->
getTimestamp
(),
null
,
'1 hour'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-05-03 22:00:00'
)
)->
getTimestamp
(),
null
,
'2 hours'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-05-04 20:00:00'
)
)->
getTimestamp
(),
null
,
'1 day'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-05-05 20:00:00'
)
)->
getTimestamp
(),
null
,
'2 days'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-06-03 20:00:00'
)
)->
getTimestamp
(),
2
,
'1 month'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-07-03 20:00:00'
)
)->
getTimestamp
(),
2
,
'2 months'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-07-04 20:00:00'
)
)->
getTimestamp
(),
2
,
'2 months and 1 day'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2025-05-03 20:00:00'
)
)->
getTimestamp
(),
2
,
'1 year'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2026-05-03 20:00:00'
)
)->
getTimestamp
(),
null
,
'2 years'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2034-05-03 20:00:00'
)
)->
getTimestamp
(),
null
,
'1 decade'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2044-05-03 20:00:00'
)
)->
getTimestamp
(),
null
,
'2 decades'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2124-05-03 20:00:00'
)
)->
getTimestamp
(),
null
,
'1 century'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2224-05-03 20:00:00'
)
)->
getTimestamp
(),
null
,
'2 centuries'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'3024-05-03 20:00:00'
)
)->
getTimestamp
(),
null
,
'1 millennium'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'4024-05-03 20:00:00'
)
)->
getTimestamp
(),
null
,
'2 millennia'
,
],
[
0
,
9001
,
null
,
'2 hours, 30 minutes and 1 second'
,
],
[
0
,
3601
,
null
,
'1 hour and 1 second'
,
],
[
(
new
DateTime
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2025-05-05 22:30:00'
)
)->
getTimestamp
(),
null
,
'1 year, 2 days, 2 hours and 30 minutes'
,
],
[
(
new
DateTimeImmutable
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTimeImmutable
()
)->
setDate
(
44024
,
05
,
03
)->
setTime
(
20
,
0
,
42
)->
getTimestamp
(),
null
,
'42 millennia and 42 seconds'
,
],
[
0
,
60
,
null
,
'1 minute'
,
],
[
0
,
61
,
null
,
'1 minute and 1 second'
,
],
[
(
new
DateTimeImmutable
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTimeImmutable
()
)->
setDate
(
2025
,
05
,
05
)->
setTime
(
22
,
30
,
0
)->
getTimestamp
(),
null
,
'1 year, 2 days, 2 hours and 30 minutes'
,
],
[
(
new
DateTimeImmutable
(
'2024-05-03 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTimeImmutable
(
'2024-10-09 20:15:37'
)
)->
getTimestamp
(),
1
,
'5 months'
,
],
[
(
new
DateTime
(
'2022-01-01 10:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2022-01-01 12:30:00'
)
)->
getTimestamp
(),
2
,
'2 hours and 30 minutes'
,
],
[
(
new
DateTime
(
'2022-01-01 10:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2022-01-02 12:30:00'
)
)->
getTimestamp
(),
3
,
'1 day, 2 hours and 30 minutes'
,
],
[
(
new
DateTime
(
'2022-01-01 10:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2022-01-01 10:30:27'
)
)->
getTimestamp
(),
1
,
'30 minutes'
,
],
[
(
new
DateTime
(
'2024-05-03 10:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2025-05-03 10:00:00'
)
)->
getTimestamp
(),
6
,
'1 year'
,
],
[
(
new
DateTime
(
'2024-01-28 10:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-03-01 10:00:00'
)
)->
getTimestamp
(),
4
,
'1 month and 2 days'
,
],
[
(
new
DateTime
(
'2023-01-28 10:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-03-01 10:00:00'
)
)->
getTimestamp
(),
6
,
'1 month and 1 day'
,
],
[
(
new
DateTime
(
'2023-01-29 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-02-28 20:00:00'
)
)->
getTimestamp
(),
6
,
'30 days'
,
],
[
(
new
DateTime
(
'2023-01-29 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-03-01 20:00:00'
)
)->
getTimestamp
(),
6
,
'1 month'
,
],
[
(
new
DateTime
(
'2023-01-30 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-03-01 20:00:00'
)
)->
getTimestamp
(),
6
,
'30 days'
,
],
[
(
new
DateTime
(
'2023-01-31 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-03-01 20:00:00'
)
)->
getTimestamp
(),
6
,
'29 days'
,
],
[
(
new
DateTime
(
'2023-01-31 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-01-31 20:00:01'
)
)->
getTimestamp
(),
6
,
'1 second'
,
],
[
(
new
DateTime
(
'2023-01-31 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-01-31 20:00:02'
)
)->
getTimestamp
(),
6
,
'2 seconds'
,
],
[
(
new
DateTime
(
'2023-01-31 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-01-31 20:01:00'
)
)->
getTimestamp
(),
6
,
'1 minute'
,
],
[
(
new
DateTime
(
'2023-01-31 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-01-31 20:02:00'
)
)->
getTimestamp
(),
6
,
'2 minutes'
,
],
[
(
new
DateTime
(
'2023-01-31 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-01-31 21:00:00'
)
)->
getTimestamp
(),
6
,
'1 hour'
,
],
[
(
new
DateTime
(
'2023-01-31 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-01-31 22:00:00'
)
)->
getTimestamp
(),
6
,
'2 hours'
,
],
[
(
new
DateTime
(
'2023-01-31 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-02-01 20:00:00'
)
)->
getTimestamp
(),
6
,
'1 day'
,
],
[
(
new
DateTime
(
'2023-01-31 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-02-02 20:00:00'
)
)->
getTimestamp
(),
6
,
'2 days'
,
],
[
(
new
DateTime
(
'2023-03-31 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-04-31 20:00:00'
)
)->
getTimestamp
(),
6
,
'1 month'
,
],
[
(
new
DateTime
(
'2023-01-31 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2023-03-31 20:00:00'
)
)->
getTimestamp
(),
6
,
'2 months'
,
],
[
(
new
DateTime
(
'2023-01-31 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2024-01-31 20:00:00'
)
)->
getTimestamp
(),
6
,
'1 year'
,
],
[
(
new
DateTime
(
'2023-01-27 15:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'2025-04-31 20:06:00'
)
)->
getTimestamp
(),
5
,
'2 years, 3 months, 4 days, 5 hours and 6 minutes'
,
],
[
(
new
DateTime
(
'2023-01-31 15:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'3025-04-31 20:06:07'
)
)->
getTimestamp
(),
7
,
'1 millennium, 2 years, 3 months, 5 hours, 6 minutes and 7 seconds'
,
],
[
(
new
DateTime
(
'2023-01-28 20:00:00'
)
)->
getTimestamp
(),
(
new
DateTime
(
'4030-05-31 22:01:14'
)
)->
getTimestamp
(),
9
,
'2 millennia, 7 years, 4 months, 3 days, 2 hours, 1 minute and 14 seconds'
,
],
];
}
/**
* @dataProvider provideCheckTitleEncodingData
*/
public
function
testCheckTitleEncoding
(
$s
)
{
$this
->
assertEquals
(
$s
,
$this
->
getLang
()->
checkTitleEncoding
(
$s
),
"checkTitleEncoding('$s')"
);
}
public
static
function
provideCheckTitleEncodingData
()
{
return
[
[
""
],
[
"United States of America"
],
// 7bit ASCII
[
rawurldecode
(
"S%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e"
)
],
[
rawurldecode
(
"Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn"
)
],
// The following two data sets come from T38839. They fail if checkTitleEncoding uses a regexp to test for
// valid UTF-8 encoding and the pcre.recursion_limit is low (like, say, 1024). They succeed if checkTitleEncoding
// uses mb_check_encoding for its test.
[
rawurldecode
(
"Acteur%7CAlbert%20Robbins%7CAnglais%7CAnn%20Donahue%7CAnthony%20E.%20Zuiker%7CCarol%20Mendelsohn%7C"
.
"Catherine%20Willows%7CDavid%20Hodges%7CDavid%20Phillips%7CGil%20Grissom%7CGreg%20Sanders%7CHodges%7C"
.
"Internet%20Movie%20Database%7CJim%20Brass%7CLady%20Heather%7C"
.
"Les%20Experts%20(s%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e)%7CLes%20Experts%20:%20Manhattan%7C"
.
"Les%20Experts%20:%20Miami%7CListe%20des%20personnages%20des%20Experts%7C"
.
"Liste%20des%20%C3%A9pisodes%20des%20Experts%7CMod%C3%A8le%20discussion:Palette%20Les%20Experts%7C"
.
"Nick%20Stokes%7CPersonnage%20de%20fiction%7CPersonnage%20fictif%7CPersonnage%20de%20fiction%7C"
.
"Personnages%20r%C3%A9currents%20dans%20Les%20Experts%7CRaymond%20Langston%7CRiley%20Adams%7C"
.
"Saison%201%20des%20Experts%7CSaison%2010%20des%20Experts%7CSaison%2011%20des%20Experts%7C"
.
"Saison%2012%20des%20Experts%7CSaison%202%20des%20Experts%7CSaison%203%20des%20Experts%7C"
.
"Saison%204%20des%20Experts%7CSaison%205%20des%20Experts%7CSaison%206%20des%20Experts%7C"
.
"Saison%207%20des%20Experts%7CSaison%208%20des%20Experts%7CSaison%209%20des%20Experts%7C"
.
"Sara%20Sidle%7CSofia%20Curtis%7CS%C3%A9rie%20t%C3%A9l%C3%A9vis%C3%A9e%7CWallace%20Langham%7C"
.
"Warrick%20Brown%7CWendy%20Simms%7C%C3%89tats-Unis"
),
],
[
rawurldecode
(
"Mod%C3%A8le%3AArrondissements%20homonymes%7CMod%C3%A8le%3ABandeau%20standard%20pour%20page%20d'homonymie%7C"
.
"Mod%C3%A8le%3ABatailles%20homonymes%7CMod%C3%A8le%3ACantons%20homonymes%7C"
.
"Mod%C3%A8le%3ACommunes%20fran%C3%A7aises%20homonymes%7CMod%C3%A8le%3AFilms%20homonymes%7C"
.
"Mod%C3%A8le%3AGouvernements%20homonymes%7CMod%C3%A8le%3AGuerres%20homonymes%7CMod%C3%A8le%3AHomonymie%7C"
.
"Mod%C3%A8le%3AHomonymie%20bateau%7CMod%C3%A8le%3AHomonymie%20d'%C3%A9tablissements%20scolaires%20ou"
.
"%20universitaires%7CMod%C3%A8le%3AHomonymie%20d'%C3%AEles%7CMod%C3%A8le%3AHomonymie%20de%20clubs%20sportifs%7C"
.
"Mod%C3%A8le%3AHomonymie%20de%20comt%C3%A9s%7CMod%C3%A8le%3AHomonymie%20de%20monument%7C"
.
"Mod%C3%A8le%3AHomonymie%20de%20nom%20romain%7CMod%C3%A8le%3AHomonymie%20de%20parti%20politique%7C"
.
"Mod%C3%A8le%3AHomonymie%20de%20route%7CMod%C3%A8le%3AHomonymie%20dynastique%7C"
.
"Mod%C3%A8le%3AHomonymie%20vid%C3%A9oludique%7CMod%C3%A8le%3AHomonymie%20%C3%A9difice%20religieux%7C"
.
"Mod%C3%A8le%3AInternationalisation%7CMod%C3%A8le%3AIsom%C3%A9rie%7CMod%C3%A8le%3AParonymie%7C"
.
"Mod%C3%A8le%3APatronyme%7CMod%C3%A8le%3APatronyme%20basque%7CMod%C3%A8le%3APatronyme%20italien%7C"
.
"Mod%C3%A8le%3APatronymie%7CMod%C3%A8le%3APersonnes%20homonymes%7CMod%C3%A8le%3ASaints%20homonymes%7C"
.
"Mod%C3%A8le%3ATitres%20homonymes%7CMod%C3%A8le%3AToponymie%7CMod%C3%A8le%3AUnit%C3%A9s%20homonymes%7C"
.
"Mod%C3%A8le%3AVilles%20homonymes%7CMod%C3%A8le%3A%C3%89difices%20religieux%20homonymes"
)
]
];
// phpcs:enable
}
/**
* @dataProvider provideRomanNumeralsData
*/
public
function
testRomanNumerals
(
$num
,
$numerals
)
{
$this
->
assertEquals
(
$numerals
,
Language
::
romanNumeral
(
$num
),
"romanNumeral('$num')"
);
}
public
static
function
provideRomanNumeralsData
()
{
return
[
[
1
,
'I'
],
[
2
,
'II'
],
[
3
,
'III'
],
[
4
,
'IV'
],
[
5
,
'V'
],
[
6
,
'VI'
],
[
7
,
'VII'
],
[
8
,
'VIII'
],
[
9
,
'IX'
],
[
10
,
'X'
],
[
20
,
'XX'
],
[
30
,
'XXX'
],
[
40
,
'XL'
],
[
49
,
'XLIX'
],
[
50
,
'L'
],
[
60
,
'LX'
],
[
70
,
'LXX'
],
[
80
,
'LXXX'
],
[
90
,
'XC'
],
[
99
,
'XCIX'
],
[
100
,
'C'
],
[
200
,
'CC'
],
[
300
,
'CCC'
],
[
400
,
'CD'
],
[
500
,
'D'
],
[
600
,
'DC'
],
[
700
,
'DCC'
],
[
800
,
'DCCC'
],
[
900
,
'CM'
],
[
999
,
'CMXCIX'
],
[
1000
,
'M'
],
[
1989
,
'MCMLXXXIX'
],
[
2000
,
'MM'
],
[
3000
,
'MMM'
],
[
4000
,
'MMMM'
],
[
5000
,
'MMMMM'
],
[
6000
,
'MMMMMM'
],
[
7000
,
'MMMMMMM'
],
[
8000
,
'MMMMMMMM'
],
[
9000
,
'MMMMMMMMM'
],
[
9999
,
'MMMMMMMMMCMXCIX'
],
[
10000
,
'MMMMMMMMMM'
],
];
}
/**
* @dataProvider provideHebrewNumeralsData
*/
public
function
testHebrewNumeral
(
$num
,
$numerals
)
{
$this
->
assertEquals
(
$numerals
,
Language
::
hebrewNumeral
(
$num
),
"hebrewNumeral('$num')"
);
}
public
static
function
provideHebrewNumeralsData
()
{
return
[
[
-
1
,
-
1
],
[
0
,
0
],
[
1
,
"א'"
],
[
2
,
"ב'"
],
[
3
,
"ג'"
],
[
4
,
"ד'"
],
[
5
,
"ה'"
],
[
6
,
"ו'"
],
[
7
,
"ז'"
],
[
8
,
"ח'"
],
[
9
,
"ט'"
],
[
10
,
"י'"
],
[
11
,
'י"א'
],
[
14
,
'י"ד'
],
[
15
,
'ט"ו'
],
[
16
,
'ט"ז'
],
[
17
,
'י"ז'
],
[
20
,
"כ'"
],
[
21
,
'כ"א'
],
[
30
,
"ל'"
],
[
40
,
"מ'"
],
[
50
,
"נ'"
],
[
60
,
"ס'"
],
[
70
,
"ע'"
],
[
80
,
"פ'"
],
[
90
,
"צ'"
],
[
99
,
'צ"ט'
],
[
100
,
"ק'"
],
[
101
,
'ק"א'
],
[
110
,
'ק"י'
],
[
200
,
"ר'"
],
[
300
,
"ש'"
],
[
400
,
"ת'"
],
[
500
,
'ת"ק'
],
[
800
,
'ת"ת'
],
[
1000
,
"א' אלף"
],
[
1001
,
"א'א'"
],
[
1012
,
"א'י
\"
ב"
],
[
1020
,
"א'ך'"
],
[
1030
,
"א'ל'"
],
[
1081
,
"א'פ
\"
א"
],
[
2000
,
"ב' אלפים"
],
[
2016
,
"ב'ט
\"
ז"
],
[
3000
,
"ג' אלפים"
],
[
4000
,
"ד' אלפים"
],
[
4904
,
"ד'תתק
\"
ד"
],
[
5000
,
"ה' אלפים"
],
[
5680
,
"ה'תר
\"
ף"
],
[
5690
,
"ה'תר
\"
ץ"
],
[
5708
,
"ה'תש
\"
ח"
],
[
5720
,
"ה'תש
\"
ך"
],
[
5740
,
"ה'תש
\"
ם"
],
[
5750
,
"ה'תש
\"
ן"
],
[
5775
,
"ה'תשע
\"
ה"
],
];
}
/**
* @dataProvider providePluralData
*/
public
function
testConvertPlural
(
$expected
,
$number
,
$forms
)
{
$chosen
=
$this
->
getLang
()->
convertPlural
(
$number
,
$forms
);
$this
->
assertEquals
(
$expected
,
$chosen
);
}
public
static
function
providePluralData
()
{
// Params are: [expected text, number given, [the plural forms]]
return
[
[
'plural'
,
0
,
[
'singular'
,
'plural'
]
],
[
'explicit zero'
,
0
,
[
'0=explicit zero'
,
'singular'
,
'plural'
]
],
[
'explicit one'
,
1
,
[
'singular'
,
'plural'
,
'1=explicit one'
,
]
],
[
'singular'
,
1
,
[
'singular'
,
'plural'
,
'0=explicit zero'
,
]
],
[
'plural'
,
3
,
[
'0=explicit zero'
,
'1=explicit one'
,
'singular'
,
'plural'
]
],
[
'explicit eleven'
,
11
,
[
'singular'
,
'plural'
,
'11=explicit eleven'
,
]
],
[
'plural'
,
12
,
[
'singular'
,
'plural'
,
'11=explicit twelve'
,
]
],
[
'plural'
,
12
,
[
'singular'
,
'plural'
,
'=explicit form'
,
]
],
[
'other'
,
2
,
[
'kissa=kala'
,
'1=2=3'
,
'other'
,
]
],
[
''
,
2
,
[
'0=explicit zero'
,
'1=explicit one'
,
]
],
];
}
public
function
testEmbedBidi
()
{
$lre
=
"
\u
{202A}"
;
// U+202A LEFT-TO-RIGHT EMBEDDING
$rle
=
"
\u
{202B}"
;
// U+202B RIGHT-TO-LEFT EMBEDDING
$pdf
=
"
\u
{202C}"
;
// U+202C POP DIRECTIONAL FORMATTING
$lang
=
$this
->
getLang
();
$this
->
assertSame
(
'123'
,
$lang
->
embedBidi
(
'123'
),
'embedBidi with neutral argument'
);
$this
->
assertEquals
(
$lre
.
'Ben_(WMF)'
.
$pdf
,
$lang
->
embedBidi
(
'Ben_(WMF)'
),
'embedBidi with LTR argument'
);
$this
->
assertEquals
(
$rle
.
'יהודי (מנוחין)'
.
$pdf
,
$lang
->
embedBidi
(
'יהודי (מנוחין)'
),
'embedBidi with RTL argument'
);
}
/**
* @dataProvider provideTranslateBlockExpiry
*/
public
function
testTranslateBlockExpiry
(
$expectedData
,
$str
,
$now
,
$desc
)
{
$lang
=
$this
->
getLang
();
if
(
is_array
(
$expectedData
)
)
{
$func
=
array_shift
(
$expectedData
);
$expected
=
$lang
->
$func
(
...
$expectedData
);
}
else
{
$expected
=
$expectedData
;
}
// HACK:
date_default_timezone_set
(
'UTC'
);
$this
->
assertSame
(
$expected
,
$lang
->
translateBlockExpiry
(
$str
,
null
,
$now
),
$desc
);
}
public
static
function
provideTranslateBlockExpiry
()
{
return
[
[
'2 hours'
,
'2 hours'
,
0
,
'simple data from ipboptions'
],
[
'indefinite'
,
'infinite'
,
0
,
'infinite from ipboptions'
],
[
'indefinite'
,
'infinity'
,
0
,
'alternative infinite from ipboptions'
],
[
'indefinite'
,
'indefinite'
,
0
,
'another alternative infinite from ipboptions'
],
[
[
'formatDurationBetweenTimestamps'
,
0
,
1023
*
60
*
60
],
'1023 hours'
,
0
,
'relative'
],
[
[
'formatDurationBetweenTimestamps'
,
0
,
-
1023
],
'-1023 seconds'
,
0
,
'negative relative'
],
[
[
'formatDurationBetweenTimestamps'
,
665553906
,
665553906
+
(
1023
*
60
*
60
)
],
'1023 hours'
,
wfTimestamp
(
TS_UNIX
,
'1991-02-03 04:05:06'
),
'relative with initial timestamp'
],
[
[
'formatDurationBetweenTimestamps'
,
0
,
0
],
'now'
,
0
,
'now'
],
[
[
'timeanddate'
,
'20120102070000'
],
'2012-1-1 7:00 +1 day'
,
0
,
'mixed, handled as absolute'
],
[
[
'timeanddate'
,
'19910203040506'
],
'1991-2-3 4:05:06'
,
0
,
'absolute'
],
[
[
'timeanddate'
,
'19700101000000'
],
'1970-1-1 0:00:00'
,
0
,
'absolute at epoch'
],
[
[
'timeanddate'
,
'19691231235959'
],
'1969-12-31 23:59:59'
,
0
,
'time before epoch'
],
[
[
'timeanddate'
,
'19910910000000'
],
'10 september'
,
wfTimestamp
(
TS_UNIX
,
'19910203040506'
),
'partial'
],
[
'dummy'
,
'dummy'
,
0
,
'return garbage as is'
],
];
}
/**
* @dataProvider provideFormatNum
*/
public
function
testFormatNum
(
$translateNumerals
,
$langCode
,
$number
,
$noSeparators
,
$expected
)
{
$this
->
hideDeprecated
(
'Language::formatNum with a non-numeric string'
);
$this
->
overrideConfigValue
(
MainConfigNames
::
TranslateNumerals
,
$translateNumerals
);
$lang
=
$this
->
getServiceContainer
()->
getLanguageFactory
()->
getLanguage
(
$langCode
);
if
(
$noSeparators
)
{
$formattedNum
=
$lang
->
formatNumNoSeparators
(
$number
);
}
else
{
$formattedNum
=
$lang
->
formatNum
(
$number
);
}
$this
->
assertIsString
(
$formattedNum
);
$this
->
assertEquals
(
$expected
,
$formattedNum
);
}
public
static
function
provideFormatNum
()
{
return
[
[
true
,
'en'
,
100
,
false
,
'100'
],
[
true
,
'en'
,
101
,
true
,
'101'
],
[
false
,
'en'
,
103
,
false
,
'103'
],
[
false
,
'en'
,
104
,
true
,
'104'
],
[
true
,
'en'
,
'105'
,
false
,
'105'
],
[
true
,
'en'
,
'106'
,
true
,
'106'
],
[
false
,
'en'
,
'107'
,
false
,
'107'
],
[
false
,
'en'
,
'108'
,
true
,
'108'
],
[
true
,
'en'
,
-
1
,
false
,
'−1'
],
[
true
,
'en'
,
10
,
false
,
'10'
],
[
true
,
'en'
,
100
,
false
,
'100'
],
[
true
,
'en'
,
1000
,
false
,
'1,000'
],
[
true
,
'en'
,
10000
,
false
,
'10,000'
],
[
true
,
'en'
,
100000
,
false
,
'100,000'
],
[
true
,
'en'
,
1000000
,
false
,
'1,000,000'
],
[
true
,
'en'
,
-
1.001
,
false
,
'−1.001'
],
[
true
,
'en'
,
1.001
,
false
,
'1.001'
],
[
true
,
'en'
,
10.0001
,
false
,
'10.0001'
],
[
true
,
'en'
,
100.001
,
false
,
'100.001'
],
[
true
,
'en'
,
1000.001
,
false
,
'1,000.001'
],
[
true
,
'en'
,
10000.001
,
false
,
'10,000.001'
],
[
true
,
'en'
,
100000.001
,
false
,
'100,000.001'
],
[
true
,
'en'
,
1000000.0001
,
false
,
'1,000,000.0001'
],
[
true
,
'en'
,
-
1.0001
,
false
,
'−1.0001'
],
[
true
,
'en'
,
'200000000000000000000'
,
false
,
'200,000,000,000,000,000,000'
],
[
true
,
'en'
,
'-200000000000000000000'
,
false
,
'−200,000,000,000,000,000,000'
],
[
true
,
'en'
,
'1.23e10'
,
false
,
'12,300,000,000'
],
[
true
,
'en'
,
1.23e10
,
false
,
'12,300,000,000'
],
[
true
,
'en'
,
'1.23E-01'
,
false
,
'0.123'
],
[
true
,
'en'
,
1.23e-1
,
false
,
'0.123'
],
[
true
,
'en'
,
0.0
,
false
,
'0'
],
[
true
,
'en'
,
-
0.0
,
false
,
'−0'
],
[
true
,
'en'
,
INF
,
false
,
'∞'
],
[
true
,
'en'
,
-
INF
,
false
,
'−∞'
],
[
true
,
'en'
,
NAN
,
false
,
'Not a Number'
],
[
true
,
'kn'
,
'1050'
,
false
,
'೧,೦೫೦'
],
[
true
,
'kn'
,
'1060'
,
true
,
'೧೦೬೦'
],
[
false
,
'kn'
,
'1070'
,
false
,
'1,070'
],
[
false
,
'kn'
,
'1080'
,
true
,
'1080'
],
[
true
,
'kn'
,
'.1090'
,
false
,
'.೧೦೯೦'
],
// Make sure non-numeric strings are not destroyed
[
false
,
'en'
,
'The number is 1234'
,
false
,
'The number is 1,234'
],
[
false
,
'en'
,
'1234 is the number'
,
false
,
'1,234 is the number'
],
[
false
,
'de'
,
'.'
,
false
,
'.'
],
[
false
,
'de'
,
','
,
false
,
','
],
/** @see https://phabricator.wikimedia.org/T237467 */
[
false
,
'kn'
,
"೭
\u
{FFFD}0"
,
false
,
"೭
\u
{FFFD}0"
],
[
false
,
'kn'
,
"-೭
\u
{FFFD}0"
,
false
,
"-೭
\u
{FFFD}0"
],
[
false
,
'kn'
,
"-1೭
\u
{FFFD}0"
,
false
,
"−1೭
\u
{FFFD}0"
],
/** @see https://phabricator.wikimedia.org/T267614 */
[
false
,
'ar'
,
"1"
,
false
,
"1"
],
[
false
,
'ar'
,
"1234.5"
,
false
,
"1٬234٫5"
],
[
true
,
'ar'
,
"1"
,
false
,
"١"
],
[
true
,
'ar'
,
"1234.5"
,
false
,
"١٬٢٣٤٫٥"
],
// Test minimumGroupingDigits > 1
[
false
,
'pl'
,
1
,
false
,
'1'
],
[
false
,
'pl'
,
100
,
false
,
'100'
],
[
false
,
'pl'
,
1000
,
false
,
'1000'
],
[
false
,
'pl'
,
10000
,
false
,
"10
\u
{00A0}000"
],
[
false
,
'pl'
,
1000000
,
false
,
"1
\u
{00A0}000
\u
{00A0}000"
],
[
false
,
'pl'
,
'1000.1'
,
false
,
"1000,1"
],
];
}
/**
* @dataProvider parseFormattedNumberProvider
*/
public
function
testParseFormattedNumber
(
$langCode
,
$number
)
{
$lang
=
$this
->
getServiceContainer
()->
getLanguageFactory
()->
getLanguage
(
$langCode
);
$localisedNum
=
$lang
->
formatNum
(
$number
);
$normalisedNum
=
$lang
->
parseFormattedNumber
(
$localisedNum
);
$this
->
assertEquals
(
$number
,
$normalisedNum
);
}
public
static
function
parseFormattedNumberProvider
()
{
return
[
[
'de'
,
377.01
],
[
'fa'
,
334
],
[
'fa'
,
382.772
],
[
'ar'
,
1844
],
[
'lzh'
,
3731
],
[
'zh-classical'
,
7432
],
[
'en'
,
1234.567
],
[
'en'
,
0.0
],
[
'en'
,
-
0.0
],
[
'en'
,
INF
],
[
'en'
,
-
INF
],
[
'en'
,
NAN
],
];
}
public
function
testListToText
()
{
$lang
=
$this
->
getLang
();
$and
=
$lang
->
getMessageFromDB
(
'and'
);
$s
=
$lang
->
getMessageFromDB
(
'word-separator'
);
$c
=
$lang
->
getMessageFromDB
(
'comma-separator'
);
$this
->
assertSame
(
''
,
$lang
->
listToText
(
[]
)
);
$this
->
assertEquals
(
'a'
,
$lang
->
listToText
(
[
'a'
]
)
);
$this
->
assertEquals
(
"a{$and}{$s}b"
,
$lang
->
listToText
(
[
'a'
,
'b'
]
)
);
$this
->
assertEquals
(
"a{$c}b{$and}{$s}c"
,
$lang
->
listToText
(
[
'a'
,
'b'
,
'c'
]
)
);
$this
->
assertEquals
(
"a{$c}b{$c}c{$and}{$s}d"
,
$lang
->
listToText
(
[
'a'
,
'b'
,
'c'
,
'd'
]
)
);
}
/**
* Example of the real localisation files being loaded.
*
* This might be a bit cumbersome to maintain long-term,
* but still valueable to have as integration test.
*/
public
function
testGetNamespaceAliasesReal
()
{
$language
=
$this
->
getServiceContainer
()->
getLanguageFactory
()->
getLanguage
(
'zh'
);
$aliases
=
$language
->
getNamespaceAliases
();
$this
->
assertSame
(
NS_FILE
,
$aliases
[
'文件'
]
);
$this
->
assertSame
(
NS_FILE
,
$aliases
[
'檔案'
]
);
}
public
function
testGetNamespaceAliasesFullLogic
()
{
$hooks
=
$this
->
createHookContainer
(
[
'Language::getMessagesFileName'
=>
static
function
(
$code
,
&
$file
)
{
$file
=
__DIR__
.
'/../../data/messages/Messages_'
.
$code
.
'.php'
;
}
]
);
$langNameUtils
=
$this
->
getDummyLanguageNameUtils
(
[
'hookContainer'
=>
$hooks
]
);
$this
->
overrideConfigValue
(
MainConfigNames
::
NamespaceAliases
,
[
'Mouse'
=>
NS_SPECIAL
,
]
);
$this
->
setService
(
'LanguageNameUtils'
,
$langNameUtils
);
$language
=
$this
->
getServiceContainer
()->
getLanguageFactory
()->
getLanguage
(
'x-bar'
);
$this
->
assertEquals
(
[
// from x-bar
'Cat'
=>
NS_FILE
,
'Cat_toots'
=>
NS_FILE_TALK
,
// inherited from x-foo
'Dog'
=>
NS_USER
,
'Dog_woofs'
=>
NS_USER_TALK
,
// add from site configuration
'Mouse'
=>
NS_SPECIAL
,
],
$language
->
getNamespaceAliases
()
);
}
public
function
testEquals
()
{
$languageFactory
=
$this
->
getServiceContainer
()->
getLanguageFactory
();
$en1
=
$languageFactory
->
getLanguage
(
'en'
);
$en2
=
$languageFactory
->
getLanguage
(
'en'
);
$en3
=
$this
->
newLanguage
();
$this
->
assertTrue
(
$en1
->
equals
(
$en2
),
'en1 equals en2'
);
$this
->
assertTrue
(
$en2
->
equals
(
$en3
),
'en2 equals en3'
);
$this
->
assertTrue
(
$en3
->
equals
(
$en1
),
'en3 equals en1'
);
$fr
=
$languageFactory
->
getLanguage
(
'fr'
);
$this
->
assertFalse
(
$en1
->
equals
(
$fr
),
'en not equals fr'
);
$ar1
=
$languageFactory
->
getLanguage
(
'ar'
);
$ar2
=
$this
->
newLanguage
(
LanguageAr
::
class
,
'ar'
);
$this
->
assertTrue
(
$ar1
->
equals
(
$ar2
),
'ar equals ar'
);
}
/**
* @dataProvider provideUcfirst
*/
public
function
testUcfirst
(
$orig
,
$expected
,
$desc
,
$overrides
=
false
)
{
$lang
=
$this
->
newLanguage
();
if
(
is_array
(
$overrides
)
)
{
$this
->
overrideConfigValue
(
MainConfigNames
::
OverrideUcfirstCharacters
,
$overrides
);
}
$this
->
assertSame
(
$expected
,
$lang
->
ucfirst
(
$orig
),
$desc
);
}
public
static
function
provideUcfirst
()
{
return
[
[
'alice'
,
'Alice'
,
'simple ASCII string'
,
false
],
[
'århus'
,
'Århus'
,
'unicode string'
,
false
],
// overrides do not affect ASCII characters
[
'foo'
,
'Foo'
,
'ASCII is not overridden'
,
[
'f'
=>
'b'
]
],
// but they do affect non-ascii ones
[
'èl'
,
'Ll'
,
'Non-ASCII is overridden'
,
[
'è'
=>
'L'
]
],
[
'ვიკიპედია'
,
'ვიკიპედია'
,
'Georgian case is preserved'
,
false
],
];
}
// The following methods are for LanguageNameUtilsTestTrait
private
function
isSupportedLanguage
(
$code
)
{
return
$this
->
getServiceContainer
()->
getLanguageNameUtils
()->
isSupportedLanguage
(
$code
);
}
private
function
isValidCode
(
$code
)
{
return
$this
->
getServiceContainer
()->
getLanguageNameUtils
()->
isValidCode
(
$code
);
}
private
function
isValidBuiltInCode
(
$code
)
{
return
$this
->
getServiceContainer
()->
getLanguageNameUtils
()->
isValidBuiltInCode
(
$code
);
}
private
function
isKnownLanguageTag
(
$code
)
{
return
$this
->
getServiceContainer
()->
getLanguageNameUtils
()->
isKnownLanguageTag
(
$code
);
}
protected
function
setLanguageTemporaryHook
(
string
$hookName
,
$handler
):
void
{
$this
->
setTemporaryHook
(
$hookName
,
$handler
);
}
protected
function
clearLanguageHook
(
string
$hookName
):
void
{
$this
->
clearHook
(
$hookName
);
}
/**
* Call getLanguageName() and getLanguageNames() using the Language static methods.
*
* @param array $options To set globals for testing Language
* @param string $expected
* @param string $code
* @param mixed ...$otherArgs Optionally, pass $inLanguage and/or $include.
*/
private
function
assertGetLanguageNames
(
array
$options
,
$expected
,
$code
,
...
$otherArgs
)
{
if
(
$options
)
{
$this
->
overrideConfigValues
(
$options
);
}
$langNameUtils
=
$this
->
getServiceContainer
()->
getLanguageNameUtils
();
$this
->
assertSame
(
$expected
,
$langNameUtils
->
getLanguageNames
(
...
$otherArgs
)[
strtolower
(
$code
)]
??
''
);
$this
->
assertSame
(
$expected
,
$langNameUtils
->
getLanguageName
(
$code
,
...
$otherArgs
)
);
}
private
function
getLanguageNames
(
...
$args
)
{
return
$this
->
getServiceContainer
()->
getLanguageNameUtils
()->
getLanguageNames
(
...
$args
);
}
private
function
getLanguageName
(
...
$args
)
{
return
$this
->
getServiceContainer
()->
getLanguageNameUtils
()->
getLanguageName
(
...
$args
);
}
private
function
getFileName
(
...
$args
)
{
return
MediaWikiServices
::
getInstance
()->
getLanguageNameUtils
()->
getFileName
(
...
$args
);
}
private
function
getMessagesFileName
(
$code
)
{
return
MediaWikiServices
::
getInstance
()->
getLanguageNameUtils
()->
getMessagesFileName
(
$code
);
}
private
function
getJsonMessagesFileName
(
$code
)
{
return
MediaWikiServices
::
getInstance
()->
getLanguageNameUtils
()->
getJsonMessagesFileName
(
$code
);
}
/**
* @todo This really belongs in the cldr extension's tests.
*/
public
function
testCldr
()
{
$this
->
markTestSkippedIfExtensionNotLoaded
(
'CLDR'
);
$languageNameUtils
=
$this
->
getServiceContainer
()->
getLanguageNameUtils
();
// "pal" is an ancient language, which probably will not appear in Names.php, but appears in
// CLDR in English
$this
->
assertTrue
(
$languageNameUtils
->
isKnownLanguageTag
(
'pal'
)
);
$this
->
assertSame
(
'allemand'
,
$languageNameUtils
->
getLanguageName
(
'de'
,
'fr'
)
);
}
/**
* @dataProvider provideGetNamespaces
*/
public
function
testGetNamespaces
(
string
$langCode
,
array
$config
,
array
$expected
)
{
$services
=
$this
->
getServiceContainer
();
$langClass
=
Language
::
class
.
ucfirst
(
$langCode
);
if
(
!
class_exists
(
$langClass
)
)
{
$langClass
=
Language
::
class
;
}
$config
+=
[
MainConfigNames
::
MetaNamespace
=>
'Project'
,
MainConfigNames
::
MetaNamespaceTalk
=>
false
,
MainConfigNames
::
ExtraNamespaces
=>
[],
];
$nsInfo
=
new
NamespaceInfo
(
new
ServiceOptions
(
NamespaceInfo
::
CONSTRUCTOR_OPTIONS
,
$config
,
$services
->
getMainConfig
()
),
$services
->
getHookContainer
(),
ExtensionRegistry
::
getInstance
()->
getAttribute
(
'ExtensionNamespaces'
),
ExtensionRegistry
::
getInstance
()->
getAttribute
(
'ImmovableNamespaces'
)
);
/** @var Language $lang */
$lang
=
new
$langClass
(
$langCode
,
$nsInfo
,
$services
->
getLocalisationCache
(),
$this
->
createNoOpMock
(
LanguageNameUtils
::
class
),
$this
->
createNoOpMock
(
LanguageFallback
::
class
),
$this
->
createNoOpMock
(
LanguageConverterFactory
::
class
),
$this
->
createMock
(
HookContainer
::
class
),
new
MultiConfig
(
[
new
HashConfig
(
$config
),
$services
->
getMainConfig
()
]
)
);
$namespaces
=
$lang
->
getNamespaces
();
$this
->
assertArraySubmapSame
(
$expected
,
$namespaces
);
}
public
static
function
provideGetNamespaces
()
{
$enNamespaces
=
[
NS_MEDIA
=>
'Media'
,
NS_SPECIAL
=>
'Special'
,
NS_MAIN
=>
''
,
NS_TALK
=>
'Talk'
,
NS_USER
=>
'User'
,
NS_USER_TALK
=>
'User_talk'
,
NS_FILE
=>
'File'
,
NS_FILE_TALK
=>
'File_talk'
,
NS_MEDIAWIKI
=>
'MediaWiki'
,
NS_MEDIAWIKI_TALK
=>
'MediaWiki_talk'
,
NS_TEMPLATE
=>
'Template'
,
NS_TEMPLATE_TALK
=>
'Template_talk'
,
NS_HELP
=>
'Help'
,
NS_HELP_TALK
=>
'Help_talk'
,
NS_CATEGORY
=>
'Category'
,
NS_CATEGORY_TALK
=>
'Category_talk'
,
];
$ukNamespaces
=
[
NS_MEDIA
=>
'Медіа'
,
NS_SPECIAL
=>
'Спеціальна'
,
NS_TALK
=>
'Обговорення'
,
NS_USER
=>
'Користувач'
,
NS_USER_TALK
=>
'Обговорення_користувача'
,
NS_FILE
=>
'Файл'
,
NS_FILE_TALK
=>
'Обговорення_файлу'
,
NS_MEDIAWIKI
=>
'MediaWiki'
,
NS_MEDIAWIKI_TALK
=>
'Обговорення_MediaWiki'
,
NS_TEMPLATE
=>
'Шаблон'
,
NS_TEMPLATE_TALK
=>
'Обговорення_шаблону'
,
NS_HELP
=>
'Довідка'
,
NS_HELP_TALK
=>
'Обговорення_довідки'
,
NS_CATEGORY
=>
'Категорія'
,
NS_CATEGORY_TALK
=>
'Обговорення_категорії'
,
];
return
[
'Default configuration'
=>
[
'en'
,
[],
$enNamespaces
+
[
NS_PROJECT
=>
'Project'
,
NS_PROJECT_TALK
=>
'Project_talk'
,
],
],
'Custom project NS + extra'
=>
[
'en'
,
[
MainConfigNames
::
MetaNamespace
=>
'Wikipedia'
,
MainConfigNames
::
ExtraNamespaces
=>
[
100
=>
'Borderlands'
,
101
=>
'Borderlands_talk'
,
],
],
$enNamespaces
+
[
NS_PROJECT
=>
'Wikipedia'
,
NS_PROJECT_TALK
=>
'Wikipedia_talk'
,
100
=>
'Borderlands'
,
101
=>
'Borderlands_talk'
,
],
],
'Custom project NS and talk + extra'
=>
[
'en'
,
[
MainConfigNames
::
MetaNamespace
=>
'Wikipedia'
,
MainConfigNames
::
MetaNamespaceTalk
=>
'Wikipedia_drama'
,
MainConfigNames
::
ExtraNamespaces
=>
[
100
=>
'Borderlands'
,
101
=>
'Borderlands_talk'
,
],
],
$enNamespaces
+
[
NS_PROJECT
=>
'Wikipedia'
,
NS_PROJECT_TALK
=>
'Wikipedia_drama'
,
100
=>
'Borderlands'
,
101
=>
'Borderlands_talk'
,
],
],
'Ukrainian default'
=>
[
'uk'
,
[],
$ukNamespaces
+
[
NS_MAIN
=>
''
,
NS_PROJECT
=>
'Project'
,
NS_PROJECT_TALK
=>
'Обговорення_Project'
,
],
],
'Ukrainian custom NS'
=>
[
'uk'
,
[
MainConfigNames
::
MetaNamespace
=>
'Вікіпедія'
,
],
$ukNamespaces
+
[
NS_MAIN
=>
''
,
NS_PROJECT
=>
'Вікіпедія'
,
NS_PROJECT_TALK
=>
'Обговорення_Вікіпедії'
,
],
],
];
}
public
function
testGetGroupName
()
{
$lang
=
$this
->
getLang
();
$groupName
=
$lang
->
getGroupName
(
'bot'
);
$this
->
assertSame
(
'Bots'
,
$groupName
);
}
public
function
testGetGroupMemberName
()
{
$lang
=
$this
->
getLang
();
$user
=
new
UserIdentityValue
(
1
,
'user'
);
$groupMemberName
=
$lang
->
getGroupMemberName
(
'bot'
,
$user
);
$this
->
assertSame
(
'bot'
,
$groupMemberName
);
$lang
=
$this
->
getServiceContainer
()->
getLanguageFactory
()->
getLanguage
(
'qqx'
);
$groupMemberName
=
$lang
->
getGroupMemberName
(
'bot'
,
$user
);
$this
->
assertSame
(
'(group-bot-member: user)'
,
$groupMemberName
);
}
public
function
testMsg
()
{
$lang
=
TestingAccessWrapper
::
newFromObject
(
$this
->
getLang
()
);
$this
->
assertSame
(
'Line 1:'
,
$lang
->
msg
(
'lineno'
,
'1'
)->
text
()
);
}
public
function
testBlockDurations
()
{
$lang
=
$this
->
getLang
();
$durations
=
$lang
->
getBlockDurations
();
$this
->
assertContains
(
'other'
,
$durations
);
$this
->
assertContains
(
'infinite'
,
$durations
);
$this
->
assertContains
(
'1 day'
,
$durations
);
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Tue, Aug 18, 22:36 (18 h, 53 m ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
23/3d/129760dc43064a662d9fac30987b
Default Alt Text
LanguageIntegrationTest.php (60 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment