Merge "QA: Do not mention Wikimedia Foundation wikis in browser tests"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Fri, 26 Sep 2014 19:52:42 +0000 (19:52 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Fri, 26 Sep 2014 19:52:42 +0000 (19:52 +0000)
17 files changed:
COPYING
includes/MediaWiki.php
includes/api/ApiPageSet.php
includes/api/ApiQueryBacklinksprop.php
includes/api/ApiQueryCategoryInfo.php
includes/api/ApiQueryDuplicateFiles.php
includes/api/ApiQueryImageInfo.php
includes/context/RequestContext.php
includes/json/FormatJson.php
languages/Language.php
languages/i18n/en.json
languages/i18n/qqq.json
resources/src/mediawiki.action/mediawiki.action.edit.styles.css [changed mode: 0755->0644]
resources/src/mediawiki.action/mediawiki.action.history.diff.css [changed mode: 0755->0644]
resources/src/mediawiki.skinning/interface.css [changed mode: 0755->0644]
tests/phpunit/includes/json/FormatJsonTest.php
tests/qunit/suites/resources/startup.test.js

diff --git a/COPYING b/COPYING
index c3bed28..1cdc9d4 100644 (file)
--- a/COPYING
+++ b/COPYING
@@ -30,8 +30,10 @@ under the GPL for use of the whole code or other sections thereof.
 MediaWiki uses the following Creative Commons icons to illustrate links to the
 CC licenses:
 
-* skins/common/images/cc-by-nc-sa.png
-* skins/common/images/cc-by-sa.png
+* resources/assets/licenses/cc-0.png
+* resources/assets/licenses/cc-by-nc-sa.png
+* resources/assets/licenses/cc-by-sa.png
+* resources/assets/licenses/cc-by.png
 
 These icons are trademarked, and used subject to the CC trademark license,
 available at http://creativecommons.org/policies#trademark
index 545a46f..87468bd 100644 (file)
@@ -121,7 +121,7 @@ class MediaWiki {
         * @return Title
         */
        public function getTitle() {
-               if ( $this->context->getTitle() === null ) {
+               if ( !$this->context->hasTitle() ) {
                        $this->context->setTitle( $this->parseTitle() );
                }
                return $this->context->getTitle();
index 0f26467..3bdecaa 100644 (file)
@@ -53,7 +53,10 @@ class ApiPageSet extends ApiBase {
 
        private $mAllPages = array(); // [ns][dbkey] => page_id or negative when missing
        private $mTitles = array();
+       private $mGoodAndMissingPages = array(); // [ns][dbkey] => page_id or negative when missing
+       private $mGoodPages = array(); // [ns][dbkey] => page_id
        private $mGoodTitles = array();
+       private $mMissingPages = array(); // [ns][dbkey] => fake page_id
        private $mMissingTitles = array();
        private $mInvalidTitles = array();
        private $mMissingPageIDs = array();
@@ -343,6 +346,14 @@ class ApiPageSet extends ApiBase {
                return count( $this->mTitles );
        }
 
+       /**
+        * Returns an array [ns][dbkey] => page_id for all good titles.
+        * @return array
+        */
+       public function getGoodTitlesByNamespace() {
+               return $this->mGoodPages;
+       }
+
        /**
         * Title objects that were found in the database.
         * @return Title[] Array page_id (int) => Title (obj)
@@ -359,6 +370,15 @@ class ApiPageSet extends ApiBase {
                return count( $this->mGoodTitles );
        }
 
+       /**
+        * Returns an array [ns][dbkey] => fake_page_id for all missing titles.
+        * fake_page_id is a unique negative number.
+        * @return array
+        */
+       public function getMissingTitlesByNamespace() {
+               return $this->mMissingPages;
+       }
+
        /**
         * Title objects that were NOT found in the database.
         * The array's index will be negative for each item
@@ -368,6 +388,22 @@ class ApiPageSet extends ApiBase {
                return $this->mMissingTitles;
        }
 
+       /**
+        * Returns an array [ns][dbkey] => page_id for all good and missing titles.
+        * @return array
+        */
+       public function getGoodAndMissingTitlesByNamespace() {
+               return $this->mGoodAndMissingPages;
+       }
+
+       /**
+        * Title objects for good and missing titles.
+        * @return array
+        */
+       public function getGoodAndMissingTitles() {
+               return $this->mGoodTitles + $this->mMissingTitles;
+       }
+
        /**
         * Titles that were deemed invalid by Title::newFromText()
         * The array's index will be unique and negative for each item
@@ -667,6 +703,8 @@ class ApiPageSet extends ApiBase {
                if ( $this->mResolveRedirects && $row->page_is_redirect == '1' ) {
                        $this->mPendingRedirectIDs[$pageId] = $title;
                } else {
+                       $this->mGoodPages[$row->page_namespace][$row->page_title] = $pageId;
+                       $this->mGoodAndMissingPages[$row->page_namespace][$row->page_title] = $pageId;
                        $this->mGoodTitles[$pageId] = $title;
                }
 
@@ -803,6 +841,8 @@ class ApiPageSet extends ApiBase {
                                        foreach ( array_keys( $dbkeys ) as $dbkey ) {
                                                $title = Title::makeTitle( $ns, $dbkey );
                                                $this->mAllPages[$ns][$dbkey] = $this->mFakePageId;
+                                               $this->mMissingPages[$ns][$dbkey] = $this->mFakePageId;
+                                               $this->mGoodAndMissingPages[$ns][$dbkey] = $this->mFakePageId;
                                                $this->mMissingTitles[$this->mFakePageId] = $title;
                                                $this->mFakePageId--;
                                                $this->mTitles[] = $title;
index cd68261..2458a26 100644 (file)
@@ -106,8 +106,8 @@ class ApiQueryBacklinksprop extends ApiQueryGeneratorBase {
                $emptyString = $db->addQuotes( '' );
 
                $pageSet = $this->getPageSet();
-               $titles = $pageSet->getGoodTitles() + $pageSet->getMissingTitles();
-               $map = $pageSet->getAllTitlesByNamespace();
+               $titles = $pageSet->getGoodAndMissingTitles();
+               $map = $pageSet->getGoodAndMissingTitlesByNamespace();
 
                // Determine our fields to query on
                $p = $settings['prefix'];
index 6e9f33c..3dd4c65 100644 (file)
@@ -38,14 +38,13 @@ class ApiQueryCategoryInfo extends ApiQueryBase {
 
        public function execute() {
                $params = $this->extractRequestParams();
-               $alltitles = $this->getPageSet()->getAllTitlesByNamespace();
+               $alltitles = $this->getPageSet()->getGoodAndMissingTitlesByNamespace();
                if ( empty( $alltitles[NS_CATEGORY] ) ) {
                        return;
                }
                $categories = $alltitles[NS_CATEGORY];
 
-               $titles = $this->getPageSet()->getGoodTitles() +
-                       $this->getPageSet()->getMissingTitles();
+               $titles = $this->getPageSet()->getGoodAndMissingTitles();
                $cattitles = array();
                foreach ( $categories as $c ) {
                        /** @var $t Title */
index 6d836cd..2212957 100644 (file)
@@ -52,7 +52,7 @@ class ApiQueryDuplicateFiles extends ApiQueryGeneratorBase {
         */
        private function run( $resultPageSet = null ) {
                $params = $this->extractRequestParams();
-               $namespaces = $this->getPageSet()->getAllTitlesByNamespace();
+               $namespaces = $this->getPageSet()->getGoodAndMissingTitlesByNamespace();
                if ( empty( $namespaces[NS_FILE] ) ) {
                        return;
                }
index 945374b..ad5cdbd 100644 (file)
@@ -58,7 +58,7 @@ class ApiQueryImageInfo extends ApiQueryBase {
                        'revdelUser' => $this->getUser(),
                );
 
-               $pageIds = $this->getPageSet()->getAllTitlesByNamespace();
+               $pageIds = $this->getPageSet()->getGoodAndMissingTitlesByNamespace();
                if ( !empty( $pageIds[NS_FILE] ) ) {
                        $titles = array_keys( $pageIds[NS_FILE] );
                        asort( $titles ); // Ensure the order is always the same
index 952af8c..b1bebe7 100644 (file)
@@ -146,6 +146,16 @@ class RequestContext implements IContextSource {
                return $this->title;
        }
 
+       /**
+        * Check, if a Title object is set
+        *
+        * @since 1.25
+        * @return bool
+        */
+       public function hasTitle() {
+               return $this->title !== null;
+       }
+
        /**
         * Check whether a WikiPage object can be get with getWikiPage().
         * Callers should expect that an exception is thrown from getWikiPage()
index e45dd3a..5565644 100644 (file)
@@ -54,6 +54,15 @@ class FormatJson {
         */
        const ALL_OK = 3;
 
+       /**
+        * If set, treat json objects '{...}' as associative arrays. Without this option,
+        * json objects will be converted to stdClass.
+        * The value is set to 1 to be backward compatible with 'true' that was used before.
+        *
+        * @since 1.24
+        */
+       const FORCE_ASSOC = 1;
+
        /**
         * Regex that matches whitespace inside empty arrays and objects.
         *
@@ -127,6 +136,52 @@ class FormatJson {
                return json_decode( $value, $assoc );
        }
 
+       /**
+        * Decodes a JSON string.
+        *
+        * @param string $value The JSON string being decoded
+        * @param int $options A bit field that allows FORCE_ASSOC, TRY_FIXING, WRAP_RESULT
+        * For backward compatibility, FORCE_ASSOC is set to 1 to match the legacy 'true'
+        * @return Status If good, the value is available in $result->getValue()
+        */
+       public static function parse( $value, $options = 0 ) {
+               $assoc = ( $options & self::FORCE_ASSOC ) !== 0;
+               $result = json_decode( $value, $assoc );
+               $code = json_last_error();
+
+               switch ( $code ) {
+                       case JSON_ERROR_NONE:
+                               return Status::newGood( $result );
+                       default:
+                               return Status::newFatal( wfMessage( 'json-error-unknown' )->numParams( $code ) );
+                       case JSON_ERROR_DEPTH:
+                               $msg = 'json-error-depth';
+                               break;
+                       case JSON_ERROR_STATE_MISMATCH:
+                               $msg = 'json-error-state-mismatch';
+                               break;
+                       case JSON_ERROR_CTRL_CHAR:
+                               $msg = 'json-error-ctrl-char';
+                               break;
+                       case JSON_ERROR_SYNTAX:
+                               $msg = 'json-error-syntax';
+                               break;
+                       case JSON_ERROR_UTF8:
+                               $msg = 'json-error-utf8';
+                               break;
+                       case JSON_ERROR_RECURSION:
+                               $msg = 'json-error-recursion';
+                               break;
+                       case JSON_ERROR_INF_OR_NAN:
+                               $msg = 'json-error-inf-or-nan';
+                               break;
+                       case JSON_ERROR_UNSUPPORTED_TYPE:
+                               $msg = 'json-error-unsupported-type';
+                               break;
+               }
+               return Status::newFatal( $msg );
+       }
+
        /**
         * JSON encoder wrapper for PHP >= 5.4, which supports useful encoding options.
         *
index b985077..fb04255 100644 (file)
@@ -3209,7 +3209,7 @@ class Language {
 
        /**
         * Get special page names, as an associative array
-        *   case folded alias => real name
+        *   canonical name => array of valid names, including aliases
         * @return array
         */
        function getSpecialPageAliases() {
index 12d1429..e8a5c3c 100644 (file)
        "mediastatistics-header-office": "Office",
        "mediastatistics-header-text": "Textual",
        "mediastatistics-header-executable": "Executables",
-       "mediastatistics-header-archive": "Compressed formats"
+       "mediastatistics-header-archive": "Compressed formats",
+       "json-error-unknown": "There was a problem with the JSON. Error: $1",
+       "json-error-depth": "The maximum stack depth has been exceeded",
+       "json-error-state-mismatch": "Invalid or malformed JSON",
+       "json-error-ctrl-char": "Control character error, possibly incorrectly encoded",
+       "json-error-syntax": "Syntax error",
+       "json-error-utf8": "Malformed UTF-8 characters, possibly incorrectly encoded",
+       "json-error-recursion": "One or more recursive references in the value to be encoded",
+       "json-error-inf-or-nan": "One or more NAN or INF values in the value to be encoded",
+       "json-error-unsupported-type": "A value of a type that cannot be encoded was given"
 }
index d480e2d..2049ae5 100644 (file)
        "mediastatistics-header-office": "Header on [[Special:MediaStatistics]] for file types that are in the Office category. This includes PDFs, OpenDocument files, Microsoft Word files, etc.",
        "mediastatistics-header-text": "Header on [[Special:MediaStatistics]] for file types that are in the text category. This includes simple text formats, including plain text formats, json, csv, and xml. Source code of compiled programming languages may be included here in the future, but isn't currently.",
        "mediastatistics-header-executable": "Header on [[Special:MediaStatistics]] for file types that are in the executable category. This includes things like source files for interpreted programming language (Shell scripts, javascript, etc).",
-       "mediastatistics-header-archive": "Header on [[Special:MediaStatistics]] for file types that are in the archive category. Includes things like tar, zip, gzip etc."
+       "mediastatistics-header-archive": "Header on [[Special:MediaStatistics]] for file types that are in the archive category. Includes things like tar, zip, gzip etc.",
+       "json-error-unknown": "User error message when there’s an unknown error.\n{{Identical|Unknown error}}. This error is shown if we received an unexpected value from PHP. See http://php.net/manual/en/function.json-last-error.php\n\nParameters:\n* $1 - integer error code",
+       "json-error-depth": "User error message when the maximum stack depth is exceeded.\nSee http://php.net/manual/en/function.json-last-error.php",
+       "json-error-state-mismatch": "User error message when underflow or the modes mismatch.\n\n'''Underflow''': A data-processing error arising when the absolute value of a computed quantity is smaller than the limits of precision of the computing device, retaining at least one significant digit.\nSee http://php.net/manual/en/function.json-last-error.php",
+       "json-error-ctrl-char": "User error message when an unexpected control character has been found.\nSee http://php.net/manual/en/function.json-last-error.php",
+       "json-error-syntax": "User error message when there is a syntax error; a malformed JSON.\nSee http://php.net/manual/en/function.json-last-error.php",
+       "json-error-utf8": "User error message when there are malformed UTF-8 characters, possibly incorrectly encoded.\nSee http://php.net/manual/en/function.json-last-error.php",
+       "json-error-recursion": "PHP JSON encoding/decoding error. See http://php.net/manual/en/function.json-last-error.php",
+       "json-error-inf-or-nan": "PHP JSON encoding/decoding error. See http://php.net/manual/en/function.json-last-error.php",
+       "json-error-unsupported-type": "PHP JSON encoding/decoding error. See http://php.net/manual/en/function.json-last-error.php"
 }
old mode 100755 (executable)
new mode 100644 (file)
index bf58ee3..0f1cdf7 100644 (file)
@@ -123,6 +123,69 @@ class FormatJsonTest extends MediaWikiTestCase {
                );
        }
 
+       public static function provideParse() {
+               return array(
+                       array( null ),
+                       array( true ),
+                       array( false ),
+                       array( 0 ),
+                       array( 1 ),
+                       array( 1.2 ),
+                       array( '' ),
+                       array( 'str' ),
+                       array( array( 0, 1, 2 ) ),
+                       array( array( 'a' => 'b' ) ),
+                       array( array( 'a' => 'b' ) ),
+                       array( array( 'a' => 'b', 'x' => array( 'c' => 'd' ) ) ),
+               );
+       }
+
+       /**
+        * Recursively convert arrays into stdClass
+        * @param array|string|bool|int|float|null $value
+        * @return stdClass|string|bool|int|float|null
+        */
+       public static function toObject( $value ) {
+               return !is_array( $value ) ? $value : (object) array_map( __METHOD__, $value );
+       }
+
+       /**
+        * @dataProvider provideParse
+        * @param mixed $value
+        */
+       public function testParse( $value ) {
+               $expected = self::toObject( $value );
+               $json = FormatJson::encode( $expected, false, FormatJson::ALL_OK );
+               $this->assertJson( $json );
+
+               $st = FormatJson::parse( $json );
+               $this->assertType( 'Status', $st );
+               $this->assertTrue( $st->isGood() );
+               $this->assertEquals( $expected, $st->getValue() );
+
+               $st = FormatJson::parse( $json, FormatJson::FORCE_ASSOC );
+               $this->assertType( 'Status', $st );
+               $this->assertTrue( $st->isGood() );
+               $this->assertEquals( $value, $st->getValue() );
+       }
+
+       public static function provideParseErrors() {
+               return array(
+                       array( 'aaa' ),
+                       array( '{"j": 1 ] }' ),
+               );
+       }
+
+       /**
+        * @dataProvider provideParseErrors
+        * @param mixed $value
+        */
+       public function testParseErrors( $value ) {
+               $st = FormatJson::parse( $value );
+               $this->assertType( 'Status', $st );
+               $this->assertFalse( $st->isOK() );
+       }
+
        /**
         * Generate a set of test cases for a particular combination of encoder options.
         *
index ed03418..6011961 100644 (file)
@@ -96,6 +96,7 @@
                        'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.7) Gecko/20060928 (Debian|Debian-1.8.0.7-1) Epiphany/2.14',
                        'Mozilla/5.0 (X11; U; Linux i686 (x86_64); en-US; rv:1.8.1.6) Gecko/20070817 IceWeasel/2.0.0.6-g2',
                        // KHTML
+                       'Mozilla/5.0 (compatible; Konqueror/3.5; Linux) KHTML/3.5.4 (like Gecko)',
                        'Mozilla/5.0 (compatible; Konqueror/4.3; Linux) KHTML/4.3.5 (like Gecko)',
                        // Text browsers
                        'Links (2.1pre33; Darwin 8.11.0 Power Macintosh; x)',