throw new MWException( "Invalid fallback sequence for language '$code'" );
}
+ /**
+ * Intended for tests that may change configuration in a way that invalidates caches.
+ *
+ * @since 1.32
+ */
+ public static function clearCaches() {
+ if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
+ throw new MWException( __METHOD__ . ' must not be used outside tests' );
+ }
+ self::$dataCache = null;
+ // Reinitialize $dataCache, since it's expected to always be available
+ self::getLocalisationCache();
+ self::$mLangObjCache = [];
+ self::$fallbackLanguageCache = [];
+ self::$grammarTransformations = null;
+ self::$languageNameCache = null;
+ }
+
/**
* Checks whether any localisation is available for that language tag
* in MediaWiki (MessagesXx.php exists).
foreach ( $this->mwGlobalsToUnset as $value ) {
unset( $GLOBALS[$value] );
}
+ if (
+ array_key_exists( 'wgExtraNamespaces', $this->mwGlobals ) ||
+ in_array( 'wgExtraNamespaces', $this->mwGlobalsToUnset )
+ ) {
+ $this->resetNamespaces();
+ }
$this->mwGlobals = [];
$this->mwGlobalsToUnset = [];
$this->restoreLoggers();
foreach ( $pairs as $key => $value ) {
$GLOBALS[$key] = $value;
}
+
+ if ( array_key_exists( 'wgExtraNamespaces', $pairs ) ) {
+ $this->resetNamespaces();
+ }
+ }
+
+ /**
+ * Must be called whenever namespaces are changed, e.g., $wgExtraNamespaces is altered.
+ * Otherwise old namespace data will lurk and cause bugs.
+ */
+ private function resetNamespaces() {
+ MWNamespace::clearCaches();
+ Language::clearCaches();
+
+ // We can't have the TitleFormatter holding on to an old Language object either
+ // @todo We shouldn't need to reset all the aliases here.
+ $services = MediaWikiServices::getInstance();
+ $services->resetServiceForTesting( 'TitleFormatter' );
+ $services->resetServiceForTesting( 'TitleParser' );
+ $services->resetServiceForTesting( '_MediaWikiTitleCodec' );
}
/**
class EditPageTest extends MediaWikiLangTestCase {
protected function setUp() {
- global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
-
parent::setUp();
- $this->setContentLang( $wgContLang );
-
$this->setMwGlobals( [
- 'wgExtraNamespaces' => $wgExtraNamespaces,
- 'wgNamespaceContentModels' => $wgNamespaceContentModels,
- 'wgContentHandlers' => $wgContentHandlers,
+ 'wgExtraNamespaces' => [
+ 12312 => 'Dummy',
+ 12313 => 'Dummy_talk',
+ ],
+ 'wgNamespaceContentModels' => [ 12312 => 'testing' ],
] );
-
- $wgExtraNamespaces[12312] = 'Dummy';
- $wgExtraNamespaces[12313] = 'Dummy_talk';
-
- $wgNamespaceContentModels[12312] = "testing";
- $wgContentHandlers["testing"] = 'DummyContentHandlerForTesting';
-
- MWNamespace::clearCaches();
- $wgContLang->resetNamespaces(); # reset namespace cache
- }
-
- protected function tearDown() {
- global $wgContLang;
-
- MWNamespace::clearCaches();
- $wgContLang->resetNamespaces(); # reset namespace cache
- parent::tearDown();
+ $this->mergeMwGlobalArrayValue(
+ 'wgContentHandlers',
+ [ 'testing' => 'DummyContentHandlerForTesting' ]
+ );
}
/**
$this->assertSame( $key, $message->getKey() );
$this->assertSame( $params, $message->getParams() );
- $this->assertEquals( $expectedLang, $message->getLanguage() );
+ $this->assertSame( $expectedLang->getCode(), $message->getLanguage()->getCode() );
$messageSpecifier = $this->getMockForAbstractClass( MessageSpecifier::class );
$messageSpecifier->expects( $this->any() )
$this->assertSame( $key, $message->getKey() );
$this->assertSame( $params, $message->getParams() );
- $this->assertEquals( $expectedLang, $message->getLanguage() );
+ $this->assertSame( $expectedLang->getCode(), $message->getLanguage()->getCode() );
}
public static function provideConstructor() {
private $the_properties;
protected function setUp() {
- global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
-
parent::setUp();
- $wgExtraNamespaces[12312] = 'Dummy';
- $wgExtraNamespaces[12313] = 'Dummy_talk';
-
- $wgNamespaceContentModels[12312] = 'DUMMY';
- $wgContentHandlers['DUMMY'] = 'DummyContentHandlerForTesting';
+ $this->setMwGlobals( [
+ 'wgExtraNamespaces' => [
+ 12312 => 'Dummy',
+ 12313 => 'Dummy_talk',
+ ],
+ 'wgNamespaceContentModels' => [ 12312 => 'DUMMY' ],
+ ] );
- MWNamespace::clearCaches();
- $wgContLang->resetNamespaces(); # reset namespace cache
+ $this->mergeMwGlobalArrayValue(
+ 'wgContentHandlers',
+ [ 'DUMMY' => 'DummyContentHandlerForTesting' ]
+ );
if ( !$this->the_properties ) {
$this->the_properties = [
}
}
- protected function tearDown() {
- global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
-
- parent::tearDown();
-
- unset( $wgExtraNamespaces[12312] );
- unset( $wgExtraNamespaces[12313] );
-
- unset( $wgNamespaceContentModels[12312] );
- unset( $wgContentHandlers['DUMMY'] );
-
- MWNamespace::clearCaches();
- $wgContLang->resetNamespaces(); # reset namespace cache
- }
-
/**
* Test getting a single property from a single page. The property was
* set in setUp().
$this->markTestSkipped( 'Main namespace does not support wikitext.' );
}
- // Avoid special pages from extensions interferring with the tests
+ // Avoid special pages from extensions interfering with the tests
$this->setMwGlobals( [
'wgSpecialPages' => [],
'wgHooks' => [],
$this->originalHandlers = TestingAccessWrapper::newFromClass( Hooks::class )->handlers;
TestingAccessWrapper::newFromClass( Hooks::class )->handlers = [];
- // Clear caches so that our new namespace appears
- MWNamespace::clearCaches();
- Language::factory( 'en' )->resetNamespaces();
-
SpecialPageFactory::resetList();
}
public function tearDown() {
- MWNamespace::clearCaches();
- Language::factory( 'en' )->resetNamespaces();
-
parent::tearDown();
TestingAccessWrapper::newFromClass( Hooks::class )->handlers = $this->originalHandlers;
abstract protected function getMcrTablesToReset();
protected function setUp() {
- global $wgContLang;
-
$this->tablesUsed += $this->getMcrTablesToReset();
parent::setUp();
$this->getMcrMigrationStage()
);
- MWNamespace::clearCaches();
- // Reset namespace cache
- $wgContLang->resetNamespaces();
-
$this->overrideMwServices();
if ( !$this->testPage ) {
}
}
- protected function tearDown() {
- global $wgContLang;
-
- parent::tearDown();
-
- MWNamespace::clearCaches();
- // Reset namespace cache
- $wgContLang->resetNamespaces();
- }
-
abstract protected function getContentHandlerUseDB();
private function makeRevisionWithProps( $props = null ) {
class TitleMethodsTest extends MediaWikiLangTestCase {
protected function setUp() {
- global $wgContLang;
-
parent::setUp();
$this->mergeMwGlobalArrayValue(
12302 => CONTENT_MODEL_JAVASCRIPT,
]
);
-
- MWNamespace::clearCaches();
- $wgContLang->resetNamespaces(); # reset namespace cache
- }
-
- protected function tearDown() {
- global $wgContLang;
-
- parent::tearDown();
-
- MWNamespace::clearCaches();
- $wgContLang->resetNamespaces(); # reset namespace cache
}
public static function provideEquals() {
class ApiEditPageTest extends ApiTestCase {
protected function setUp() {
- global $wgExtraNamespaces, $wgNamespaceContentModels, $wgContentHandlers, $wgContLang;
-
parent::setUp();
- $this->setContentLang( $wgContLang );
-
$this->setMwGlobals( [
- 'wgExtraNamespaces' => $wgExtraNamespaces,
- 'wgNamespaceContentModels' => $wgNamespaceContentModels,
- 'wgContentHandlers' => $wgContentHandlers,
+ 'wgExtraNamespaces' => [
+ 12312 => 'Dummy',
+ 12313 => 'Dummy_talk',
+ 12314 => 'DummyNonText',
+ 12315 => 'DummyNonText_talk',
+ ],
+ 'wgNamespaceContentModels' => [
+ 12312 => 'testing',
+ 12314 => 'testing-nontext',
+ ],
+ ] );
+ $this->mergeMwGlobalArrayValue( 'wgContentHandlers', [
+ 'testing' => 'DummyContentHandlerForTesting',
+ 'testing-nontext' => 'DummyNonTextContentHandler',
+ 'testing-serialize-error' => 'DummySerializeErrorContentHandler',
] );
-
- $wgExtraNamespaces[12312] = 'Dummy';
- $wgExtraNamespaces[12313] = 'Dummy_talk';
- $wgExtraNamespaces[12314] = 'DummyNonText';
- $wgExtraNamespaces[12315] = 'DummyNonText_talk';
-
- $wgNamespaceContentModels[12312] = "testing";
- $wgNamespaceContentModels[12314] = "testing-nontext";
-
- $wgContentHandlers["testing"] = 'DummyContentHandlerForTesting';
- $wgContentHandlers["testing-nontext"] = 'DummyNonTextContentHandler';
- $wgContentHandlers["testing-serialize-error"] =
- 'DummySerializeErrorContentHandler';
-
- MWNamespace::clearCaches();
- $wgContLang->resetNamespaces(); # reset namespace cache
- }
-
- protected function tearDown() {
- global $wgContLang;
-
- MWNamespace::clearCaches();
- $wgContLang->resetNamespaces(); # reset namespace cache
-
- parent::tearDown();
}
public function testEdit() {
return new \Message( $key, $params, \Language::factory( 'en' ) );
}
+ /**
+ * Test two AuthenticationResponses for equality. We don't want to use regular assertEquals
+ * because that recursively compares members, which leads to false negatives if e.g. Language
+ * caches are reset.
+ *
+ * @param AuthenticationResponse $response1
+ * @param AuthenticationResponse $response2
+ * @param string $msg
+ * @return bool
+ */
+ private function assertResponseEquals(
+ AuthenticationResponse $expected, AuthenticationResponse $actual, $msg = ''
+ ) {
+ foreach ( ( new \ReflectionClass( $expected ) )->getProperties() as $prop ) {
+ $name = $prop->getName();
+ $usedMsg = ltrim( "$msg ($name)" );
+ if ( $name === 'message' && $expected->message ) {
+ $this->assertSame( $expected->message->serialize(), $actual->message->serialize(),
+ $usedMsg );
+ } else {
+ $this->assertEquals( $expected->$name, $actual->$name, $usedMsg );
+ }
+ }
+ }
+
/**
* Initialize the AuthManagerConfig variable in $this->config
*
$this->assertSame( 'http://localhost/', $req->returnToUrl );
$ret->message = $this->message( $ret->message );
- $this->assertEquals( $response, $ret, "Response $i, response" );
+ $this->assertResponseEquals( $response, $ret, "Response $i, response" );
if ( $success ) {
$this->assertSame( $id, $session->getUser()->getId(),
"Response $i, authn" );
"Response $i, login marker" );
}
$ret->message = $this->message( $ret->message );
- $this->assertEquals( $response, $ret, "Response $i, response" );
+ $this->assertResponseEquals( $response, $ret, "Response $i, response" );
if ( $success || $response->status === AuthenticationResponse::FAIL ) {
$this->assertNull(
$this->request->getSession()->getSecret( 'AuthManager::accountCreationState' ),
$this->assertSame( 'http://localhost/', $req->returnToUrl );
$ret->message = $this->message( $ret->message );
- $this->assertEquals( $response, $ret, "Response $i, response" );
+ $this->assertResponseEquals( $response, $ret, "Response $i, response" );
if ( $response->status === AuthenticationResponse::PASS ||
$response->status === AuthenticationResponse::FAIL
) {
class ContentHandlerTest extends MediaWikiTestCase {
protected function setUp() {
- global $wgContLang;
parent::setUp();
$this->setMwGlobals( [
],
] );
- // Reset namespace cache
- MWNamespace::clearCaches();
- $wgContLang->resetNamespaces();
- // And LinkCache
+ // Reset LinkCache
MediaWikiServices::getInstance()->resetServiceForTesting( 'LinkCache' );
}
protected function tearDown() {
- global $wgContLang;
-
- // Reset namespace cache
- MWNamespace::clearCaches();
- $wgContLang->resetNamespaces();
- // And LinkCache
+ // Reset LinkCache
MediaWikiServices::getInstance()->resetServiceForTesting( 'LinkCache' );
parent::tearDown();
<?php
+use Wikimedia\TestingAccessWrapper;
+
class LanguageTest extends LanguageClassesTestCase {
/**
* @covers Language::convertDoubleWidth
$this->assertEquals( "a{$c}b{$c}c{$and}{$s}d", $lang->listToText( [ 'a', 'b', 'c', 'd' ] ) );
}
+ /**
+ * @covers Language::clearCaches
+ */
+ public function testClearCaches() {
+ $languageClass = TestingAccessWrapper::newFromClass( Language::class );
+
+ // Populate $dataCache
+ Language::getLocalisationCache()->getItem( 'zh', 'mainpage' );
+ $oldCacheObj = Language::$dataCache;
+ $this->assertNotCount( 0,
+ TestingAccessWrapper::newFromObject( Language::$dataCache )->loadedItems );
+
+ // Populate $mLangObjCache
+ $lang = Language::factory( 'en' );
+ $this->assertNotCount( 0, Language::$mLangObjCache );
+
+ // Populate $fallbackLanguageCache
+ Language::getFallbacksIncludingSiteLanguage( 'en' );
+ $this->assertNotCount( 0, $languageClass->fallbackLanguageCache );
+
+ // Populate $grammarTransformations
+ $lang->getGrammarTransformations();
+ $this->assertNotNull( $languageClass->grammarTransformations );
+
+ // Populate $languageNameCache
+ Language::fetchLanguageNames();
+ $this->assertNotNull( $languageClass->languageNameCache );
+
+ Language::clearCaches();
+
+ $this->assertNotSame( $oldCacheObj, Language::$dataCache );
+ $this->assertCount( 0,
+ TestingAccessWrapper::newFromObject( Language::$dataCache )->loadedItems );
+ $this->assertCount( 0, Language::$mLangObjCache );
+ $this->assertCount( 0, $languageClass->fallbackLanguageCache );
+ $this->assertNull( $languageClass->grammarTransformations );
+ $this->assertNull( $languageClass->languageNameCache );
+ }
+
/**
* @dataProvider provideIsSupportedLanguage
* @covers Language::isSupportedLanguage