diff --git a/includes/user/User.php b/includes/user/User.php index 3fcba4698d0..fa74cb341e3 100644 --- a/includes/user/User.php +++ b/includes/user/User.php @@ -28,6 +28,7 @@ use MediaWiki\Auth\AuthenticationResponse; use MediaWiki\Auth\AuthenticationRequest; use MediaWiki\User\UserIdentity; use MediaWiki\Logger\LoggerFactory; +use Wikimedia\Assert\Assert; use Wikimedia\IPSet; use Wikimedia\ScopedCallback; use Wikimedia\Rdbms\Database; @@ -1749,6 +1750,23 @@ class User implements IDBAccessObject, UserIdentity { } } + /** @var array|null */ + private static $defOpt = null; + /** @var string|null */ + private static $defOptLang = null; + + /** + * Reset the process cache of default user options. This is only necessary + * if the wiki configuration has changed since defaults were calculated, + * and as such should only be performed inside the testing suite that + * regularly changes wiki configuration. + */ + public static function resetGetDefaultOptionsForTestsOnly() { + Assert::invariant( defined( 'MW_PHPUNIT_TEST' ), 'Unit tests only' ); + self::$defOpt = null; + self::$defOptLang = null; + } + /** * Combine the language default options with any site-specific options * and add the default language variants. @@ -1758,26 +1776,23 @@ class User implements IDBAccessObject, UserIdentity { public static function getDefaultOptions() { global $wgNamespacesToBeSearchedDefault, $wgDefaultUserOptions, $wgDefaultSkin; - static $defOpt = null; - static $defOptLang = null; - $contLang = MediaWikiServices::getInstance()->getContentLanguage(); - if ( $defOpt !== null && $defOptLang === $contLang->getCode() ) { + if ( self::$defOpt !== null && self::$defOptLang === $contLang->getCode() ) { // The content language does not change (and should not change) mid-request, but the // unit tests change it anyway, and expect this method to return values relevant to the // current content language. - return $defOpt; + return self::$defOpt; } - $defOpt = $wgDefaultUserOptions; + self::$defOpt = $wgDefaultUserOptions; // Default language setting - $defOptLang = $contLang->getCode(); - $defOpt['language'] = $defOptLang; + self::$defOptLang = $contLang->getCode(); + self::$defOpt['language'] = self::$defOptLang; foreach ( LanguageConverter::$languagesWithVariants as $langCode ) { if ( $langCode === $contLang->getCode() ) { - $defOpt['variant'] = $langCode; + self::$defOpt['variant'] = $langCode; } else { - $defOpt["variant-$langCode"] = $langCode; + self::$defOpt["variant-$langCode"] = $langCode; } } @@ -1785,13 +1800,13 @@ class User implements IDBAccessObject, UserIdentity { // since extensions may change the set of searchable namespaces depending // on user groups/permissions. foreach ( $wgNamespacesToBeSearchedDefault as $nsnum => $val ) { - $defOpt['searchNs' . $nsnum] = (bool)$val; + self::$defOpt['searchNs' . $nsnum] = (bool)$val; } - $defOpt['skin'] = Skin::normalizeKey( $wgDefaultSkin ); + self::$defOpt['skin'] = Skin::normalizeKey( $wgDefaultSkin ); - Hooks::run( 'UserGetDefaultOptions', [ &$defOpt ] ); + Hooks::run( 'UserGetDefaultOptions', [ &self::$defOpt ] ); - return $defOpt; + return self::$defOpt; } /** diff --git a/tests/phpunit/MediaWikiTestCase.php b/tests/phpunit/MediaWikiTestCase.php index 36d66fb2aa5..f43f0a9dd3f 100644 --- a/tests/phpunit/MediaWikiTestCase.php +++ b/tests/phpunit/MediaWikiTestCase.php @@ -361,6 +361,7 @@ abstract class MediaWikiTestCase extends PHPUnit\Framework\TestCase { public static function resetNonServiceCaches() { global $wgRequest, $wgJobClasses; + User::resetGetDefaultOptionsForTestsOnly(); foreach ( $wgJobClasses as $type => $class ) { JobQueueGroup::singleton()->get( $type )->delete(); } diff --git a/tests/phpunit/includes/specials/SpecialWatchlistTest.php b/tests/phpunit/includes/specials/SpecialWatchlistTest.php index 28e26a082bb..642ae3e2de3 100644 --- a/tests/phpunit/includes/specials/SpecialWatchlistTest.php +++ b/tests/phpunit/includes/specials/SpecialWatchlistTest.php @@ -59,7 +59,44 @@ class SpecialWatchlistTest extends SpecialPageTestBase { /** * @dataProvider provideFetchOptionsFromRequest */ - public function testFetchOptionsFromRequest( $expectedValues, $preferences, $inputParams ) { + public function testFetchOptionsFromRequest( + $expectedValuesDefaults, $expectedValues, $preferences, $inputParams + ) { + // $defaults and $allFalse are just to make the expected values below + // shorter by hiding the background. + + $page = TestingAccessWrapper::newFromObject( + $this->newSpecialPage() + ); + + $page->registerFilters(); + + // Does not consider $preferences, just wiki's defaults + $wikiDefaults = $page->getDefaultOptions()->getAllValues(); + + switch ( $expectedValuesDefaults ) { + case 'allFalse': + $allFalse = $wikiDefaults; + + foreach ( $allFalse as $key => $value ) { + if ( $value === true ) { + $allFalse[$key] = false; + } + } + + // This is not exposed on the form (only in preferences) so it + // respects the preference. + $allFalse['extended'] = true; + + $expectedValues += $allFalse; + break; + case 'wikiDefaults': + $expectedValues += $wikiDefaults; + break; + default: + $this->fail( "Unknown \$expectedValuesDefaults: $expectedValuesDefaults" ); + } + $page = TestingAccessWrapper::newFromObject( $this->newSpecialPage() ); @@ -90,43 +127,21 @@ class SpecialWatchlistTest extends SpecialPageTestBase { } public function provideFetchOptionsFromRequest() { - // $defaults and $allFalse are just to make the expected values below - // shorter by hiding the background. - - $page = TestingAccessWrapper::newFromObject( - $this->newSpecialPage() - ); - - $page->registerFilters(); - - // Does not consider $preferences, just wiki's defaults - $wikiDefaults = $page->getDefaultOptions()->getAllValues(); - - $allFalse = $wikiDefaults; - - foreach ( $allFalse as $key => &$value ) { - if ( $value === true ) { - $value = false; - } - } - - // This is not exposed on the form (only in preferences) so it - // respects the preference. - $allFalse['extended'] = true; - return [ - [ - [ + 'ignores casing' => [ + 'expectedValuesDefaults' => 'wikiDefaults', + 'expectedValues' => [ 'hideminor' => true, - ] + $wikiDefaults, - [], - [ + ], + 'preferences' => [], + 'inputParams' => [ 'hideMinor' => 1, ], ], - [ - [ + 'first two same as prefs, second two overriden' => [ + 'expectedValuesDefaults' => 'wikiDefaults', + 'expectedValues' => [ // First two same as prefs 'hideminor' => true, 'hidebots' => false, @@ -135,38 +150,38 @@ class SpecialWatchlistTest extends SpecialPageTestBase { 'hideanons' => false, 'hideliu' => true, 'userExpLevel' => 'registered' - ] + $wikiDefaults, - [ + ], + 'preferences' => [ 'watchlisthideminor' => 1, 'watchlisthidebots' => 0, 'watchlisthideanons' => 1, 'watchlisthideliu' => 0, ], - [ + 'inputParams' => [ 'hideanons' => 0, 'hideliu' => 1, ], ], - // Defaults/preferences for form elements are entirely ignored for - // action=submit and omitted elements become false - [ - [ + 'Defaults/preferences for form elements are entirely ignored for ' + . 'action=submit and omitted elements become false' => [ + 'expectedValuesDefaults' => 'allFalse', + 'expectedValues' => [ 'hideminor' => false, 'hidebots' => true, 'hideanons' => false, 'hideliu' => true, 'userExpLevel' => 'unregistered' - ] + $allFalse, - [ + ], + 'preferences' => [ 'watchlisthideminor' => 0, 'watchlisthidebots' => 1, 'watchlisthideanons' => 0, 'watchlisthideliu' => 1, ], - [ + 'inputParams' => [ 'hidebots' => 1, 'hideliu' => 1, 'action' => 'submit',