Make UserDefTest a unit test
Building on my last few changes to use UserIdentityLookup and TitleParser, plus the recent addition of UserNameUtils to the DummyServicesTrait, its now fairly simple to make this a unit test and retrieve services from DummyServicesTrait instead of MediaWikiServices. Add a 'hookContainer' option to DummyServicesTrait::getDummyUserNameUtils(), because subclasses of TypeDefTestCase don't have a helper method createHookContainer() (normally this is provided by MediaWikiTestCaseTrait). Instead, create a manual mock HookContainer, like we did previously at NamespaceDefTest. Also add more options to DummyServicesTrait to allow callers to provide service instances, needed to avoid creating two MediaWikiTitleCodec objects and to use a hook container in NamespaceInfo. This also required replacing uses of createNoOpMock() in DummyServicesTrait, because that is also not available in UserDefTest (its another feature of MediaWikiTestCaseTrait). It may be worth exploring splitting MediaWikiTestCaseTrait into the parts that are specific to MediaWiki (like HookContainer or the Message system) and parts that are useful generally (like createNoOpMock). Change-Id: I25b8f0256d222d994173eee66f379fb5422994b5
This commit is contained in:
parent
5da80e9abf
commit
722ae6c6e1
2 changed files with 55 additions and 64 deletions
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 = [
|
||||
Loading…
Reference in a new issue