*/
private $mwGlobalsToUnset = [];
+ /**
+ * Holds original contents of interwiki table
+ * @var IResultWrapper
+ */
+ private $interwikiTable = null;
+
/**
* Holds original loggers which have been replaced by setLogger()
* @var LoggerInterface[]
* MediaWikiServices.
* @return MediaWikiServices
*/
- protected static function resetGlobalServices( Config $bootstrapConfig = null ) {
+ private static function resetGlobalServices( Config $bootstrapConfig = null ) {
$oldServices = MediaWikiServices::getInstance();
$oldConfigFactory = $oldServices->getConfigFactory();
$oldLoadBalancerFactory = $oldServices->getDBLoadBalancerFactory();
}
}
+ // Store contents of interwiki table in case it changes. Unfortunately, we seem to have no
+ // way to do this only when needed, because tablesUsed can be changed mid-test.
+ if ( $this->db ) {
+ $this->interwikiTable = $this->db->select( 'interwiki', '*', '', __METHOD__ );
+ }
+
// Reset all caches between tests.
$this->doLightweightServiceReset();
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();
return $object;
}
);
+
+ if ( $name === 'ContentLanguage' ) {
+ $this->doSetMwGlobals( [ 'wgContLang' => $object ] );
+ }
}
/**
*
* @param array|string $pairs Key to the global variable, or an array
* of key/value pairs.
- * @param mixed $value Value to set the global to (ignored
+ * @param mixed|null $value Value to set the global to (ignored
* if an array is given as first argument).
*
* @note To allow changes to global variables to take effect on global service instances,
$pairs = [ $pairs => $value ];
}
+ if ( isset( $pairs['wgContLang'] ) ) {
+ throw new MWException(
+ 'No setting $wgContLang, use setContentLang() or setService( \'ContentLanguage\' )'
+ );
+ }
+
+ $this->doSetMwGlobals( $pairs, $value );
+ }
+
+ /**
+ * An internal method that allows setService() to set globals that tests are not supposed to
+ * touch.
+ */
+ private function doSetMwGlobals( $pairs, $value = null ) {
$this->stashMwGlobals( array_keys( $pairs ) );
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' );
}
/**
*
* @since 1.27
*
- * @param Config $configOverrides Configuration overrides for the new MediaWikiServices instance.
+ * @param Config|null $configOverrides Configuration overrides for the new MediaWikiServices
+ * instance.
* @param callable[] $services An associative array of services to re-define. Keys are service
* names, values are callables.
*
$langCode = $lang;
$langObj = Language::factory( $langCode );
}
- $this->setMwGlobals( [
- 'wgLanguageCode' => $langCode,
- 'wgContLang' => $langObj,
- ] );
+ $this->setMwGlobals( 'wgLanguageCode', $langCode );
+ $this->setService( 'ContentLanguage', $langObj );
}
/**
* in which case the next two parameters are ignored; or a single string
* identifying a group, to use with the next two parameters.
* @param string|null $newKey
- * @param mixed $newValue
+ * @param mixed|null $newValue
*/
public function setGroupPermissions( $newPerms, $newKey = null, $newValue = null ) {
global $wgGroupPermissions;
* @since 1.25 ($namespace in 1.28)
* @param string|Title $pageName Page name or title
* @param string $text Page's content
- * @param int $namespace Namespace id (name cannot already contain namespace)
- * @param User $user If null, static::getTestSysop()->getUser() is used.
+ * @param int|null $namespace Namespace id (name cannot already contain namespace)
+ * @param User|null $user If null, static::getTestSysop()->getUser() is used.
* @return array Title object and page id
*/
protected function insertPage(
* Otherwise, it will clone the tables and change the prefix.
*
* @param IMaintainableDatabase $db Database to use
- * @param string $prefix Prefix to use for test tables. If not given, the prefix is determined
+ * @param string|null $prefix Prefix to use for test tables. If not given, the prefix is determined
* automatically for $db.
* @return bool True if tables were cloned, false if only the prefix was changed
*/
$truncate = in_array( $db->getType(), [ 'oracle', 'mysql' ] );
foreach ( $tablesUsed as $tbl ) {
- // TODO: reset interwiki table to its original content.
- if ( $tbl == 'interwiki' ) {
- continue;
- }
-
if ( !$db->tableExists( $tbl ) ) {
continue;
}
$db->resetSequenceForTable( $tbl, __METHOD__ );
}
+ if ( $tbl === 'interwiki' ) {
+ if ( !$this->interwikiTable ) {
+ // @todo We should probably throw here, but this causes test failures that I
+ // can't figure out, so for now we silently continue.
+ continue;
+ }
+ $db->insert(
+ 'interwiki',
+ array_values( array_map( 'get_object_vars', iterator_to_array( $this->interwikiTable ) ) ),
+ __METHOD__
+ );
+ }
+
if ( $tbl === 'page' ) {
// Forget about the pages since they don't
// exist in the DB.
return $loaded;
}
+ /**
+ * Skip the test if using the specified database type
+ *
+ * @param string $type Database type
+ * @since 1.32
+ */
+ protected function markTestSkippedIfDbType( $type ) {
+ if ( $this->db->getType() === $type ) {
+ $this->markTestSkipped( "The $type database type isn't supported for this test" );
+ }
+ }
+
/**
* Used as a marker to prevent wfResetOutputBuffers from breaking PHPUnit.
* @param string $buffer
}
self::assertEquals( file_get_contents( $fileName ), $actualData, $msg );
}
+
+ /**
+ * Edits or creates a page/revision
+ * @param string $pageName Page title
+ * @param string $text Content of the page
+ * @param string $summary Optional summary string for the revision
+ * @param int $defaultNs Optional namespace id
+ * @return array Array as returned by WikiPage::doEditContent()
+ */
+ protected function editPage( $pageName, $text, $summary = '', $defaultNs = NS_MAIN ) {
+ $title = Title::newFromText( $pageName, $defaultNs );
+ $page = WikiPage::factory( $title );
+
+ return $page->doEditContent( ContentHandler::makeContent( $text, $title ), $summary );
+ }
+
+ /**
+ * Revision-deletes a revision.
+ *
+ * @param Revision|int $rev Revision to delete
+ * @param array $value Keys are Revision::DELETED_* flags. Values are 1 to set the bit, 0 to
+ * clear, -1 to leave alone. (All other values also clear the bit.)
+ * @param string $comment Deletion comment
+ */
+ protected function revisionDelete(
+ $rev, array $value = [ Revision::DELETED_TEXT => 1 ], $comment = ''
+ ) {
+ if ( is_int( $rev ) ) {
+ $rev = Revision::newFromId( $rev );
+ }
+ RevisionDeleter::createList(
+ 'revision', RequestContext::getMain(), $rev->getTitle(), [ $rev->getId() ]
+ )->setVisibility( [
+ 'value' => $value,
+ 'comment' => $comment,
+ ] );
+ }
}