From fe2cb4efc64bad506294adeea516efe70368a9b1 Mon Sep 17 00:00:00 2001 From: Erik Bernhardson Date: Wed, 27 Mar 2019 16:55:09 -0700 Subject: [PATCH] Recalculate user default options for each test Statically caching the default user options means tests that change the inputs, and expect to see the result in their code, are foiled and the reasons shrowded in mystery. Recalculate default user options on a per test basis. Change-Id: I9075cc9c05546a857850e8b4b4dea9f51873451b --- includes/user/User.php | 43 +++++--- tests/phpunit/MediaWikiTestCase.php | 1 + .../specials/SpecialWatchlistTest.php | 99 +++++++++++-------- 3 files changed, 87 insertions(+), 56 deletions(-) diff --git a/includes/user/User.php b/includes/user/User.php index 3fcba4698d..fa74cb341e 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 36d66fb2aa..f43f0a9dd3 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 28e26a082b..642ae3e2de 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', -- 2.20.1