Recalculate user default options for each test
authorErik Bernhardson <ebernhardson@wikimedia.org>
Wed, 27 Mar 2019 23:55:09 +0000 (16:55 -0700)
committerErik Bernhardson <ebernhardson@wikimedia.org>
Thu, 28 Mar 2019 18:12:17 +0000 (11:12 -0700)
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
tests/phpunit/MediaWikiTestCase.php
tests/phpunit/includes/specials/SpecialWatchlistTest.php

index 3fcba46..fa74cb3 100644 (file)
@@ -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;
        }
 
        /**
index 36d66fb..f43f0a9 100644 (file)
@@ -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();
                }
index 28e26a0..642ae3e 100644 (file)
@@ -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',