diff options
author | Tim Starling <tstarling@wikimedia.org> | 2025-02-17 12:36:00 +1100 |
---|---|---|
committer | Tim Starling <tstarling@wikimedia.org> | 2025-02-21 12:01:38 +1100 |
commit | 1edccf294ac00b304400738a812358e6da252403 (patch) | |
tree | 0f414904640a00b0739fae9a83226c2f640f1eb3 /tests/phpunit | |
parent | c40e70a6f8368fc6785c35c739748e5e8d83a47d (diff) | |
download | mediawikicore-1edccf294ac00b304400738a812358e6da252403.tar.gz mediawikicore-1edccf294ac00b304400738a812358e6da252403.zip |
Split MessageParser out of MessageCache
MessageCache has enough to do without also being a parser. Split a
MessageParser class out of MessageCache and make it a service.
* MessageCache::parseWithPostprocessing() becomes MessageParser::parse()
because every caller wants postprocessing so it makes sense to use the
shorter name for this.
* MessageCache::parse() becomes MessageParser
::parseWithoutPostprocessing(). I changed the return type from
ParserOutput|string to ParserOutput, which is a followup to
I8a1fa84e650d920d07d74722d8059d5afeedec6b. Narrowing the return type
does not break b/c so it is possible to make this change for both
variants.
* In the new methods, a null title is always a convenience alias for a
placeholder title (Special:Badtitle). This reflects the convention in
Parser::setPage(). The old MessageCache::parse() retains its b/c
fallback to $wgTitle. MessageCache::transform() had the potential to
fall back to the title used in the previous call, a fragile mechanism
which I removed without deprecation.
* For consistency, allow a string language in all new methods.
* In EmailNotification, clean up an early attempt at global state
avoidance.
Change-Id: I05ab21508d5f8394189fd41ac6a2254ac0e0d785
Diffstat (limited to 'tests/phpunit')
8 files changed, 132 insertions, 30 deletions
diff --git a/tests/phpunit/includes/Status/StatusFormatterTest.php b/tests/phpunit/includes/Status/StatusFormatterTest.php index b16d8064b2a9..289c9c381d41 100644 --- a/tests/phpunit/includes/Status/StatusFormatterTest.php +++ b/tests/phpunit/includes/Status/StatusFormatterTest.php @@ -1,6 +1,7 @@ <?php use MediaWiki\Context\RequestContext; +use MediaWiki\Language\MessageParser; use MediaWiki\Language\RawMessage; use MediaWiki\Message\Message; use MediaWiki\Parser\ParserOutput; @@ -37,8 +38,8 @@ class StatusFormatterTest extends MediaWikiLangTestCase { } }; - $cache = $this->createNoOpMock( MessageCache::class, [ 'parseWithPostprocessing' ] ); - $cache->method( 'parseWithPostprocessing' )->willReturnCallback( + $cache = $this->createNoOpMock( MessageParser::class, [ 'parse' ] ); + $cache->method( 'parse' )->willReturnCallback( static function ( $text, ...$args ) { $text = html_entity_decode( $text, ENT_QUOTES | ENT_HTML5 ); return new ParserOutput( "<p>" . trim( $text ) . "\n</p>" ); diff --git a/tests/phpunit/includes/language/LocalizationUpdateSpyTrait.php b/tests/phpunit/includes/language/LocalizationUpdateSpyTrait.php index 0a7aaed1b054..05b3d037f2a1 100644 --- a/tests/phpunit/includes/language/LocalizationUpdateSpyTrait.php +++ b/tests/phpunit/includes/language/LocalizationUpdateSpyTrait.php @@ -41,9 +41,6 @@ trait LocalizationUpdateSpyTrait { $messageCache->method( 'get' ) ->willReturn( 'dummy test' ); - $messageCache->method( 'transform' ) - ->willReturn( 'dummy test' ); - $messageCache->method( 'getMsgFromNamespace' ) ->willReturn( false ); diff --git a/tests/phpunit/includes/language/MessageCacheTest.php b/tests/phpunit/includes/language/MessageCacheTest.php index 05278ed02d15..731915a20e8c 100644 --- a/tests/phpunit/includes/language/MessageCacheTest.php +++ b/tests/phpunit/includes/language/MessageCacheTest.php @@ -3,9 +3,7 @@ use MediaWiki\CommentStore\CommentStoreComment; use MediaWiki\Content\ContentHandler; use MediaWiki\Deferred\DeferredUpdates; -use MediaWiki\Language\RawMessage; use MediaWiki\MainConfigNames; -use MediaWiki\Page\PageIdentityValue; use MediaWiki\Revision\RevisionRecord; use MediaWiki\Revision\SlotRecord; use MediaWiki\Title\Title; @@ -332,21 +330,6 @@ class MessageCacheTest extends MediaWikiLangTestCase { ]; } - public function testNestedMessageParse() { - $msgOuter = ( new RawMessage( '[[Link|{{#language:}}]]' ) ) - ->inLanguage( 'outer' ) - ->page( new PageIdentityValue( 1, NS_MAIN, 'Link', PageIdentityValue::LOCAL ) ); - - // T372891: Allow nested message parsing - // Any hook from Linker or LinkRenderer will do for this test, but this one is the simplest - $this->setTemporaryHook( 'SelfLinkBegin', static function ( $nt, &$html, &$trail, &$prefix, &$ret ) { - $msgInner = ( new RawMessage( '{{#language:}}' ) )->inLanguage( 'inner' ); - $html .= $msgInner->escaped(); - } ); - - $this->assertEquals( '<a class="mw-selflink selflink">outerinner</a>', $msgOuter->parse() ); - } - /** @dataProvider provideXssLanguage */ public function testXssLanguage( array $config, bool $expectXssMessage ): void { $this->overrideConfigValues( $config + [ diff --git a/tests/phpunit/includes/language/MessageParserTest.php b/tests/phpunit/includes/language/MessageParserTest.php new file mode 100644 index 000000000000..eeb980598e0d --- /dev/null +++ b/tests/phpunit/includes/language/MessageParserTest.php @@ -0,0 +1,120 @@ +<?php + +use MediaWiki\DAO\WikiAwareEntity; +use MediaWiki\Language\RawMessage; +use MediaWiki\Page\PageIdentityValue; + +/** + * @covers MediaWiki\Language\MessageParser + */ +class MessageParserTest extends MediaWikiIntegrationTestCase { + + public function testNestedMessageParse() { + $msgOuter = ( new RawMessage( '[[Link|{{#language:}}]]' ) ) + ->inLanguage( 'outer' ) + ->page( new PageIdentityValue( 1, NS_MAIN, 'Link', PageIdentityValue::LOCAL ) ); + + // T372891: Allow nested message parsing + // Any hook from Linker or LinkRenderer will do for this test, but this one is the simplest + $this->setTemporaryHook( 'SelfLinkBegin', static function ( $nt, &$html, &$trail, &$prefix, &$ret ) { + $msgInner = ( new RawMessage( '{{#language:}}' ) )->inLanguage( 'inner' ); + $html .= $msgInner->escaped(); + } ); + + $this->assertEquals( '<a class="mw-selflink selflink">outerinner</a>', $msgOuter->parse() ); + } + + public static function provideTransform() { + return [ + [ + 'test', + [], + 'test' + ], + [ + '{{PLURAL:21|one|more}}', + [ 'lang' => 'en' ], + 'more' + ], + [ + '{{PLURAL:21|one|more}}', + [ 'lang' => 'be' ], + 'one' + ], + [ + '{{PAGENAME}}', + [], + 'Badtitle/MessageParser' + ], + [ + '{{PAGENAME}}', + [ 'page' => 'Main_Page' ], + 'Main Page', + ] + ]; + } + + /** + * @dataProvider provideTransform + */ + public function testTransform( $input, $options, $expected ) { + $messageParser = $this->getServiceContainer()->getMessageParser(); + $result = $messageParser->transform( + $input, + $options['interface'] ?? true, + $options['lang'] ?? null, + $this->makePage( $options['page'] ?? null ) + ); + $this->assertSame( $expected, $result ); + } + + private function makePage( $title ) { + return $title + ? new PageIdentityValue( 1, NS_MAIN, $title, WikiAwareEntity::LOCAL ) + : null; + } + + public static function provideParse() { + return [ + [ + 'test', + [], + 'test' + ], + [ + '* Bullet', + [], + '<ul><li>Bullet</li></ul>' + ], + [ + '* Asterisk', + [ 'lineStart' => false ], + '* Asterisk' + ], + [ + '{{#bcp47:}}', + [ 'lang' => 'fr' ], + 'fr' + ], + ]; + } + + /** + * @dataProvider provideParse + * @param string $input + * @param array $options + * @param string $expected + */ + public function testParse( $input, $options, $expected ) { + $messageParser = $this->getServiceContainer()->getMessageParser(); + $parserOutput = $messageParser->parse( + $input, + $this->makePage( $options['page'] ?? null ), + $options['lineStart'] ?? true, + $options['interface'] ?? true, + $options['lang'] ?? null + ); + $result = Parser::stripOuterParagraph( $parserOutput->getContentHolderText() ); + $this->assertSame( $expected, $result ); + } +} diff --git a/tests/phpunit/includes/specials/SpecialRecentChangesTest.php b/tests/phpunit/includes/specials/SpecialRecentChangesTest.php index a7a2d530afc0..f50984c67513 100644 --- a/tests/phpunit/includes/specials/SpecialRecentChangesTest.php +++ b/tests/phpunit/includes/specials/SpecialRecentChangesTest.php @@ -1,6 +1,7 @@ <?php use MediaWiki\Context\RequestContext; +use MediaWiki\Language\MessageParser; use MediaWiki\MainConfigNames; use MediaWiki\Request\FauxRequest; use MediaWiki\Specials\SpecialRecentChanges; @@ -26,7 +27,7 @@ class SpecialRecentChangesTest extends AbstractChangesListSpecialPageTestCase { protected function getPage(): SpecialRecentChanges { return new SpecialRecentChanges( $this->getServiceContainer()->getWatchedItemStore(), - $this->getServiceContainer()->getMessageCache(), + $this->getServiceContainer()->getMessageParser(), $this->getServiceContainer()->getUserOptionsLookup(), $this->getServiceContainer()->getChangeTagsStore(), $this->getServiceContainer()->getUserIdentityUtils(), @@ -258,7 +259,7 @@ class SpecialRecentChangesTest extends AbstractChangesListSpecialPageTestCase { $page = new class ( $dense, $this->getServiceContainer()->getWatchedItemStore(), - $this->getServiceContainer()->getMessageCache(), + $this->getServiceContainer()->getMessageParser(), $this->getServiceContainer()->getUserOptionsLookup() ) extends SpecialRecentChanges { private $dense; @@ -266,10 +267,10 @@ class SpecialRecentChangesTest extends AbstractChangesListSpecialPageTestCase { public function __construct( $dense, ?WatchedItemStoreInterface $watchedItemStore = null, - ?MessageCache $messageCache = null, + ?MessageParser $messageParser = null, ?\MediaWiki\User\Options\UserOptionsLookup $userOptionsLookup = null ) { - parent::__construct( $watchedItemStore, $messageCache, $userOptionsLookup ); + parent::__construct( $watchedItemStore, $messageParser, $userOptionsLookup ); $this->dense = $dense; } diff --git a/tests/phpunit/includes/title/TitleTest.php b/tests/phpunit/includes/title/TitleTest.php index 81e1e17ab2d4..0b66ab0f37d9 100644 --- a/tests/phpunit/includes/title/TitleTest.php +++ b/tests/phpunit/includes/title/TitleTest.php @@ -1798,7 +1798,6 @@ class TitleTest extends MediaWikiIntegrationTestCase { public function testNewMainPage() { $mock = $this->createMock( MessageCache::class ); $mock->method( 'get' )->willReturn( 'Foresheet' ); - $mock->method( 'transform' )->willReturn( 'Foresheet' ); $this->setService( 'MessageCache', $mock ); @@ -1816,7 +1815,6 @@ class TitleTest extends MediaWikiIntegrationTestCase { public function testNewMainPageNoRecursion() { $mock = $this->createMock( MessageCache::class ); $mock->method( 'get' )->willReturn( 'localtestiw:' ); - $mock->method( 'transform' )->willReturn( 'localtestiw:' ); $this->setService( 'MessageCache', $mock ); $this->assertSame( diff --git a/tests/phpunit/unit/includes/Permissions/UserAuthorityTest.php b/tests/phpunit/unit/includes/Permissions/UserAuthorityTest.php index 9d0833bb8b9e..45e521ac786f 100644 --- a/tests/phpunit/unit/includes/Permissions/UserAuthorityTest.php +++ b/tests/phpunit/unit/includes/Permissions/UserAuthorityTest.php @@ -22,6 +22,7 @@ namespace MediaWiki\Tests\Unit\Permissions; use InvalidArgumentException; use MediaWiki\Block\AbstractBlock; +use MediaWiki\Language\MessageParser; use MediaWiki\Page\PageIdentity; use MediaWiki\Page\PageIdentityValue; use MediaWiki\Permissions\PermissionStatus; @@ -386,7 +387,7 @@ class UserAuthorityTest extends MediaWikiUnitTestCase { $formatter = new StatusFormatter( new FakeQqxMessageLocalizer(), - $this->createNoOpMock( \MessageCache::class ), + $this->createNoOpMock( MessageParser::class ), new NullLogger() ); // Despite all the futzing around with services, StatusFormatter depends on this global through wfEscapeWikiText diff --git a/tests/phpunit/unit/includes/language/FormatterFactoryTest.php b/tests/phpunit/unit/includes/language/FormatterFactoryTest.php index 49d1c43dd4bb..834582168cf3 100644 --- a/tests/phpunit/unit/includes/language/FormatterFactoryTest.php +++ b/tests/phpunit/unit/includes/language/FormatterFactoryTest.php @@ -3,6 +3,7 @@ use MediaWiki\Context\IContextSource; use MediaWiki\HookContainer\HookContainer; use MediaWiki\Language\FormatterFactory; +use MediaWiki\Language\MessageParser; use MediaWiki\Languages\LanguageFactory; use MediaWiki\Title\TitleFormatter; use MediaWiki\User\UserIdentityUtils; @@ -15,7 +16,7 @@ class FormatterFactoryTest extends MediaWikiUnitTestCase { private function getFactory() { return new FormatterFactory( - $this->createNoOpMock( MessageCache::class ), + $this->createNoOpMock( MessageParser::class ), $this->createNoOpMock( TitleFormatter::class ), $this->createNoOpMock( HookContainer::class ), $this->createNoOpMock( UserIdentityUtils::class ), |