Merge "Add default for revision.rev_text_id where missing"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Mon, 19 Mar 2018 20:14:12 +0000 (20:14 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Mon, 19 Mar 2018 20:14:13 +0000 (20:14 +0000)
50 files changed:
.phpcs.xml
composer.json
includes/DefaultSettings.php
includes/GlobalFunctions.php
includes/Storage/RevisionStore.php
includes/WebRequest.php
includes/api/ApiBase.php
includes/api/ApiFormatBase.php
includes/api/ApiQuerySiteinfo.php
includes/debug/MWDebug.php
includes/diff/TableDiffFormatter.php
includes/export/DumpNamespaceFilter.php
includes/filerepo/file/LocalFile.php
includes/htmlform/HTMLForm.php
includes/jobqueue/JobQueueFederated.php
includes/libs/HashRing.php
includes/libs/HtmlArmor.php
includes/libs/Timing.php
includes/libs/http/HttpAcceptNegotiator.php
includes/libs/http/HttpAcceptParser.php
includes/libs/rdbms/database/Database.php
includes/libs/virtualrest/SwiftVirtualRESTService.php
includes/parser/StripState.php
includes/profiler/ProfileSection.php
includes/resourceloader/ResourceLoaderModule.php
maintenance/Maintenance.php
maintenance/rebuildFileCache.php
resources/src/mediawiki.legacy/commonPrint.css
resources/src/mediawiki.legacy/oldshared.css
resources/src/mediawiki.legacy/shared.css
resources/src/mediawiki.skinning/content.css
resources/src/mediawiki/mediawiki.toc.print.css
resources/src/mediawiki/mediawiki.util.js
tests/common/TestsAutoLoader.php
tests/parser/ParserTestRunner.php
tests/phpunit/data/composer/composer.json
tests/phpunit/data/composer/composer.lock
tests/phpunit/data/composer/installed.json
tests/phpunit/data/composer/new-composer.json
tests/phpunit/includes/WebRequestTest.php
tests/phpunit/includes/api/ApiTestCaseUpload.php
tests/phpunit/includes/api/ApiUploadTest.php
tests/phpunit/includes/api/ApiUploadTestCase.php [new file with mode: 0644]
tests/phpunit/includes/changes/ChangesListStringOptionsFilterGroupTest.php
tests/phpunit/includes/libs/GenericArrayObjectTest.php
tests/phpunit/includes/libs/IPTest.php
tests/phpunit/includes/libs/composer/ComposerInstalledTest.php
tests/phpunit/includes/libs/composer/ComposerLockTest.php
tests/phpunit/includes/page/WikiPageDbTestBase.php
tests/selenium/wdio.conf.beta.js [new file with mode: 0644]

index cd55428..d77d398 100644 (file)
@@ -22,8 +22,6 @@
                <exclude name="MediaWiki.Files.ClassMatchesFilename.NotMatch" />
                <exclude name="Generic.Files.OneObjectStructurePerFile.MultipleFound" />
                <exclude name="MediaWiki.VariableAnalysis.ForbiddenGlobalVariables.ForbiddenGlobal$wgTitle" />
-               <exclude name="MediaWiki.Usage.DeprecatedConstantUsage.NS_IMAGE" />
-               <exclude name="MediaWiki.Usage.DeprecatedConstantUsage.NS_IMAGE_TALK" />
                <exclude name="MediaWiki.Commenting.FunctionComment.SpacingDocStar" />
                <exclude name="MediaWiki.Commenting.FunctionComment.SpacingDocTag" />
                <exclude name="Squiz.Scope.MethodScope.Missing" />
index 178c280..0569b03 100644 (file)
@@ -9,7 +9,7 @@
                        "homepage": "https://www.mediawiki.org/wiki/Special:Version/Credits"
                }
        ],
-       "license": "GPL-2.0+",
+       "license": "GPL-2.0-or-later",
        "support": {
                "issues": "https://bugs.mediawiki.org/",
                "irc": "irc://irc.freenode.net/mediawiki",
index fad49e4..538c1b2 100644 (file)
@@ -7335,7 +7335,7 @@ $wgAutoloadAttemptLowercase = true;
  *     'version' => '1.9.0',
  *     'url' => 'https://example.org/example-extension/',
  *     'descriptionmsg' => 'exampleextension-desc',
- *     'license-name' => 'GPL-2.0+',
+ *     'license-name' => 'GPL-2.0-or-later',
  * ];
  * @endcode
  *
@@ -7369,7 +7369,7 @@ $wgAutoloadAttemptLowercase = true;
  *    localizable message (omit in favour of 'descriptionmsg').
  *
  * - license-name: Short name of the license (used as label for the link), such
- *   as "GPL-2.0+" or "MIT" (https://spdx.org/licenses/ for a list of identifiers).
+ *   as "GPL-2.0-or-later" or "MIT" (https://spdx.org/licenses/ for a list of identifiers).
  */
 $wgExtensionCredits = [];
 
index 1d61996..7a5a5d8 100644 (file)
@@ -1050,7 +1050,7 @@ function wfMatchesDomainList( $url, $domains ) {
  */
 function wfDebug( $text, $dest = 'all', array $context = [] ) {
        global $wgDebugRawPage, $wgDebugLogPrefix;
-       global $wgDebugTimestamps, $wgRequestTime;
+       global $wgDebugTimestamps;
 
        if ( !$wgDebugRawPage && wfIsDebugRawPage() ) {
                return;
@@ -1061,7 +1061,7 @@ function wfDebug( $text, $dest = 'all', array $context = [] ) {
        if ( $wgDebugTimestamps ) {
                $context['seconds_elapsed'] = sprintf(
                        '%6.4f',
-                       microtime( true ) - $wgRequestTime
+                       microtime( true ) - $_SERVER['REQUEST_TIME_FLOAT']
                );
                $context['memory_used'] = sprintf(
                        '%5.1fM',
@@ -1514,9 +1514,11 @@ function wfHostname() {
  * @return string
  */
 function wfReportTime() {
-       global $wgRequestTime, $wgShowHostnames;
+       global $wgShowHostnames;
 
-       $responseTime = round( ( microtime( true ) - $wgRequestTime ) * 1000 );
+       $elapsed = ( microtime( true ) - $_SERVER['REQUEST_TIME_FLOAT'] );
+       // seconds to milliseconds
+       $responseTime = round( $elapsed * 1000 );
        $reportVars = [ 'wgBackendResponseTime' => $responseTime ];
        if ( $wgShowHostnames ) {
                $reportVars['wgHostname'] = wfHostname();
index 98ad287..2e3103c 100644 (file)
@@ -1044,9 +1044,10 @@ class RevisionStore
         * @return RevisionRecord|null
         */
        public function getRevisionByTimestamp( $title, $timestamp ) {
+               $db = $this->getDBConnection( DB_REPLICA );
                return $this->newRevisionFromConds(
                        [
-                               'rev_timestamp' => $timestamp,
+                               'rev_timestamp' => $db->timestamp( $timestamp ),
                                'page_namespace' => $title->getNamespace(),
                                'page_title' => $title->getDBkey()
                        ],
index 0a7f416..26e2d45 100644 (file)
@@ -88,8 +88,7 @@ class WebRequest {
         * @codeCoverageIgnore
         */
        public function __construct() {
-               $this->requestTime = isset( $_SERVER['REQUEST_TIME_FLOAT'] )
-                       ? $_SERVER['REQUEST_TIME_FLOAT'] : microtime( true );
+               $this->requestTime = $_SERVER['REQUEST_TIME_FLOAT'];
 
                // POST overrides GET data
                // We don't use $_REQUEST here to avoid interference from cookies...
index 73315a0..22202c0 100644 (file)
@@ -2465,7 +2465,7 @@ abstract class ApiBase extends ContextSource {
                                realpath( __DIR__ ) ?: __DIR__ => [
                                        'path' => $IP,
                                        'name' => 'MediaWiki',
-                                       'license-name' => 'GPL-2.0+',
+                                       'license-name' => 'GPL-2.0-or-later',
                                ],
                                realpath( "$IP/extensions" ) ?: "$IP/extensions" => null,
                                realpath( $extDir ) ?: $extDir => null,
index 18c36de..4b93b31 100644 (file)
@@ -298,7 +298,7 @@ abstract class ApiFormatBase extends ApiBase {
 
                        if ( $this->getIsWrappedHtml() ) {
                                // This is a special output mode mainly intended for ApiSandbox use
-                               $time = microtime( true ) - $this->getConfig()->get( 'RequestTime' );
+                               $time = $this->getMain()->getRequest()->getElapsedTime();
                                $json = FormatJson::encode(
                                        [
                                                'status' => (int)( $this->mHttpStatus ?: 200 ),
index f924736..3048273 100644 (file)
@@ -465,7 +465,7 @@ class ApiQuerySiteinfo extends ApiQueryBase {
                                'host' => $showHostnames
                                                ? $lb->getServerName( $index )
                                                : '',
-                               'lag' => intval( $lag )
+                               'lag' => $lag
                        ];
                }
 
index 012837f..7479841 100644 (file)
@@ -517,7 +517,7 @@ class MWDebug {
                        return [];
                }
 
-               global $wgVersion, $wgRequestTime;
+               global $wgVersion;
                $request = $context->getRequest();
 
                // HHVM's reported memory usage from memory_get_peak_usage()
@@ -540,7 +540,7 @@ class MWDebug {
                        'gitRevision' => GitInfo::headSHA1(),
                        'gitBranch' => $branch,
                        'gitViewUrl' => GitInfo::headViewUrl(),
-                       'time' => microtime( true ) - $wgRequestTime,
+                       'time' => $request->getElapsedTime(),
                        'log' => self::$log,
                        'debugLog' => self::$debug,
                        'queries' => self::$query,
index 14307b5..67f9a79 100644 (file)
@@ -38,7 +38,6 @@ class TableDiffFormatter extends DiffFormatter {
        }
 
        /**
-        * @static
         * @param string $msg
         *
         * @return mixed
index 2b71db0..12b9b55 100644 (file)
@@ -50,8 +50,8 @@ class DumpNamespaceFilter extends DumpFilter {
                        "NS_PROJECT_TALK"   => NS_PROJECT_TALK,
                        "NS_FILE"           => NS_FILE,
                        "NS_FILE_TALK"      => NS_FILE_TALK,
-                       "NS_IMAGE"          => NS_IMAGE, // NS_IMAGE is an alias for NS_FILE
-                       "NS_IMAGE_TALK"     => NS_IMAGE_TALK,
+                       "NS_IMAGE"          => NS_FILE, // NS_IMAGE is an alias for NS_FILE
+                       "NS_IMAGE_TALK"     => NS_FILE_TALK,
                        "NS_MEDIAWIKI"      => NS_MEDIAWIKI,
                        "NS_MEDIAWIKI_TALK" => NS_MEDIAWIKI_TALK,
                        "NS_TEMPLATE"       => NS_TEMPLATE,
index ec4a5fb..7fc45eb 100644 (file)
@@ -3374,6 +3374,8 @@ class LocalFileMoveBatch {
         * many rows where updated.
         */
        protected function doDBUpdates() {
+               global $wgCommentTableSchemaMigrationStage;
+
                $dbw = $this->db;
 
                // Update current image
@@ -3383,6 +3385,15 @@ class LocalFileMoveBatch {
                        [ 'img_name' => $this->oldName ],
                        __METHOD__
                );
+               if ( $wgCommentTableSchemaMigrationStage > MIGRATION_OLD ) {
+                       $dbw->update(
+                               'image_comment_temp',
+                               [ 'imgcomment_name' => $this->newName ],
+                               [ 'imgcomment_name' => $this->oldName ],
+                               __METHOD__
+                       );
+               }
+
                // Update old images
                $dbw->update(
                        'oldimage',
index 78e7625..9b58f92 100644 (file)
@@ -504,7 +504,7 @@ class HTMLForm extends ContextSource {
        /**
         * Prepare form for submission.
         *
-        * @attention When doing method chaining, that should be the very last
+        * @warning When doing method chaining, that should be the very last
         * method call before displayForm().
         *
         * @throws MWException
@@ -1006,7 +1006,7 @@ class HTMLForm extends ContextSource {
         * Display the form (sending to the context's OutputPage object), with an
         * appropriate error message or stack of messages, and any validation errors, etc.
         *
-        * @attention You should call prepareForm() before calling this function.
+        * @warning You should call prepareForm() before calling this function.
         * Moreover, when doing method chaining this should be the very last method
         * call just after prepareForm().
         *
index 118b0f9..7f3b2b1 100644 (file)
@@ -187,7 +187,7 @@ class JobQueueFederated extends JobQueue {
                // phpcs:ignore Generic.CodeAnalysis.ForLoopWithTestFunctionCall
                for ( $i = $this->maxPartitionsTry; $i > 0 && count( $jobsLeft ); --$i ) {
                        try {
-                               $partitionRing->getLiveRing();
+                               $partitionRing->getLiveLocationWeights();
                        } catch ( UnexpectedValueException $e ) {
                                break; // all servers down; nothing to insert to
                        }
index 21558f7..3b9c24d 100644 (file)
@@ -83,7 +83,7 @@ class HashRing {
         * @param string $item
         * @return string Location
         */
-       public function getLocation( $item ) {
+       final public function getLocation( $item ) {
                $locations = $this->getLocations( $item, 1 );
 
                return $locations[0];
@@ -136,19 +136,6 @@ class HashRing {
                return $this->sourceMap;
        }
 
-       /**
-        * Get a new hash ring with a location removed from the ring
-        *
-        * @param string $location
-        * @return HashRing|bool Returns false if no non-zero weighted spots are left
-        */
-       public function newWithoutLocation( $location ) {
-               $map = $this->sourceMap;
-               unset( $map[$location] );
-
-               return count( $map ) ? new self( $map ) : false;
-       }
-
        /**
         * Remove a location from the "live" hash ring
         *
@@ -174,7 +161,7 @@ class HashRing {
         * @return HashRing
         * @throws UnexpectedValueException
         */
-       public function getLiveRing() {
+       protected function getLiveRing() {
                $now = time();
                if ( $this->liveRing === null || $this->ejectionNextExpiry <= $now ) {
                        $this->ejectionExpiries = array_filter(
index 1c141ab..6e6ad7c 100644 (file)
@@ -16,7 +16,7 @@
  * http://www.gnu.org/copyleft/gpl.html
  *
  * @file
- * @license GPL-2.0+
+ * @license GPL-2.0-or-later
  * @author Kunal Mehta <legoktm@member.fsf.org>
  */
 
index 57c253d..7b1a914 100644 (file)
@@ -94,9 +94,7 @@ class Timing implements LoggerAwareInterface {
                                'requestStart' => [
                                        'name'      => 'requestStart',
                                        'entryType' => 'mark',
-                                       'startTime' => isset( $_SERVER['REQUEST_TIME_FLOAT'] )
-                                               ? $_SERVER['REQUEST_TIME_FLOAT']
-                                               : $_SERVER['REQUEST_TIME'],
+                                       'startTime' => $_SERVER['REQUEST_TIME_FLOAT'],
                                        'duration'  => 0,
                                ],
                        ];
index 84c1182..4de8e77 100644 (file)
@@ -10,7 +10,7 @@ namespace Wikimedia\Http;
  * To use this with a request header, first parse the header value into an array of weights
  * using HttpAcceptParser, then call getBestSupportedKey.
  *
- * @license GPL-2.0+
+ * @license GPL-2.0-or-later
  * @author Daniel Kinzler
  * @author Thiemo Kreuz
  */
index bce071e..df22b41 100644 (file)
@@ -4,7 +4,7 @@
  * Utility for parsing a HTTP Accept header value into a weight map. May also be used with
  * other, similar headers like Accept-Language, Accept-Encoding, etc.
  *
- * @license GPL-2.0+
+ * @license GPL-2.0-or-later
  * @author Daniel Kinzler
  */
 
index 53cf55c..97ea266 100644 (file)
@@ -1590,17 +1590,12 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        public function estimateRowCount(
                $table, $vars = '*', $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
        ) {
-               $rows = 0;
                $res = $this->select(
                        $table, [ 'rowcount' => 'COUNT(*)' ], $conds, $fname, $options, $join_conds
                );
+               $row = $res ? $this->fetchRow( $res ) : [];
 
-               if ( $res ) {
-                       $row = $this->fetchRow( $res );
-                       $rows = ( isset( $row['rowcount'] ) ) ? (int)$row['rowcount'] : 0;
-               }
-
-               return $rows;
+               return isset( $row['rowcount'] ) ? (int)$row['rowcount'] : 0;
        }
 
        public function selectRowCount(
@@ -2204,9 +2199,9 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        if ( is_array( $table ) ) {
                                // A parenthesized group
                                if ( count( $table ) > 1 ) {
-                                       $joinedTable = '('
-                                               . $this->tableNamesWithIndexClauseOrJOIN( $table, $use_index, $ignore_index, $join_conds )
-                                               . ')';
+                                       $joinedTable = '(' .
+                                               $this->tableNamesWithIndexClauseOrJOIN(
+                                                       $table, $use_index, $ignore_index, $join_conds ) . ')';
                                } else {
                                        // Degenerate case
                                        $innerTable = reset( $table );
@@ -2364,7 +2359,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        }
                }
 
-               return ' LIKE ' . $this->addQuotes( $s ) . ' ESCAPE ' . $this->addQuotes( $escapeChar ) . ' ';
+               return ' LIKE ' .
+                       $this->addQuotes( $s ) . ' ESCAPE ' . $this->addQuotes( $escapeChar ) . ' ';
        }
 
        public function anyChar() {
index 679d51c..e00bee3 100644 (file)
@@ -22,7 +22,7 @@
 
 /**
  * Example virtual rest service for OpenStack Swift
- * @TODO: caching support (APC/memcached)
+ * @todo caching support (APC/memcached)
  * @since 1.23
  */
 class SwiftVirtualRESTService extends VirtualRESTService {
index d329f69..855ce1d 100644 (file)
@@ -199,7 +199,7 @@ class StripState {
        /**
         * Get an array of parameters to pass to ParserOutput::setLimitReportData()
         *
-        * @unstable Should only be called by Parser
+        * @internal Should only be called by Parser
         * @return array
         */
        public function getLimitReport() {
index d48f744..124e2d3 100644 (file)
@@ -35,7 +35,7 @@ class ProfileSection {
         * the same moment that the function to be profiled terminates.
         *
         * This is typically called like:
-        * @code$section = new ProfileSection( __METHOD__ );@endcode
+        * @code $section = new ProfileSection( __METHOD__ ); @endcode
         *
         * @param string $name Name of the function to profile
         */
index 3be687b..8bf7170 100644 (file)
@@ -620,7 +620,7 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
         *             'https://example.org/image.png' => [ 'as' => 'image' ],
         *         ];
         *     }
-        * @encode
+        * @endcode
         *
         * @par Example using HiDPI image variants
         * @code
@@ -636,7 +636,7 @@ abstract class ResourceLoaderModule implements LoggerAwareInterface {
         *             ],
         *         ];
         *     }
-        * @encode
+        * @endcode
         *
         * @see ResourceLoaderModule::getHeaders
         * @since 1.30
index 1778a79..0c79bd5 100644 (file)
@@ -678,7 +678,7 @@ abstract class Maintenance {
         * Do some sanity checking and basic setup
         */
        public function setup() {
-               global $IP, $wgCommandLineMode, $wgRequestTime;
+               global $IP, $wgCommandLineMode;
 
                # Abort if called from a web server
                # wfIsCLI() is not available yet
@@ -715,8 +715,6 @@ abstract class Maintenance {
                # But sometimes this doesn't seem to be the case.
                ini_set( 'max_execution_time', 0 );
 
-               $wgRequestTime = microtime( true );
-
                # Define us as being in MediaWiki
                define( 'MEDIAWIKI', true );
 
index ecdec29..1f89426 100644 (file)
@@ -57,8 +57,6 @@ class RebuildFileCache extends Maintenance {
        }
 
        public function execute() {
-               global $wgRequestTime;
-
                if ( !$this->enabled ) {
                        $this->fatalError( "Nothing to do -- \$wgUseFileCache is disabled." );
                }
@@ -90,7 +88,8 @@ class RebuildFileCache extends Maintenance {
                        $this->fatalError( "Nothing to do." );
                }
 
-               $_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip'; // hack, no real client
+               // Mock request (hack, no real client)
+               $_SERVER['HTTP_ACCEPT_ENCODING'] = 'bgzip';
 
                # Do remaining chunk
                $end += $batchSize - 1;
@@ -141,22 +140,27 @@ class RebuildFileCache extends Maintenance {
                                        }
 
                                        Wikimedia\suppressWarnings(); // header notices
-                                       // Cache ?action=view
-                                       $wgRequestTime = microtime( true ); # T24852
+
+                                       // 1. Cache ?action=view
+                                       // Be sure to reset the mocked request time (T24852)
+                                       $_SERVER['REQUEST_TIME_FLOAT'] = microtime( true );
                                        ob_start();
                                        $article->view();
                                        $context->getOutput()->output();
                                        $context->getOutput()->clearHTML();
                                        $viewHtml = ob_get_clean();
                                        $viewCache->saveToFileCache( $viewHtml );
-                                       // Cache ?action=history
-                                       $wgRequestTime = microtime( true ); # T24852
+
+                                       // 2. Cache ?action=history
+                                       // Be sure to reset the mocked request time (T24852)
+                                       $_SERVER['REQUEST_TIME_FLOAT'] = microtime( true );
                                        ob_start();
                                        Action::factory( 'history', $article, $context )->show();
                                        $context->getOutput()->output();
                                        $context->getOutput()->clearHTML();
                                        $historyHtml = ob_get_clean();
                                        $historyCache->saveToFileCache( $historyHtml );
+
                                        Wikimedia\restoreWarnings();
 
                                        if ( $rebuilt ) {
index df5aa0f..64870fd 100644 (file)
@@ -166,7 +166,6 @@ ul {
        margin: 0 !important; /* stylelint-disable-line declaration-no-important */
 }
 
-#toc,
 .toc {
        background-color: #f9f9f9;
        border: 1pt solid #aaa;
index 7b2d711..2572b52 100644 (file)
@@ -166,7 +166,6 @@ img {
        border: 0;
 }
 
-#toc,
 .toc {
        border: 1px solid #bba;
        background-color: #f7f8ff;
@@ -182,18 +181,15 @@ img {
 }
 
 /* CSS for backwards-compatibility with cached page renders and creative uses in wikitext */
-table#toc,
 table.toc {
        border-collapse: collapse;
 }
 
 /* Remove additional paddings inside table-cells that are not present in <div>s */
-table#toc td,
 table.toc td {
        padding: 0;
 }
 
-#toc h2,
 .toc h2 {
        display: inline;
        border: 0;
@@ -202,7 +198,6 @@ table.toc td {
        font-weight: bold;
 }
 
-#toc ul,
 .toc ul {
        list-style-type: none;
        list-style-image: none;
@@ -210,7 +205,6 @@ table.toc td {
        text-align: left;
 }
 
-#toc ul ul,
 .toc ul ul {
        margin: 0 0 0 2em;
 }
@@ -274,7 +268,7 @@ table.small {
        font-size: 100%;
 }
 
-/* use this instead of #toc for page content */
+/* use this instead of .toc for page content */
 .toccolours {
        border: 1px solid #aaa;
        background-color: #f9f9f9;
index e46c758..0f84ff1 100644 (file)
@@ -625,43 +625,31 @@ ol:lang( or ) li {
        list-style-type: oriya;
 }
 
-#toc ul,
 .toc ul {
        margin: 0.3em 0;
 }
 
 /* Correct directionality when page dir is different from site/user dir */
 /* @noflip */ .mw-content-ltr .toc ul,
-.mw-content-ltr #toc ul,
-.mw-content-rtl .mw-content-ltr .toc ul,
-.mw-content-rtl .mw-content-ltr #toc ul {
+.mw-content-rtl .mw-content-ltr .toc ul {
        text-align: left;
 }
 
 /* @noflip */ .mw-content-rtl .toc ul,
-.mw-content-rtl #toc ul,
-.mw-content-ltr .mw-content-rtl .toc ul,
-.mw-content-ltr .mw-content-rtl #toc ul {
+.mw-content-ltr .mw-content-rtl .toc ul {
        text-align: right;
 }
 
 /* @noflip */ .mw-content-ltr .toc ul ul,
-.mw-content-ltr #toc ul ul,
-.mw-content-rtl .mw-content-ltr .toc ul ul,
-.mw-content-rtl .mw-content-ltr #toc ul ul {
+.mw-content-rtl .mw-content-ltr .toc ul ul {
        margin: 0 0 0 2em;
 }
 
 /* @noflip */ .mw-content-rtl .toc ul ul,
-.mw-content-rtl #toc ul ul,
-.mw-content-ltr .mw-content-rtl .toc ul ul,
-.mw-content-ltr .mw-content-rtl #toc ul ul {
+.mw-content-ltr .mw-content-rtl .toc ul ul {
        margin: 0 2em 0 0;
 }
 
-#toc #toctitle,
-.toc #toctitle,
-#toc .toctitle,
 .toc .toctitle {
        direction: ltr;
 }
index 5ded184..890856a 100644 (file)
@@ -6,7 +6,6 @@
  */
 
 /* Table of Contents */
-#toc,
 .toc,
 .mw-warning,
 .toccolours {
@@ -28,7 +27,6 @@
  * inline elements. In practice inline elements surrounding the TOC are uncommon enough that
  * this is an acceptable sacrifice.
  */
-#toc,
 .toc {
        display: inline-block;
        display: table;
 }
 
 /* CSS for backwards-compatibility with cached page renders and creative uses in wikitext */
-table#toc,
 table.toc {
        border-collapse: collapse;
 }
 
 /* Remove additional paddings inside table-cells that are not present in <div>s */
-table#toc td,
 table.toc td {
        padding: 0;
 }
 
-#toc h2,
 .toc h2 {
        display: inline;
        border: 0;
@@ -61,14 +56,10 @@ table.toc td {
        font-weight: bold;
 }
 
-#toc #toctitle,
-.toc #toctitle,
-#toc .toctitle,
 .toc .toctitle {
        text-align: center;
 }
 
-#toc ul,
 .toc ul {
        list-style-type: none;
        list-style-image: none;
@@ -77,7 +68,6 @@ table.toc td {
        text-align: left;
 }
 
-#toc ul ul,
 .toc ul ul {
        margin: 0 0 0 2em;
 }
index fb34a89..d7b3f35 100644 (file)
                 * Note: borrows from IP::isIPv4
                 *
                 * @param {string} address
-                * @param {boolean} allowBlock
+                * @param {boolean} [allowBlock=false]
                 * @return {boolean}
                 */
                isIPv4Address: function ( address, allowBlock ) {
                 * Note: borrows from IP::isIPv6
                 *
                 * @param {string} address
-                * @param {boolean} allowBlock
+                * @param {boolean} [allowBlock=false]
                 * @return {boolean}
                 */
                isIPv6Address: function ( address, allowBlock ) {
                 *
                 * @since 1.25
                 * @param {string} address String to check
-                * @param {boolean} allowBlock True if a block of IPs should be allowed
+                * @param {boolean} [allowBlock=false] If a block of IPs should be allowed
                 * @return {boolean}
                 */
                isIPAddress: function ( address, allowBlock ) {
index a777153..b994f8a 100644 (file)
@@ -77,6 +77,7 @@ $wgAutoloadClasses += [
        'ApiTestCase' => "$testDir/phpunit/includes/api/ApiTestCase.php",
        'ApiTestCaseUpload' => "$testDir/phpunit/includes/api/ApiTestCaseUpload.php",
        'ApiTestContext' => "$testDir/phpunit/includes/api/ApiTestContext.php",
+       'ApiUploadTestCase' => "$testDir/phpunit/includes/api/ApiUploadTestCase.php",
        'MockApi' => "$testDir/phpunit/includes/api/MockApi.php",
        'MockApiQueryBase' => "$testDir/phpunit/includes/api/MockApiQueryBase.php",
        'UserWrapper' => "$testDir/phpunit/includes/api/UserWrapper.php",
index a03f969..f0c815f 100644 (file)
@@ -636,7 +636,6 @@ class ParserTestRunner {
 
        /**
         * Remove last character if it is a newline
-        * @group utility
         * @param string $s
         * @return string
         */
index bcd196f..9b902ae 100644 (file)
@@ -9,7 +9,7 @@
                        "homepage": "https://www.mediawiki.org/wiki/Special:Version/Credits"
                }
        ],
-       "license": "GPL-2.0",
+       "license": "GPL-2.0-only",
        "support": {
                "issues": "https://bugzilla.wikimedia.org/",
                "irc": "irc://irc.freenode.net/mediawiki",
index cae6a47..5c030db 100644 (file)
             "notification-url": "https://packagist.org/downloads/",
             "license": [
                 "MIT",
-                "GPL-3.0"
+                "GPL-3.0-only"
             ],
             "authors": [
                 {
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
-                "GPL-2.0+"
+                "GPL-2.0-or-later"
             ],
             "authors": [
                 {
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
-                "GPL-2.0+",
+                "GPL-2.0-or-later",
                 "MIT"
             ],
             "description": "The primary aim is to allow users to select a language and configure its support in an easy way. Main features are language selection, input methods and web fonts.",
             },
             "notification-url": "https://packagist.org/downloads/",
             "license": [
-                "GPL-2.0"
+                "GPL-2.0-only"
             ],
             "authors": [
                 {
index ddac980..88a6bae 100644 (file)
@@ -30,7 +30,7 @@
         "notification-url": "https://packagist.org/downloads/",
         "license": [
             "MIT",
-            "GPL-3.0"
+            "GPL-3.0-only"
         ],
         "authors": [
             {
index 0634c2d..3a88676 100644 (file)
@@ -9,7 +9,7 @@
                        "homepage": "https://www.mediawiki.org/wiki/Special:Version/Credits"
                }
        ],
-       "license": "GPL-2.0",
+       "license": "GPL-2.0-only",
        "support": {
                "issues": "https://bugzilla.wikimedia.org/",
                "irc": "irc://irc.freenode.net/mediawiki",
index 936f4f5..9583921 100644 (file)
@@ -26,7 +26,7 @@ class WebRequestTest extends MediaWikiTestCase {
        public function testDetectServer( $expected, $input, $description ) {
                $this->setMwGlobals( 'wgAssumeProxiesUseDefaultProtocolPorts', true );
 
-               $_SERVER = $input;
+               $this->setServerVars( $input );
                $result = WebRequest::detectServer();
                $this->assertEquals( $expected, $result, $description );
        }
@@ -363,7 +363,7 @@ class WebRequestTest extends MediaWikiTestCase {
         * @covers WebRequest::getIP
         */
        public function testGetIP( $expected, $input, $squid, $xffList, $private, $description ) {
-               $_SERVER = $input;
+               $this->setServerVars( $input );
                $this->setMwGlobals( [
                        'wgUsePrivateIPs' => $private,
                        'wgHooks' => [
@@ -608,8 +608,19 @@ class WebRequestTest extends MediaWikiTestCase {
         * @covers WebRequest::getAcceptLang
         */
        public function testAcceptLang( $acceptLanguageHeader, $expectedLanguages, $description ) {
-               $_SERVER = [ 'HTTP_ACCEPT_LANGUAGE' => $acceptLanguageHeader ];
+               $this->setServerVars( [ 'HTTP_ACCEPT_LANGUAGE' => $acceptLanguageHeader ] );
                $request = new WebRequest();
                $this->assertSame( $request->getAcceptLang(), $expectedLanguages, $description );
        }
+
+       protected function setServerVars( $vars ) {
+               // Don't remove vars which should be available in all SAPI.
+               if ( !isset( $vars['REQUEST_TIME_FLOAT'] ) ) {
+                       $vars['REQUEST_TIME_FLOAT'] = $_SERVER['REQUEST_TIME_FLOAT'];
+               }
+               if ( !isset( $vars['REQUEST_TIME'] ) ) {
+                       $vars['REQUEST_TIME'] = $_SERVER['REQUEST_TIME'];
+               }
+               $_SERVER = $vars;
+       }
 }
index f15da2e..3670fad 100644 (file)
@@ -1,153 +1,8 @@
 <?php
 
 /**
- * Abstract class to support upload tests
+ * For backward compatibility since 1.31
  */
-abstract class ApiTestCaseUpload extends ApiTestCase {
-       /**
-        * Fixture -- run before every test
-        */
-       protected function setUp() {
-               parent::setUp();
+abstract class ApiTestCaseUpload extends ApiUploadTestCase {
 
-               $this->setMwGlobals( [
-                       'wgEnableUploads' => true,
-                       'wgEnableAPI' => true,
-               ] );
-
-               $this->clearFakeUploads();
-       }
-
-       /**
-        * Helper function -- remove files and associated articles by Title
-        *
-        * @param Title $title Title to be removed
-        *
-        * @return bool
-        */
-       public function deleteFileByTitle( $title ) {
-               if ( $title->exists() ) {
-                       $file = wfFindFile( $title, [ 'ignoreRedirect' => true ] );
-                       $noOldArchive = ""; // yes this really needs to be set this way
-                       $comment = "removing for test";
-                       $restrictDeletedVersions = false;
-                       $status = FileDeleteForm::doDelete(
-                               $title,
-                               $file,
-                               $noOldArchive,
-                               $comment,
-                               $restrictDeletedVersions
-                       );
-
-                       if ( !$status->isGood() ) {
-                               return false;
-                       }
-
-                       $page = WikiPage::factory( $title );
-                       $page->doDeleteArticle( "removing for test" );
-
-                       // see if it now doesn't exist; reload
-                       $title = Title::newFromText( $title->getText(), NS_FILE );
-               }
-
-               return !( $title && $title instanceof Title && $title->exists() );
-       }
-
-       /**
-        * Helper function -- remove files and associated articles with a particular filename
-        *
-        * @param string $fileName Filename to be removed
-        *
-        * @return bool
-        */
-       public function deleteFileByFileName( $fileName ) {
-               return $this->deleteFileByTitle( Title::newFromText( $fileName, NS_FILE ) );
-       }
-
-       /**
-        * Helper function -- given a file on the filesystem, find matching
-        * content in the db (and associated articles) and remove them.
-        *
-        * @param string $filePath Path to file on the filesystem
-        *
-        * @return bool
-        */
-       public function deleteFileByContent( $filePath ) {
-               $hash = FSFile::getSha1Base36FromPath( $filePath );
-               $dupes = RepoGroup::singleton()->findBySha1( $hash );
-               $success = true;
-               foreach ( $dupes as $dupe ) {
-                       $success &= $this->deleteFileByTitle( $dupe->getTitle() );
-               }
-
-               return $success;
-       }
-
-       /**
-        * Fake an upload by dumping the file into temp space, and adding info to $_FILES.
-        * (This is what PHP would normally do).
-        *
-        * @param string $fieldName Name this would have in the upload form
-        * @param string $fileName Name to title this
-        * @param string $type MIME type
-        * @param string $filePath Path where to find file contents
-        *
-        * @throws Exception
-        * @return bool
-        */
-       function fakeUploadFile( $fieldName, $fileName, $type, $filePath ) {
-               $tmpName = $this->getNewTempFile();
-               if ( !file_exists( $filePath ) ) {
-                       throw new Exception( "$filePath doesn't exist!" );
-               }
-
-               if ( !copy( $filePath, $tmpName ) ) {
-                       throw new Exception( "couldn't copy $filePath to $tmpName" );
-               }
-
-               clearstatcache();
-               $size = filesize( $tmpName );
-               if ( $size === false ) {
-                       throw new Exception( "couldn't stat $tmpName" );
-               }
-
-               $_FILES[$fieldName] = [
-                       'name' => $fileName,
-                       'type' => $type,
-                       'tmp_name' => $tmpName,
-                       'size' => $size,
-                       'error' => null
-               ];
-
-               return true;
-       }
-
-       function fakeUploadChunk( $fieldName, $fileName, $type, & $chunkData ) {
-               $tmpName = $this->getNewTempFile();
-               // copy the chunk data to temp location:
-               if ( !file_put_contents( $tmpName, $chunkData ) ) {
-                       throw new Exception( "couldn't copy chunk data to $tmpName" );
-               }
-
-               clearstatcache();
-               $size = filesize( $tmpName );
-               if ( $size === false ) {
-                       throw new Exception( "couldn't stat $tmpName" );
-               }
-
-               $_FILES[$fieldName] = [
-                       'name' => $fileName,
-                       'type' => $type,
-                       'tmp_name' => $tmpName,
-                       'size' => $size,
-                       'error' => null
-               ];
-       }
-
-       /**
-        * Remove traces of previous fake uploads
-        */
-       function clearFakeUploads() {
-               $_FILES = [];
-       }
 }
index 345f196..41c9aed 100644 (file)
@@ -22,7 +22,7 @@
  *
  * @covers ApiUpload
  */
-class ApiUploadTest extends ApiTestCaseUpload {
+class ApiUploadTest extends ApiUploadTestCase {
        /**
         * Testing login
         * XXX this is a funny way of getting session context
diff --git a/tests/phpunit/includes/api/ApiUploadTestCase.php b/tests/phpunit/includes/api/ApiUploadTestCase.php
new file mode 100644 (file)
index 0000000..3c7efd5
--- /dev/null
@@ -0,0 +1,153 @@
+<?php
+
+/**
+ * Abstract class to support upload tests
+ */
+abstract class ApiUploadTestCase extends ApiTestCase {
+       /**
+        * Fixture -- run before every test
+        */
+       protected function setUp() {
+               parent::setUp();
+
+               $this->setMwGlobals( [
+                       'wgEnableUploads' => true,
+                       'wgEnableAPI' => true,
+               ] );
+
+               $this->clearFakeUploads();
+       }
+
+       /**
+        * Helper function -- remove files and associated articles by Title
+        *
+        * @param Title $title Title to be removed
+        *
+        * @return bool
+        */
+       public function deleteFileByTitle( $title ) {
+               if ( $title->exists() ) {
+                       $file = wfFindFile( $title, [ 'ignoreRedirect' => true ] );
+                       $noOldArchive = ""; // yes this really needs to be set this way
+                       $comment = "removing for test";
+                       $restrictDeletedVersions = false;
+                       $status = FileDeleteForm::doDelete(
+                               $title,
+                               $file,
+                               $noOldArchive,
+                               $comment,
+                               $restrictDeletedVersions
+                       );
+
+                       if ( !$status->isGood() ) {
+                               return false;
+                       }
+
+                       $page = WikiPage::factory( $title );
+                       $page->doDeleteArticle( "removing for test" );
+
+                       // see if it now doesn't exist; reload
+                       $title = Title::newFromText( $title->getText(), NS_FILE );
+               }
+
+               return !( $title && $title instanceof Title && $title->exists() );
+       }
+
+       /**
+        * Helper function -- remove files and associated articles with a particular filename
+        *
+        * @param string $fileName Filename to be removed
+        *
+        * @return bool
+        */
+       public function deleteFileByFileName( $fileName ) {
+               return $this->deleteFileByTitle( Title::newFromText( $fileName, NS_FILE ) );
+       }
+
+       /**
+        * Helper function -- given a file on the filesystem, find matching
+        * content in the db (and associated articles) and remove them.
+        *
+        * @param string $filePath Path to file on the filesystem
+        *
+        * @return bool
+        */
+       public function deleteFileByContent( $filePath ) {
+               $hash = FSFile::getSha1Base36FromPath( $filePath );
+               $dupes = RepoGroup::singleton()->findBySha1( $hash );
+               $success = true;
+               foreach ( $dupes as $dupe ) {
+                       $success &= $this->deleteFileByTitle( $dupe->getTitle() );
+               }
+
+               return $success;
+       }
+
+       /**
+        * Fake an upload by dumping the file into temp space, and adding info to $_FILES.
+        * (This is what PHP would normally do).
+        *
+        * @param string $fieldName Name this would have in the upload form
+        * @param string $fileName Name to title this
+        * @param string $type MIME type
+        * @param string $filePath Path where to find file contents
+        *
+        * @throws Exception
+        * @return bool
+        */
+       function fakeUploadFile( $fieldName, $fileName, $type, $filePath ) {
+               $tmpName = $this->getNewTempFile();
+               if ( !file_exists( $filePath ) ) {
+                       throw new Exception( "$filePath doesn't exist!" );
+               }
+
+               if ( !copy( $filePath, $tmpName ) ) {
+                       throw new Exception( "couldn't copy $filePath to $tmpName" );
+               }
+
+               clearstatcache();
+               $size = filesize( $tmpName );
+               if ( $size === false ) {
+                       throw new Exception( "couldn't stat $tmpName" );
+               }
+
+               $_FILES[$fieldName] = [
+                       'name' => $fileName,
+                       'type' => $type,
+                       'tmp_name' => $tmpName,
+                       'size' => $size,
+                       'error' => null
+               ];
+
+               return true;
+       }
+
+       function fakeUploadChunk( $fieldName, $fileName, $type, & $chunkData ) {
+               $tmpName = $this->getNewTempFile();
+               // copy the chunk data to temp location:
+               if ( !file_put_contents( $tmpName, $chunkData ) ) {
+                       throw new Exception( "couldn't copy chunk data to $tmpName" );
+               }
+
+               clearstatcache();
+               $size = filesize( $tmpName );
+               if ( $size === false ) {
+                       throw new Exception( "couldn't stat $tmpName" );
+               }
+
+               $_FILES[$fieldName] = [
+                       'name' => $fileName,
+                       'type' => $type,
+                       'tmp_name' => $tmpName,
+                       'size' => $size,
+                       'error' => null
+               ];
+       }
+
+       /**
+        * Remove traces of previous fake uploads
+        */
+       function clearFakeUploads() {
+               $_FILES = [];
+       }
+}
index 2355f76..b627178 100644 (file)
@@ -179,8 +179,6 @@ class ChangesListStringOptionsFilterGroupTest extends MediaWikiTestCase {
        /**
         * @param array $groupDefinition Group definition
         * @param string $input Value in URL
-        *
-        * @dataProvider provideModifyQuery
         */
        protected function modifyQueryHelper( $groupDefinition, $input ) {
                $ctx = $this->createMock( IContextSource::class );
index a7cf755..3be2b06 100644 (file)
@@ -173,8 +173,6 @@ abstract class GenericArrayObjectTest extends PHPUnit\Framework\TestCase {
         * @since 1.20
         *
         * @param callable $function
-        *
-        * @covers GenericArrayObject::getObjectType
         */
        protected function checkTypeChecks( $function ) {
                $excption = null;
@@ -206,7 +204,7 @@ abstract class GenericArrayObjectTest extends PHPUnit\Framework\TestCase {
         * @since 1.20
         *
         * @param array $elements
-        *
+        * @covers GenericArrayObject::getObjectType
         * @covers GenericArrayObject::offsetSet
         */
        public function testOffsetSet( array $elements ) {
index 6a75181..9702c82 100644 (file)
@@ -16,7 +16,7 @@ class IPTest extends PHPUnit\Framework\TestCase {
         * @covers IP::isIPAddress
         * @dataProvider provideInvalidIPs
         */
-       public function isNotIPAddress( $val, $desc ) {
+       public function testIsNotIPAddress( $val, $desc ) {
                $this->assertFalse( IP::isIPAddress( $val ), $desc );
        }
 
index 23225b6..05ae2a3 100644 (file)
@@ -20,7 +20,7 @@ class ComposerInstalledTest extends MediaWikiTestCase {
                'leafo/lessphp' => [
                        'version' => '0.5.0',
                        'type' => 'library',
-                       'licenses' => [ 'MIT', 'GPL-3.0' ],
+                       'licenses' => [ 'MIT', 'GPL-3.0-only' ],
                        'authors' => [
                                [
                                        'name' => 'Leaf Corcoran',
index eef7e27..dc81e1d 100644 (file)
@@ -20,7 +20,7 @@ class ComposerLockTest extends MediaWikiTestCase {
                        'wikimedia/cdb' => [
                                'version' => '1.0.1',
                                'type' => 'library',
-                               'licenses' => [ 'GPL-2.0' ],
+                               'licenses' => [ 'GPL-2.0-only' ],
                                'authors' => [
                                        [
                                                'name' => 'Tim Starling',
@@ -44,7 +44,7 @@ class ComposerLockTest extends MediaWikiTestCase {
                        'leafo/lessphp' => [
                                'version' => '0.5.0',
                                'type' => 'library',
-                               'licenses' => [ 'MIT', 'GPL-3.0' ],
+                               'licenses' => [ 'MIT', 'GPL-3.0-only' ],
                                'authors' => [
                                        [
                                                'name' => 'Leaf Corcoran',
@@ -89,7 +89,7 @@ class ComposerLockTest extends MediaWikiTestCase {
                        'mediawiki/translate' => [
                                'version' => '2014.12',
                                'type' => 'mediawiki-extension',
-                               'licenses' => [ 'GPL-2.0+' ],
+                               'licenses' => [ 'GPL-2.0-or-later' ],
                                'authors' => [
                                        [
                                                'name' => 'Niklas Laxström',
@@ -109,7 +109,7 @@ class ComposerLockTest extends MediaWikiTestCase {
                        'mediawiki/universal-language-selector' => [
                                'version' => '2014.12',
                                'type' => 'mediawiki-extension',
-                               'licenses' => [ 'GPL-2.0+', 'MIT' ],
+                               'licenses' => [ 'GPL-2.0-or-later', 'MIT' ],
                                'authors' => [],
                                'description' => 'The primary aim is to allow users to select a language ' .
                                        'and configure its support in an easy way. ' .
index 6367a0f..53b659f 100644 (file)
@@ -1390,7 +1390,7 @@ more stuff
         * @covers WikiPage::newFromID
         */
        public function testNewFromId_returnsNullOnNonExistingId() {
-               $this->assertNull( WikiPage::newFromID( 73574757437437743743 ) );
+               $this->assertNull( WikiPage::newFromID( 2147483647 ) );
        }
 
        public function provideTestInsertProtectNullRevision() {
diff --git a/tests/selenium/wdio.conf.beta.js b/tests/selenium/wdio.conf.beta.js
new file mode 100644 (file)
index 0000000..8f5c2c7
--- /dev/null
@@ -0,0 +1,21 @@
+'use strict';
+const merge = require( 'deepmerge' ),
+       username = 'Selenium user',
+       wdioConf = require( './wdio.conf.js' );
+
+// Overwrite default settings
+exports.config = merge( wdioConf.config, {
+       username: process.env.MEDIAWIKI_USER === undefined ?
+               username :
+               process.env.MEDIAWIKI_USER,
+       password: process.env.MEDIAWIKI_PASSWORD,
+       baseUrl: (
+               process.env.MW_SERVER === undefined ?
+                       'https://en.wikipedia.beta.wmflabs.org:443' :
+                       process.env.MW_SERVER
+       ) + (
+               process.env.MW_SCRIPT_PATH === undefined ?
+                       '/w' :
+                       process.env.MW_SCRIPT_PATH
+       )
+} );