Emit deprecation warnings reading from $wgUser

With this patch deprecation warnings will be emitted
if $wgUser is accessed or written into. The only pattern
of usage still allowed is

$oldUser = $wgUser;
$wgUser = $newUser;
// Do something
$wgUser = $oldUser;

Once there is no deprecation warnings, we know that nothing
legitimately depends on $wgUser being set, so we can safely
remove the code that's still allowed as well.

Bug: T267861
Change-Id: Ia1c42b3a32acd0e2bb9b0e93f1dc3c82640dcb22
This commit is contained in:
DannyS712 2021-09-04 19:19:47 +00:00 committed by Petr Pchelko
parent 71167aa56c
commit a2b20b63d7
27 changed files with 382 additions and 47 deletions

View file

@ -15,7 +15,6 @@
<exclude name="MediaWiki.NamingConventions.LowerCamelFunctionsName.FunctionName" />
<exclude name="MediaWiki.Usage.DbrQueryUsage.DbrQueryFound" />
<exclude name="MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgTitle" />
<exclude name="MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgUser" />
<exclude name="MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgVersion" />
<exclude name="MediaWiki.Usage.ExtendClassUsage.FunctionConfigUsage" />
<exclude name="MediaWiki.Usage.ExtendClassUsage.FunctionVarUsage" />
@ -177,6 +176,7 @@
</rule>
<rule ref="PSR2.Methods.MethodDeclaration.Underscore">
<exclude-pattern>*/includes/StubObject\.php</exclude-pattern>
<exclude-pattern>*/includes/StubGlobalUser\.php</exclude-pattern>
<exclude-pattern>*/includes/StubUserLang\.php</exclude-pattern>
</rule>
<rule ref="MediaWiki.Usage.AssignmentInReturn.AssignmentInReturn">

View file

@ -778,6 +778,11 @@ because of Phabricator reports.
- PPDPart has been merged into PPDPart_Hash
- PPDStack has been merged into PPDStack_Hash
- PPDStackElement has been merged into PPDStackElement_Hash
* By default, the global variable $wgUser is now an instance of the new class
StubGlobalUser rather than User, and the first time it is used it will emit
deprecation warnings (the $wgUser variable was deprecated in 1.35). For
extensions that read from this variable, please use a relevant ContextSource
instead, falling back to RequestContext::getMain() if none is available.
* Collation::singleton and ::factory were deprecated, obtain an CollationFactory
instance from MediaWikiServices instead.
* Title::getDefaultNamespace() has been deprecated to be removed because

View file

@ -1610,6 +1610,7 @@ $wgAutoloadLocalClasses = [
'StringPrefixSearch' => __DIR__ . '/includes/search/StringPrefixSearch.php',
'StringUtils' => __DIR__ . '/includes/libs/StringUtils.php',
'StripState' => __DIR__ . '/includes/parser/StripState.php',
'StubGlobalUser' => __DIR__ . '/includes/StubGlobalUser.php',
'StubObject' => __DIR__ . '/includes/StubObject.php',
'StubUserLang' => __DIR__ . '/includes/StubUserLang.php',
'SubmitAction' => __DIR__ . '/includes/actions/SubmitAction.php',

View file

@ -820,7 +820,10 @@ if ( !defined( 'MW_NO_SESSION' ) && !$wgCommandLineMode ) {
* @deprecated since 1.35, use an available context source when possible, or, as a backup,
* RequestContext::getMain()
*/
$wgUser = RequestContext::getMain()->getUser(); // BackCompat
$wgUser = new StubGlobalUser( RequestContext::getMain()->getUser() ); // BackCompat
register_shutdown_function( static function () {
StubGlobalUser::$destructorDeprecationDisarmed = true;
} );
/**
* @var Language|StubUserLang $wgLang

148
includes/StubGlobalUser.php Normal file
View file

@ -0,0 +1,148 @@
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
/**
* Stub object for the global user ($wgUser) that makes it possible to change the
* relevant underlying object while still ensuring that deprecation warnings will
* be emitted upon method calls.
*
* @internal Will be removed in 1.38
*
* @since 1.37
* @author Danny712
*/
class StubGlobalUser extends StubObject {
/** @var bool */
public static $destructorDeprecationDisarmed = false;
/** @var User */
public $realUser;
/**
* @param User $realUser
*/
public function __construct( User $realUser ) {
parent::__construct( 'wgUser' );
$this->realUser = $realUser;
}
/**
* @return User
*/
public function _newObject() {
// Based on DeprecatedGlobal::_newObject
/*
* Put the caller offset for wfDeprecated as 6, as
* that gives the function that uses this object, since:
*
* 1 = this function ( _newObject )
* 2 = StubGlobalUser::_unstub
* 3 = StubObject::_call
* 4 = StubObject::__call
* 5 = StubGlobalUser::<method of global called>
* 6 = Actual function using the global.
* (the same applies to _get/__get or _set/__set instead of _call/__call)
*
* Of course its theoretically possible to have other call
* sequences for this method, but that seems to be
* rather unlikely.
*/
// Officially deprecated since 1.35
wfDeprecated( '$wgUser', '1.35', false, 6 );
return $this->realUser;
}
/**
* Reset the stub global user to a different "real" user object, while ensuring that
* any method calls on that object will still trigger deprecation notices.
*
* @param StubGlobalUser|User $user
*/
public static function setUser( $user ) {
// This is intended to be interacting with the deprecated global
// phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgUser
global $wgUser;
self::$destructorDeprecationDisarmed = true;
// Supports StubGlobalUser parameter in case something fetched the existing value of
// $wgUser, set it to something else, and now is trying to restore it
$realUser = self::getRealUser( $user );
$wgUser = new self( $realUser );
self::$destructorDeprecationDisarmed = false;
}
/**
* Get the relevant "real" user object based on either a User object or a StubGlobalUser
* wrapper. Bypasses deprecation notices from converting a StubGlobalUser to an actual
* user, and does not change $wgUser.
*
* @param StubGlobalUser|User $globalUser
* @return User
*/
public static function getRealUser( $globalUser ): User {
if ( $globalUser instanceof StubGlobalUser ) {
return $globalUser->realUser;
} elseif ( $globalUser instanceof User ) {
return $globalUser;
} else {
throw new InvalidArgumentException(
'$globalUser must be a User (or StubGlobalUser), got ' .
( is_object( $globalUser ) ? get_class( $globalUser ) : gettype( $globalUser ) )
);
}
}
/**
* This function creates a new object of the real class and replace it in
* the global variable.
* This is public, for the convenience of external callers wishing to access
* properties, e.g. eval.php
*
* Overriding StubObject::_unstub because for some reason that thinks there is
* an unstub loop when trying to use the magic __set() logic, but there isn't
* any loop because _newObject() returns a specific instance of User rather
* than calling any methods that could then try to use $wgUser. The main difference
* between this and the parent method is that we don't try to check for
* recursion loops.
*
* @param string $name Name of the method called in this object.
* @param int $level Level to go in the stack trace to get the function
* who called this function.
* @return User The unstubbed version
*/
public function _unstub( $name = '_unstub', $level = 2 ) {
if ( !$GLOBALS[$this->global] instanceof self ) {
return $GLOBALS[$this->global]; // already unstubbed.
}
$caller = wfGetCaller( $level );
wfDebug( "Unstubbing \${$this->global} on call of "
. "\${$this->global}::$name from $caller" );
$GLOBALS[$this->global] = $this->_newObject();
return $GLOBALS[$this->global];
}
public function __destruct() {
if ( !self::$destructorDeprecationDisarmed ) {
wfDeprecatedMsg( '$wgUser reassignment detected', '1.37', false, 3 );
}
}
}

View file

@ -528,10 +528,9 @@ class ApiMain extends ApiBase {
// If we're in a mode that breaks the same-origin policy, strip
// user credentials for security.
if ( $this->lacksSameOriginSecurity() ) {
global $wgUser;
wfDebug( "API: stripping user credentials when the same-origin policy is not applied" );
$user = new User();
$wgUser = $user;
StubGlobalUser::setUser( $user );
$derivativeContext->setUser( $user );
$request->response()->header( 'MediaWiki-Login-Suppressed: true' );
}

View file

@ -579,7 +579,7 @@ class RequestContext implements IContextSource, MutableContext {
}
$importSessionFunc = static function ( User $user, array $params ) {
global $wgRequest, $wgUser;
global $wgRequest;
$context = RequestContext::getMain();
@ -608,7 +608,7 @@ class RequestContext implements IContextSource, MutableContext {
// and caught (leaving the main context in a mixed state), there is no risk
// of the User object being attached to the wrong IP, headers, or session.
$context->setUser( $user );
$wgUser = $context->getUser(); // b/c
StubGlobalUser::setUser( $context->getUser() ); // b/c
if ( $session && MediaWiki\Session\PHPSessionHandler::isEnabled() ) {
session_id( $session->getId() );
AtEase::quietCall( 'session_start' );

View file

@ -446,7 +446,7 @@ abstract class Installer {
* @throws MWException
*/
public function resetMediaWikiServices( Config $installerConfig = null, $serviceOverrides = [] ) {
global $wgUser, $wgObjectCaches, $wgLang;
global $wgObjectCaches, $wgLang;
$serviceOverrides += [
// Disable interwiki lookup, to avoid database access during parses
@ -482,7 +482,7 @@ abstract class Installer {
// Note that this will reset the context's language,
// so set the user before setting the language.
$user = User::newFromId( 0 );
$wgUser = $user;
StubGlobalUser::setUser( $user );
RequestContext::getMain()->setUser( $user );

View file

@ -169,6 +169,7 @@ class DoubleRedirectJob extends Job {
}
// Save it
// phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgUser
global $wgUser;
$oldUser = $wgUser;
$wgUser = $user;

View file

@ -1841,8 +1841,9 @@ class WikiPage implements Page, IDBAccessObject, PageRecord {
if ( !$performer ) {
// Its okay to fallback to $wgUser because this whole method is deprecated
// phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgUser
global $wgUser;
$performer = $wgUser;
$performer = StubGlobalUser::getRealUser( $wgUser );
}
return $this->doUserEditContent(
@ -2060,8 +2061,9 @@ class WikiPage implements Page, IDBAccessObject, PageRecord {
) {
if ( !$user ) {
wfDeprecated( __METHOD__ . ' without a UserIdentity', '1.37' );
// phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgUser
global $wgUser;
$user = $wgUser;
$user = StubGlobalUser::getRealUser( $wgUser );
}
$slots = RevisionSlotsUpdate::newFromContent( [ SlotRecord::MAIN => $content ] );

View file

@ -484,7 +484,7 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
* reflected in the current request.
*/
protected function setSessionUserForCurrentRequest() {
global $wgUser, $wgLang;
global $wgLang;
$context = RequestContext::getMain();
$localContext = $this->getContext();
@ -495,7 +495,7 @@ abstract class LoginSignupSpecialPage extends AuthManagerSpecialPage {
$user = $context->getRequest()->getSession()->getUser();
$wgUser = $user;
StubGlobalUser::setUser( $user );
$context->setUser( $user );
$wgLang = $context->getLanguage();

View file

@ -1386,6 +1386,7 @@ class SpecialPageFactory {
public function capturePath(
PageReference $page, IContextSource $context, LinkRenderer $linkRenderer = null
) {
// phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgUser
global $wgTitle, $wgOut, $wgRequest, $wgUser, $wgLang;
$main = RequestContext::getMain();

View file

@ -47,7 +47,7 @@ class CleanupSpam extends Maintenance {
}
public function execute() {
global $IP, $wgLocalDatabases, $wgUser;
global $IP, $wgLocalDatabases;
$username = wfMessage( 'spambot_username' )->text();
$user = User::newSystemUser( $username );
@ -56,7 +56,7 @@ class CleanupSpam extends Maintenance {
}
// Hack: Grant bot rights so we don't flood RecentChanges
MediaWikiServices::getInstance()->getUserGroupManager()->addUserToGroup( $user, 'bot' );
$wgUser = $user;
StubGlobalUser::setUser( $user );
$spec = $this->getArg( 0 );

View file

@ -50,8 +50,6 @@ class DeleteBatch extends Maintenance {
}
public function execute() {
global $wgUser;
# Change to current working directory
$oldCwd = getcwd();
chdir( $oldCwd );
@ -69,7 +67,7 @@ class DeleteBatch extends Maintenance {
if ( !$user ) {
$this->fatalError( "Invalid username" );
}
$wgUser = $user;
StubGlobalUser::setUser( $user );
if ( $this->hasArg( 0 ) ) {
$file = fopen( $this->getArg( 0 ), 'r' );

View file

@ -41,7 +41,6 @@ class DeleteDefaultMessages extends Maintenance {
}
public function execute() {
global $wgUser;
$services = MediaWikiServices::getInstance();
$this->output( "Checking existence of old default messages..." );
@ -86,7 +85,7 @@ class DeleteDefaultMessages extends Maintenance {
}
$userGroupManager = $services->getUserGroupManager();
$userGroupManager->addUserToGroup( $user, 'bot' );
$wgUser = $user;
StubGlobalUser::setUser( $user );
// Handle deletion
$this->output( "\n...deleting old default messages (this may take a long time!)...", 'msg' );

View file

@ -174,8 +174,7 @@ class DeleteEqualMessages extends Maintenance {
if ( !$user ) {
$this->fatalError( "Invalid username" );
}
global $wgUser;
$wgUser = $user;
StubGlobalUser::setUser( $user );
// Hide deletions from RecentChanges
$userGroupManager = $services->getUserGroupManager();

View file

@ -49,8 +49,6 @@ class EditCLI extends Maintenance {
}
public function execute() {
global $wgUser;
$userName = $this->getOption( 'user', false );
$summary = $this->getOption( 'summary', '' );
$remove = $this->hasOption( 'remove' );
@ -71,7 +69,7 @@ class EditCLI extends Maintenance {
if ( $user->isAnon() ) {
$user->addToDatabase();
}
$wgUser = $user;
StubGlobalUser::setUser( $user );
$title = Title::newFromText( $this->getArg( 0 ) );
if ( !$title ) {

View file

@ -125,7 +125,7 @@ class ImportImages extends Maintenance {
}
public function execute() {
global $wgFileExtensions, $wgUser, $wgRestrictionLevels;
global $wgFileExtensions, $wgRestrictionLevels;
$services = MediaWikiServices::getInstance();
$permissionManager = $services->getPermissionManager();
@ -160,7 +160,7 @@ class ImportImages extends Maintenance {
if ( !$user instanceof User ) {
$user = User::newSystemUser( User::MAINTENANCE_SCRIPT_USER, [ 'steal' => true ] );
}
$wgUser = $user;
StubGlobalUser::setUser( $user );
# Get block check. If a value is given, this specified how often the check is performed
$checkUserBlock = (int)$this->getOption( 'check-userblock' );
@ -286,7 +286,7 @@ class ImportImages extends Maintenance {
);
continue;
}
$wgUser = $realUser;
StubGlobalUser::setUser( $realUser );
$user = $realUser;
}
} else {

View file

@ -41,15 +41,13 @@ class ImportSiteScripts extends Maintenance {
}
public function execute() {
global $wgUser;
$username = $this->getOption( 'username', false );
if ( $username === false ) {
$user = User::newSystemUser( 'ScriptImporter', [ 'steal' => true ] );
} else {
$user = User::newFromName( $username );
}
$wgUser = $user;
StubGlobalUser::setUser( $user );
$baseUrl = $this->getArg( 1 );
$pageList = $this->fetchScriptList();

View file

@ -47,8 +47,6 @@ class MoveBatch extends Maintenance {
}
public function execute() {
global $wgUser;
# Change to current working directory
$oldCwd = getcwd();
chdir( $oldCwd );
@ -76,7 +74,7 @@ class MoveBatch extends Maintenance {
if ( !$user ) {
$this->fatalError( "Invalid username" );
}
$wgUser = $user;
StubGlobalUser::setUser( $user );
# Setup complete, now start
$dbw = $this->getDB( DB_PRIMARY );

View file

@ -214,14 +214,12 @@ class PPFuzzTest {
}
public function execute() {
global $wgUser;
$user = new PPFuzzUser;
$user->mName = 'Fuzz';
$user->mFrom = 'name';
$user->ppfz_test = $this;
$wgUser = $user;
StubGlobalUser::setUser( $user );
$options = ParserOptions::newFromUser( $user );
$options->setTemplateCallback( [ $this, 'templateHook' ] );

View file

@ -33,8 +33,6 @@ class Undelete extends Maintenance {
}
public function execute() {
global $wgUser;
$username = $this->getOption( 'user', false );
$reason = $this->getOption( 'reason', '' );
$pageName = $this->getArg( 0 );
@ -51,7 +49,7 @@ class Undelete extends Maintenance {
if ( !$user ) {
$this->fatalError( "Invalid username" );
}
$wgUser = $user;
StubGlobalUser::setUser( $user );
$archive = new PageArchive( $title, RequestContext::getMain()->getConfig() );
$this->output( "Undeleting " . $title->getPrefixedDBkey() . '...' );

View file

@ -1316,7 +1316,7 @@ class ParserTestRunner {
Wikimedia\restoreWarnings();
// Reset context to the restored globals
$context->setUser( $GLOBALS['wgUser'] );
$context->setUser( StubGlobalUser::getRealUser( $GLOBALS['wgUser'] ) );
$context->setSkin( $oldSkin );
$context->setOutput( $GLOBALS['wgOut'] );
};

View file

@ -1863,11 +1863,14 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
if ( in_array( 'user', $tablesUsed ) ) {
TestUserRegistry::clear();
// Reset $wgUser, which is probably 127.0.0.1, as its loaded data is probably not valid
// @todo Should we start setting $wgUser to something nondeterministic
// Reset context user, which is probably 127.0.0.1, as its loaded
// data is probably not valid. This used to manipulate $wgUser but
// since that is deprecated tests are more likely to be relying on
// RequestContext::getMain() instead.
// @todo Should we start setting the user to something nondeterministic
// to encourage tests to be updated to not depend on it?
global $wgUser;
$wgUser->clearInstanceCache( $wgUser->mFrom );
$user = RequestContext::getMain()->getUser();
$user->clearInstanceCache( $user->mFrom );
}
$this->truncateTables( $tablesUsed, $db );

View file

@ -101,8 +101,15 @@ class ApiMainTest extends ApiTestCase {
}
public function testSuppressedLogin() {
// Testing some logic that changes the global $wgUser
// ApiMain will be setting it to a StubGlobalUser object, it should already
// be one but in case its a full User object we will wrap the comparisons
// in StubGlobalUser::getRealUser() which will return the inner User object
// for a StubGlobalUser, or the actual User object if given a user.
// phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgUser
global $wgUser;
$origUser = $wgUser;
$origUser = StubGlobalUser::getRealUser( $wgUser );
$api = $this->getNonInternalApiMain( [
'action' => 'query',
@ -114,7 +121,7 @@ class ApiMainTest extends ApiTestCase {
$api->execute();
ob_end_clean();
$this->assertNotSame( $origUser, $wgUser );
$this->assertNotSame( $origUser, StubGlobalUser::getRealUser( $wgUser ) );
$this->assertSame( 'true', $api->getContext()->getRequest()->response()
->getHeader( 'MediaWiki-Login-Suppressed' ) );
}

View file

@ -266,7 +266,14 @@ class WikiPageDbTest extends MediaWikiLangTestCase {
public function testDoEditContent() {
$this->hideDeprecated( 'WikiPage::doEditContent' );
// We set $wgUser to a User we create to avoid dealing with StubGlobalUser
// deprecation, etc. The entire method is deprecated anyway.
$user = $this->getTestSysop()->getUser();
// phpcs:ignore MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgUser
global $wgUser;
$originalUser = $wgUser;
$wgUser = $user;
// NOTE: Test that Editing also works with a fragment title!
$page = $this->newPage( __METHOD__ . '#Fragment' );
@ -332,8 +339,11 @@ class WikiPageDbTest extends MediaWikiLangTestCase {
$this->assertStringContainsString( '[[gubergren]]', $newText, 'New text must replace old text.' );
$this->assertStringNotContainsString( '[[Lorem ipsum]]', $newText, 'New text must replace old text.' );
$this->assertStringNotContainsString( '~~~~', $newText, 'PST must substitute signature.' );
$this->assertStringContainsString( $wgUser->getName(), $newText,
$this->assertStringContainsString( $user->getName(), $newText,
'Must fall back to $wgUser when no user has been specified.' );
// Reset so that other tests would still fail if interacting with $wgUser
$wgUser = $originalUser;
}
/**

View file

@ -0,0 +1,169 @@
<?php
/**
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
* http://www.gnu.org/copyleft/gpl.html
*
* @file
*/
// phpcs:disable MediaWiki.Usage.DeprecatedGlobalVariables.Deprecated$wgUser
/**
* Tests the StubGlobalUser, including magic support for __get() and __set()
*
* @author DannyS712
*
* @covers \StubGlobalUser
*/
class StubGlobalUserTest extends MediaWikiIntegrationTestCase {
/** @var int */
private $oldErrorLevel;
protected function setUp(): void {
parent::setUp();
// Make sure deprecation notices are seen
$this->oldErrorLevel = error_reporting( -1 );
// Using User::newFromRow() to avoid needing any integration
$userFields = [
'user_id' => 12345,
];
$realUser = User::newFromRow( (object)$userFields );
StubGlobalUser::setUser( $realUser );
}
protected function tearDown(): void {
error_reporting( $this->oldErrorLevel );
parent::tearDown();
}
public function testRealUser() {
// Should not be emitting deprecation warnings
global $wgUser;
$this->assertInstanceOf( StubGlobalUser::class, $wgUser );
$real = StubGlobalUser::getRealUser( $wgUser );
$this->assertInstanceOf( User::class, $real );
$real2 = StubGlobalUser::getRealUser( $real );
$this->assertSame( $real, $real2 );
}
public function testRealUser_exception() {
$this->expectException( InvalidArgumentException::class );
$this->expectExceptionMessage(
'$globalUser must be a User (or StubGlobalUser), got integer'
);
StubGlobalUser::getRealUser( 12345 );
}
public function testMagicCall() {
$this->expectDeprecation();
$this->expectDeprecationMessage( 'Use of $wgUser was deprecated in MediaWiki 1.35' );
global $wgUser;
$this->assertInstanceOf(
StubGlobalUser::class,
$wgUser,
'Sanity check: $wgUser should be a StubGlobalUser at the start of the test'
);
$this->assertSame(
12345,
$wgUser->getId(),
'__call() based on id set in ::setUp()'
);
$this->assertInstanceOf(
User::class,
$wgUser,
'__call() resulted in unstubbing'
);
}
public function testGetMagic() {
$this->expectDeprecation();
$this->expectDeprecationMessage( 'Use of $wgUser was deprecated in MediaWiki 1.35' );
global $wgUser;
$this->assertInstanceOf(
StubGlobalUser::class,
$wgUser,
'Sanity check: $wgUser should be a StubGlobalUser at the start of the test'
);
$this->assertSame(
12345,
$wgUser->mId,
'__get() based on id set in ::setUp()'
);
$this->assertInstanceOf(
User::class,
$wgUser,
'__get() resulted in unstubbing'
);
}
public function testSetMagic() {
// This test is why we need StubGlobalUser::_unstub to override StubObject::_unstub
// and not try to detect and throw exceptions in unstub loops - for some reason it
// thinks this creates a loop.
$this->expectDeprecation();
$this->expectDeprecationMessage( 'Use of $wgUser was deprecated in MediaWiki 1.35' );
global $wgUser;
$this->assertInstanceOf(
StubGlobalUser::class,
$wgUser,
'Sanity check: $wgUser should be a StubGlobalUser at the start of the test'
);
$wgUser->mId = 2000;
$this->assertInstanceOf(
User::class,
$wgUser,
'__set() resulted in unstubbing'
);
$this->assertSame(
2000,
$wgUser->mId,
'__set() call worked'
);
}
public function testDeprecationEmittedWhenReassigned() {
$this->expectDeprecation();
global $wgUser;
$wgUser = new User;
}
/**
* @doesNotPerformAssertions
*/
public function testReassignmentWithRestoring() {
global $wgUser;
$oldUser = $wgUser;
$wgUser = new User;
$wgUser = $oldUser;
}
/**
* @doesNotPerformAssertions
*/
public function testSetUserNoDeprecation() {
StubGlobalUser::setUser( new User );
}
}