diff --git a/tests/phpunit/mocks/DummyServicesTrait.php b/tests/phpunit/mocks/DummyServicesTrait.php index c7864423546..ae6f9e865c5 100644 --- a/tests/phpunit/mocks/DummyServicesTrait.php +++ b/tests/phpunit/mocks/DummyServicesTrait.php @@ -205,6 +205,7 @@ trait DummyServicesTrait { * @param array $options Supported keys: * - validInterwikis: array of interwiki info to pass to getDummyInterwikiLookup * - throwMockExceptions: boolean, see above + * - any of the options passed to getDummyNamespaceInfo (the same $options is passed on) * * @return MediaWikiTitleCodec */ @@ -215,13 +216,10 @@ trait DummyServicesTrait { ]; $config = $options + $baseConfig; - $namespaceInfo = $this->getDummyNamespaceInfo(); + $namespaceInfo = $this->getDummyNamespaceInfo( $options ); /** @var Language|MockObject $language */ - $language = $this->createNoOpMock( - Language::class, - [ 'ucfirst', 'lc', 'getNsIndex', 'needsGenderDistinction', 'getNsText' ] - ); + $language = $this->createMock( Language::class ); $language->method( 'ucfirst' )->willReturnCallback( 'ucfirst' ); $language->method( 'lc' )->willReturnCallback( static function ( $str, $first ) { @@ -263,7 +261,7 @@ trait DummyServicesTrait { $language->method( 'needsGenderDistinction' )->willReturn( false ); /** @var GenderCache|MockObject $genderCache */ - $genderCache = $this->createNoOpMock( GenderCache::class ); + $genderCache = $this->createMock( GenderCache::class ); $interwikiLookup = $this->getDummyInterwikiLookup( $config['validInterwikis'] ); @@ -361,10 +359,17 @@ trait DummyServicesTrait { } /** - * @param array $options Valid keys are any of the configuration options passed, plus - * 'logger' (defaults to a NullLogger), 'validInterwikis' (defaults to 'interwiki'), - * and 'textFormatter' (defaults to a mock where the 'format' method (the only one - * used by UserNameUtils) just returns the key of the MessageValue provided) + * @param array $options Supported keys: + * - any of the configuration options used in the ServiceOptions + * - logger: logger to use, defaults to a NullLogger + * - textFormatter: ITextFormatter to use, defaults to a mock where the 'format' method + * (the only one used by UserNameUtils) just returns the key of the MessageValue provided) + * - titleParser: TitleParser to use, otherwise we will use getDummyTitleParser() + * - any of the options passed to getDummyTitleParser (the same $options is passed on if + * no titleParser is provided) (we change the default for "validInterwikis" to be + * [ 'interwiki' ] instead of an empty array if not provided) + * - hookContainer: specific HookContainer to use, default to creating an empty one via + * $this->createHookContainer() * @return UserNameUtils */ private function getDummyUserNameUtils( array $options = [] ) { @@ -385,7 +390,7 @@ trait DummyServicesTrait { // create a mock in each test. Note that the actual Language::ucfirst is a bit // more complicated than this, but since the tests are all in English the plain // php `ucfirst` should be enough. - $contentLang = $this->createNoOpMock( Language::class, [ 'ucfirst' ] ); + $contentLang = $this->createMock( Language::class, [ 'ucfirst' ] ); $contentLang->method( 'ucfirst' ) ->willReturnCallback( static function ( $str ) { return ucfirst( $str ); @@ -404,16 +409,21 @@ trait DummyServicesTrait { ); } - // The TitleParser from DummyServicesTrait::getDummyTitleParser is really a - // MediaWikiTitleCodec object, and by passing `throwMockExceptions` we replace - // the actual creation of `MalformedTitleException`s with mocks - see - // MediaWikiTitleCodec::overrideCreateMalformedTitleExceptionCallback() - // The UserNameUtils code doesn't care about the message in the exception, - // just whether it is thrown. - $titleParser = $this->getDummyTitleParser( [ - 'validInterwikis' => ( $options['validInterwikis'] ?? [ 'interwiki' ] ), - 'throwMockExceptions' => true, - ] ); + $titleParser = $options['titleParser'] ?? false; + if ( !$titleParser ) { + // The TitleParser from DummyServicesTrait::getDummyTitleParser is really a + // MediaWikiTitleCodec object, and by passing `throwMockExceptions` we replace + // the actual creation of `MalformedTitleException`s with mocks - see + // MediaWikiTitleCodec::overrideCreateMalformedTitleExceptionCallback() + // The UserNameUtils code doesn't care about the message in the exception, + // just whether it is thrown. + $titleParser = $this->getDummyTitleParser( + $options + [ + 'validInterwikis' => [ 'interwiki' ], + 'throwMockExceptions' => true + ] + ); + } return new UserNameUtils( $serviceOptions, @@ -421,7 +431,7 @@ trait DummyServicesTrait { $logger, $titleParser, $textFormatter, - $this->createHookContainer() + $options['hookContainer'] ?? $this->createHookContainer() ); } diff --git a/tests/phpunit/includes/ParamValidator/TypeDef/UserDefTest.php b/tests/phpunit/unit/includes/ParamValidator/TypeDef/UserDefTest.php similarity index 89% rename from tests/phpunit/includes/ParamValidator/TypeDef/UserDefTest.php rename to tests/phpunit/unit/includes/ParamValidator/TypeDef/UserDefTest.php index ba7ca63a4b8..03494c67c79 100644 --- a/tests/phpunit/includes/ParamValidator/TypeDef/UserDefTest.php +++ b/tests/phpunit/unit/includes/ParamValidator/TypeDef/UserDefTest.php @@ -2,8 +2,8 @@ namespace MediaWiki\ParamValidator\TypeDef; -use MediaWiki\Interwiki\ClassicInterwikiLookup; -use MediaWiki\MediaWikiServices; +use MediaWiki\HookContainer\HookContainer; +use MediaWiki\Tests\Unit\DummyServicesTrait; use MediaWiki\User\UserIdentity; use MediaWiki\User\UserIdentityLookup; use MediaWiki\User\UserIdentityValue; @@ -14,11 +14,10 @@ use Wikimedia\ParamValidator\TypeDef\TypeDefTestCase; use Wikimedia\ParamValidator\ValidationException; /** - * @TODO convert to a unit test, all dependencies are injected - * * @covers MediaWiki\ParamValidator\TypeDef\UserDef */ class UserDefTest extends TypeDefTestCase { + use DummyServicesTrait; protected function getInstance( SimpleCallbacks $callbacks, array $options ) { // The UserIdentityLookup that we have knows about 5 users, with ids @@ -48,50 +47,32 @@ class UserDefTest extends TypeDefTestCase { return null; } ); + + // DummyServicesTrait will call $this->createHookContainer() if we didn't pass + // one, but that method is only available from MediaWikiTestCaseTrait - just + // create a simple mock that doesn't do anything, because we + // don't care about hooks here + $hookContainer = $this->createMock( HookContainer::class ); + $hookContainer->method( 'run' )->willReturn( true ); + // We can throw mock exceptions because the UserDef code doesn't care about + // the messages in the exceptions, just if they are thrown + $titleParser = $this->getDummyTitleParser( [ + 'validInterwikis' => [ 'interwiki' ], + 'throwMockExceptions' => true, + 'hookContainer' => $hookContainer, // for the NamespaceInfo + ] ); + $userNameUtils = $this->getDummyUserNameUtils( [ + 'titleParser' => $titleParser, // don't create a new one + 'hookContainer' => $hookContainer, + ] ); return new UserDef( $callbacks, $userIdentityLookup, - MediaWikiServices::getInstance()->getTitleParser(), - MediaWikiServices::getInstance()->getUserNameUtils() + $titleParser, + $userNameUtils ); } - private $wgInterwikiCache = null; - - protected function setUp(): void { - global $wgInterwikiCache; - - parent::setUp(); - - // We don't have MediaWikiIntegrationTestCase's methods available, so we have to do it ourself. - $this->wgInterwikiCache = $wgInterwikiCache; - $wgInterwikiCache = ClassicInterwikiLookup::buildCdbHash( [ - [ - 'iw_prefix' => 'interwiki', - 'iw_url' => 'http://example.com/', - 'iw_local' => 0, - 'iw_trans' => 0, - ], - ] ); - // UserNameUtils holds TitleParser (aka _MediaWikiTitleCodec) holds InterwikiLookup - MediaWikiServices::getInstance()->resetServiceForTesting( 'InterwikiLookup' ); - MediaWikiServices::getInstance()->resetServiceForTesting( '_MediaWikiTitleCodec' ); - MediaWikiServices::getInstance()->resetServiceForTesting( 'TitleParser' ); - MediaWikiServices::getInstance()->resetServiceForTesting( 'UserNameUtils' ); - } - - protected function tearDown(): void { - global $wgInterwikiCache; - - $wgInterwikiCache = $this->wgInterwikiCache; - MediaWikiServices::getInstance()->resetServiceForTesting( 'InterwikiLookup' ); - MediaWikiServices::getInstance()->resetServiceForTesting( '_MediaWikiTitleCodec' ); - MediaWikiServices::getInstance()->resetServiceForTesting( 'TitleParser' ); - MediaWikiServices::getInstance()->resetServiceForTesting( 'UserNameUtils' ); - - parent::tearDown(); - } - public function provideValidate() { // General tests of string inputs $data = [