Merge "Correctly format null error reporting level"
[lhc/web/wiklou.git] / tests / phpunit / MediaWikiIntegrationTestCase.php
index 496f265..82d359f 100644 (file)
@@ -23,8 +23,9 @@ use Wikimedia\TestingAccessWrapper;
 abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
 
        use MediaWikiCoversValidator;
-       use PHPUnit4And6Compat;
        use MediaWikiGroupValidator;
+       use MediaWikiTestCaseTrait;
+       use PHPUnit4And6Compat;
 
        /**
         * The original service locator. This is overridden during setUp().
@@ -181,8 +182,10 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
                global $IP;
                parent::setUpBeforeClass();
                if ( !file_exists( "$IP/LocalSettings.php" ) ) {
-                       echo 'A working MediaWiki installation with a configured LocalSettings.php file is'
-                       . ' required for tests that extend ' . self::class;
+                               echo "File \"$IP/LocalSettings.php\" could not be found. "
+                               . "Test case " . static::class . " extends " . self::class . " "
+                               . "which requires a working MediaWiki installation.\n"
+                               . ( new RuntimeException() )->getTraceAsString();
                        die();
                }
                self::initializeForStandardPhpunitEntrypointIfNeeded();
@@ -583,23 +586,16 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
                $this->tmpFiles = array_merge( $this->tmpFiles, (array)$files );
        }
 
-       // @todo Make const when we no longer support HHVM (T192166)
-       private static $namespaceAffectingSettings = [
-               'wgAllowImageMoving',
-               'wgCanonicalNamespaceNames',
-               'wgCapitalLinkOverrides',
-               'wgCapitalLinks',
-               'wgContentNamespaces',
-               'wgExtensionMessagesFiles',
-               'wgExtensionNamespaces',
-               'wgExtraNamespaces',
-               'wgExtraSignatureNamespaces',
-               'wgNamespaceContentModels',
-               'wgNamespaceProtection',
-               'wgNamespacesWithSubpages',
-               'wgNonincludableNamespaces',
-               'wgRestrictionLevels',
-       ];
+       private static function formatErrorLevel( $errorLevel ) {
+               switch ( gettype( $errorLevel ) ) {
+               case 'integer':
+                       return '0x' . strtoupper( dechex( $errorLevel ) );
+               case 'NULL':
+                       return 'null';
+               default:
+                       throw new MWException( 'Unexpected error level type ' . gettype( $errorLevel ) );
+               }
+       }
 
        protected function tearDown() {
                global $wgRequest, $wgSQLMode;
@@ -647,12 +643,6 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
                foreach ( $this->iniSettings as $name => $value ) {
                        ini_set( $name, $value );
                }
-               if (
-                       array_intersect( self::$namespaceAffectingSettings, array_keys( $this->mwGlobals ) ) ||
-                       array_intersect( self::$namespaceAffectingSettings, $this->mwGlobalsToUnset )
-               ) {
-                       $this->resetNamespaces();
-               }
                $this->mwGlobals = [];
                $this->mwGlobalsToUnset = [];
                $this->restoreLoggers();
@@ -672,10 +662,10 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
                if ( $phpErrorLevel !== $this->phpErrorLevel ) {
                        ini_set( 'error_reporting', $this->phpErrorLevel );
 
-                       $oldHex = strtoupper( dechex( $this->phpErrorLevel ) );
-                       $newHex = strtoupper( dechex( $phpErrorLevel ) );
+                       $oldVal = self::formatErrorLevel( $this->phpErrorLevel );
+                       $newVal = self::formatErrorLevel( $phpErrorLevel );
                        $message = "PHP error_reporting setting was left dirty: "
-                               . "was 0x$oldHex before test, 0x$newHex after test!";
+                               . "was $oldVal before test, $newVal after test!";
 
                        $this->fail( $message );
                }
@@ -741,7 +731,7 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
                );
 
                if ( $name === 'ContentLanguage' ) {
-                       $this->doSetMwGlobals( [ 'wgContLang' => $this->localServices->getContentLanguage() ] );
+                       $this->setMwGlobals( [ 'wgContLang' => $this->localServices->getContentLanguage() ] );
                }
        }
 
@@ -752,9 +742,6 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
         * The key is added to the array of globals that will be reset afterwards
         * in the tearDown().
         *
-        * It may be necessary to call resetServices() to allow any changed configuration variables
-        * to take effect on services that get initialized based on these variables.
-        *
         * @par Example
         * @code
         *     protected function setUp() {
@@ -778,8 +765,7 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
         * @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,
-        *       call resetServices().
+        * @note This will call resetServices().
         *
         * @since 1.21
         */
@@ -788,29 +774,13 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
                        $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->doStashMwGlobals( array_keys( $pairs ) );
 
                foreach ( $pairs as $key => $value ) {
                        $GLOBALS[$key] = $value;
                }
 
-               if ( array_intersect( self::$namespaceAffectingSettings, array_keys( $pairs ) ) ) {
-                       $this->resetNamespaces();
-               }
+               $this->resetServices();
        }
 
        /**
@@ -825,23 +795,6 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
                ini_set( $name, $value );
        }
 
-       /**
-        * Must be called whenever namespaces are changed, e.g., $wgExtraNamespaces is altered.
-        * Otherwise old namespace data will lurk and cause bugs.
-        */
-       private function resetNamespaces() {
-               if ( !$this->localServices ) {
-                       throw new Exception( __METHOD__ . ' must be called after MediaWikiTestCase::run()' );
-               }
-
-               if ( $this->localServices !== MediaWikiServices::getInstance() ) {
-                       throw new Exception( __METHOD__ . ' will not work because the global MediaWikiServices '
-                               . 'instance has been replaced by test code.' );
-               }
-
-               Language::clearCaches();
-       }
-
        /**
         * Check if we can back up a value by performing a shallow copy.
         * Values which fail this test are copied recursively.
@@ -938,16 +891,12 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
         * Useful for setting some entries in a configuration array, instead of
         * setting the entire array.
         *
-        * It may be necessary to call resetServices() to allow any changed configuration variables
-        * to take effect on services that get initialized based on these variables.
-        *
         * @param string $name The name of the global, as in wgFooBar
         * @param array $values The array containing the entries to set in that global
         *
         * @throws MWException If the designated global is not an array.
         *
-        * @note To allow changes to global variables to take effect on global service instances,
-        *       call resetServices().
+        * @note This will call resetServices().
         *
         * @since 1.21
         */
@@ -997,6 +946,7 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
                }
 
                self::resetGlobalParser();
+               Language::clearCaches();
        }
 
        /**
@@ -1181,16 +1131,14 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
         */
        public function setContentLang( $lang ) {
                if ( $lang instanceof Language ) {
-                       $this->setMwGlobals( 'wgLanguageCode', $lang->getCode() );
                        // Set to the exact object requested
                        $this->setService( 'ContentLanguage', $lang );
+                       $this->setMwGlobals( 'wgLanguageCode', $lang->getCode() );
                } else {
-                       $this->setMwGlobals( 'wgLanguageCode', $lang );
-                       // Let the service handler make up the object.  Avoid calling setService(), because if
-                       // we do, overrideMwServices() will complain if it's called later on.
-                       $services = MediaWikiServices::getInstance();
-                       $services->resetServiceForTesting( 'ContentLanguage' );
-                       $this->doSetMwGlobals( [ 'wgContLang' => $services->getContentLanguage() ] );
+                       $this->setMwGlobals( [
+                               'wgLanguageCode' => $lang,
+                               'wgContLang' => Language::factory( $lang ),
+                       ] );
                }
        }
 
@@ -1201,6 +1149,8 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
         * or three values to set a single permission, like
         *   $this->setGroupPermissions( '*', 'read', false );
         *
+        * @note This will call resetServices().
+        *
         * @since 1.31
         * @param array|string $newPerms Either an array of permissions to change,
         *   in which case the next two parameters are ignored; or a single string
@@ -1223,11 +1173,6 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
                }
 
                $this->setMwGlobals( 'wgGroupPermissions', $newPermissions );
-
-               // Reset services so they pick up the new permissions.
-               // Resetting just PermissionManager is not sufficient, since other services may
-               // have the old instance of PermissionManager injected.
-               $this->resetServices();
        }
 
        /**
@@ -1501,7 +1446,6 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
 
                if ( !isset( $db->_originalTablePrefix ) ) {
                        $oldPrefix = $db->tablePrefix();
-
                        if ( $oldPrefix === $prefix ) {
                                // table already has the correct prefix, but presumably no cloned tables
                                $oldPrefix = self::$oldTablePrefix;
@@ -1511,11 +1455,13 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
                        $tablesCloned = self::listTables( $db );
                        $dbClone = new CloneDatabase( $db, $tablesCloned, $prefix, $oldPrefix );
                        $dbClone->useTemporaryTables( self::$useTemporaryTables );
-
                        $dbClone->cloneTableStructure();
 
                        $db->tablePrefix( $prefix );
                        $db->_originalTablePrefix = $oldPrefix;
+
+                       $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
+                       $lb->setTempTablesOnlyMode( self::$useTemporaryTables, $lb->getLocalDomainID() );
                }
 
                return true;
@@ -1862,8 +1808,10 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
 
                $dbClone = new CloneDatabase( $db, $tables, $db->tablePrefix(), $db->_originalTablePrefix );
                $dbClone->useTemporaryTables( self::$useTemporaryTables );
-
                $dbClone->cloneTableStructure();
+
+               $lb = MediaWikiServices::getInstance()->getDBLoadBalancer();
+               $lb->setTempTablesOnlyMode( self::$useTemporaryTables, $lb->getLocalDomainID() );
        }
 
        /**
@@ -2418,6 +2366,9 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
        /**
         * Create a temporary hook handler which will be reset by tearDown.
         * This replaces other handlers for the same hook.
+        *
+        * @note This will call resetServices().
+        *
         * @param string $hookName Hook name
         * @param mixed $handler Value suitable for a hook handler
         * @since 1.28
@@ -2510,20 +2461,6 @@ abstract class MediaWikiIntegrationTestCase extends PHPUnit\Framework\TestCase {
                        'comment' => $comment,
                ] );
        }
-
-       /**
-        * Returns a PHPUnit constraint that matches anything other than a fixed set of values. This can
-        * be used to whitelist values, e.g.
-        *   $mock->expects( $this->never() )->method( $this->anythingBut( 'foo', 'bar' ) );
-        * which will throw if any unexpected method is called.
-        *
-        * @param mixed ...$values Values that are not matched
-        */
-       protected function anythingBut( ...$values ) {
-               return $this->logicalNot( $this->logicalOr(
-                       ...array_map( [ $this, 'matches' ], $values )
-               ) );
-       }
 }
 
 class_alias( 'MediaWikiIntegrationTestCase', 'MediaWikiTestCase' );