3 use MediaWiki\Context\RequestContext
;
4 use MediaWiki\Language\Language
;
5 use MediaWiki\Linker\LinkTarget
;
6 use MediaWiki\MainConfigNames
;
7 use MediaWiki\Page\PageReference
;
8 use MediaWiki\Page\PageReferenceValue
;
9 use MediaWiki\Title\Title
;
10 use MediaWiki\Title\TitleValue
;
11 use MediaWiki\User\Options\UserOptionsLookup
;
12 use MediaWiki\User\User
;
16 * @covers \MediaWiki\Language\LanguageConverter
18 class LanguageConverterTest
extends MediaWikiLangTestCase
{
23 /** @var DummyConverter */
26 private function setContextUser( User
$user ) {
27 // LanguageConverter::getPreferredVariant() reads the user from
28 // RequestContext::getMain(), so set it occordingly
29 RequestContext
::getMain()->setUser( $user );
32 protected function setUp(): void
{
34 $this->overrideConfigValues( [
35 MainConfigNames
::LanguageCode
=> 'en',
36 MainConfigNames
::DefaultLanguageVariant
=> false,
38 $this->setContentLang( 'tg' );
39 $this->setContextUser( new User
);
41 $this->lang
= $this->createNoOpMock( Language
::class, [ 'factory', 'getNsText', 'ucfirst' ] );
42 $this->lang
->method( 'getNsText' )->with( NS_MEDIAWIKI
)->willReturn( 'MediaWiki' );
43 $this->lang
->method( 'ucfirst' )->willReturnCallback( 'ucfirst' );
44 $this->lc
= new DummyConverter( $this->lang
);
47 protected function tearDown(): void
{
54 public function testGetPreferredVariantDefaults() {
55 $this->assertEquals( 'tg', $this->lc
->getPreferredVariant() );
59 * @dataProvider provideGetPreferredVariant
61 public function testGetPreferredVariant( $requestVal, $expected ) {
62 $request = RequestContext
::getMain()->getRequest();
63 $request->setVal( 'variant', $requestVal );
65 $this->assertEquals( $expected, $this->lc
->getPreferredVariant() );
68 public static function provideGetPreferredVariant() {
69 yield
'normal (tg-latn)' => [ 'tg-latn', 'tg-latn' ];
70 yield
'deprecated (bat-smg)' => [ 'bat-smg', 'sgs' ];
71 yield
'BCP47 (en-simple)' => [ 'en-simple', 'simple' ];
75 * @dataProvider provideGetPreferredVariantHeaders
77 public function testGetPreferredVariantHeaders( $headerVal, $expected ) {
78 $request = RequestContext
::getMain()->getRequest();
79 $request->setHeader( 'Accept-Language', $headerVal );
81 $this->assertEquals( $expected, $this->lc
->getPreferredVariant() );
84 public static function provideGetPreferredVariantHeaders() {
85 yield
'normal (tg-latn)' => [ 'tg-latn', 'tg-latn' ];
86 yield
'BCP47 (en-simple)' => [ 'en-simple', 'simple' ];
87 yield
'with weight #1' => [ 'tg;q=1', 'tg' ];
88 yield
'with weight #2' => [ 'tg-latn;q=1', 'tg-latn' ];
89 yield
'with multi' => [ 'en, tg-latn;q=1', 'tg-latn' ];
93 * @dataProvider provideGetPreferredVariantUserOption
95 public function testGetPreferredVariantUserOption( $optionVal, $expected, $foreignLang ) {
96 $optionName = 'variant';
98 $this->setContentLang( 'en' );
99 $optionName = 'variant-tg';
103 $user->load(); // from 'defaults'
105 $user->mDataLoaded
= true;
107 $userOptionsLookup = $this->createMock( UserOptionsLookup
::class );
108 $userOptionsLookup->method( 'getOption' )
109 ->with( $user, $optionName )
110 ->willReturn( $optionVal );
111 $this->setService( 'UserOptionsLookup', $userOptionsLookup );
113 $this->setContextUser( $user );
115 $this->assertEquals( $expected, $this->lc
->getPreferredVariant() );
118 public static function provideGetPreferredVariantUserOption() {
119 yield
'normal (tg-latn)' => [ 'tg-latn', 'tg-latn', false ];
120 yield
'deprecated (bat-smg)' => [ 'bat-smg', 'sgs', false ];
121 yield
'BCP47 (en-simple)' => [ 'en-simple', 'simple', false ];
122 yield
'for foreign language, normal (tg-latn)' => [ 'tg-latn', 'tg-latn', true ];
123 yield
'for foreign language, deprecated (bat-smg)' => [ 'bat-smg', 'sgs', true ];
124 yield
'for foreign language, BCP47 (en-simple)' => [ 'en-simple', 'simple', true ];
127 public function testGetPreferredVariantHeaderUserVsUrl() {
128 $request = RequestContext
::getMain()->getRequest();
130 $this->setContentLang( 'tg-latn' );
131 $request->setVal( 'variant', 'tg' );
133 $user = User
::newFromId( "admin" );
135 $user->mFrom
= 'defaults';
136 // The user's data is ignored because the variant is set in the URL.
137 $userOptionsLookup = $this->createMock( UserOptionsLookup
::class );
138 $userOptionsLookup->method( 'getOption' )
139 ->with( $user, 'variant' )
140 ->willReturn( 'tg-latn' );
141 $this->setService( 'UserOptionsLookup', $userOptionsLookup );
143 $this->setContextUser( $user );
145 $this->assertEquals( 'tg', $this->lc
->getPreferredVariant() );
149 * @dataProvider provideGetPreferredVariant
151 public function testGetPreferredVariantDefaultLanguageVariant( $globalVal, $expected ) {
152 $this->overrideConfigValue( MainConfigNames
::DefaultLanguageVariant
, $globalVal );
153 $this->assertEquals( $expected, $this->lc
->getPreferredVariant() );
156 public function testGetPreferredVariantDefaultLanguageVsUrlVariant() {
157 $request = RequestContext
::getMain()->getRequest();
159 $this->setContentLang( 'tg-latn' );
160 $this->overrideConfigValue( MainConfigNames
::DefaultLanguageVariant
, 'tg' );
161 $request->setVal( 'variant', null );
162 $this->assertEquals( 'tg', $this->lc
->getPreferredVariant() );
166 * Test exhausting pcre.backtrack_limit
168 public function testAutoConvertT124404() {
169 $testString = str_repeat( 'xxx xxx xxx', 1000 );
170 $testString .= "\n<big id='в'></big>";
171 $this->setIniSetting( 'pcre.backtrack_limit', 200 );
172 $result = $this->lc
->autoConvert( $testString, 'tg-latn' );
173 // The в in the id attribute should not get converted to a v
174 $this->assertStringNotContainsString(
177 "в converted to v despite being in attribue"
182 * @dataProvider provideTitlesToConvert
183 * @param LinkTarget|PageReference|callable $title title to convert
184 * @param string $expected
186 public function testConvertTitle( $title, string $expected ): void
{
187 if ( is_callable( $title ) ) {
190 $actual = $this->lc
->convertTitle( $title );
191 $this->assertSame( $expected, $actual );
194 public static function provideTitlesToConvert(): array {
196 'Title FromText default' => [
197 Title
::makeTitle( NS_MAIN
, 'Dummy_title' ),
200 'Title FromText with NS' => [
201 Title
::makeTitle( NS_FILE
, 'Dummy_title' ),
204 'Title MainPage default' => [
206 // Don't call this until services have been set up
207 return Title
::newMainPage();
211 'Title MainPage with MessageLocalizer' => [
213 // Don't call this until services have been set up
214 return Title
::newMainPage( new MockMessageLocalizer() );
219 new TitleValue( NS_FILE
, 'Dummy page' ),
223 new PageReferenceValue( NS_FILE
, 'Dummy page', PageReference
::LOCAL
),