Merge "CSSMin: Re-introduce whitespace mangling in embedded SVGs"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Tue, 9 Jan 2018 17:44:56 +0000 (17:44 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Tue, 9 Jan 2018 17:44:56 +0000 (17:44 +0000)
14 files changed:
autoload.php
docs/hooks.txt
includes/DefaultSettings.php
includes/ServiceWiring.php
includes/api/ApiErrorFormatter.php
includes/dao/DBAccessBase.php
includes/export/BaseDump.php [new file with mode: 0644]
includes/specials/SpecialEditWatchlist.php
includes/watcheditem/NoWriteWatchedItemStore.php [new file with mode: 0644]
maintenance/backupPrefetch.inc [deleted file]
maintenance/dumpTextPass.php
tests/phan/config.php
tests/phpunit/includes/watcheditem/NoWriteWatchedItemStoreUnitTest.php [new file with mode: 0644]
tests/phpunit/maintenance/backupPrefetchTest.php

index 351136d..4a50894 100644 (file)
@@ -175,7 +175,7 @@ $wgAutoloadLocalClasses = [
        'BadRequestError' => __DIR__ . '/includes/exception/BadRequestError.php',
        'BadTitleError' => __DIR__ . '/includes/exception/BadTitleError.php',
        'BagOStuff' => __DIR__ . '/includes/libs/objectcache/BagOStuff.php',
-       'BaseDump' => __DIR__ . '/maintenance/backupPrefetch.inc',
+       'BaseDump' => __DIR__ . '/includes/export/BaseDump.php',
        'BaseTemplate' => __DIR__ . '/includes/skins/BaseTemplate.php',
        'BashkirUppercaseCollation' => __DIR__ . '/includes/collation/BashkirUppercaseCollation.php',
        'BatchRowIterator' => __DIR__ . '/includes/utils/BatchRowIterator.php',
@@ -1048,6 +1048,7 @@ $wgAutoloadLocalClasses = [
        'NewFilesPager' => __DIR__ . '/includes/specials/pagers/NewFilesPager.php',
        'NewPagesPager' => __DIR__ . '/includes/specials/pagers/NewPagesPager.php',
        'NewUsersLogFormatter' => __DIR__ . '/includes/logging/NewUsersLogFormatter.php',
+       'NoWriteWatchedItemStore' => __DIR__ . '/includes/watcheditem/NoWriteWatchedItemStore.php',
        'NolinesImageGallery' => __DIR__ . '/includes/gallery/NolinesImageGallery.php',
        'NorthernSamiUppercaseCollation' => __DIR__ . '/includes/collation/NorthernSamiUppercaseCollation.php',
        'NotRecursiveIterator' => __DIR__ . '/includes/libs/iterators/NotRecursiveIterator.php',
index 45387a3..2c6fc02 100644 (file)
@@ -3917,14 +3917,15 @@ dumps. One, and only one hook should set this, and return false.
 &$opts: Options to use for the query
 &$join: Join conditions
 
-'WikiPageDeletionUpdates': manipulate the list of DataUpdates to be applied when
+'WikiPageDeletionUpdates': manipulate the list of DeferrableUpdates to be applied when
 a page is deleted. Called in WikiPage::getDeletionUpdates(). Note that updates
 specific to a content model should be provided by the respective Content's
 getDeletionUpdates() method.
 $page: the WikiPage
-$content: the Content to generate updates for (or null, if the Content could not be loaded
-due to an error)
-&$updates: the array of DataUpdate objects. Hook function may want to add to it.
+$content: the Content to generate updates for, or null in case the page revision could not be
+  loaded. The delete will succeed despite this.
+&$updates: the array of objects that implement DeferrableUpdate. Hook function may want to add to
+  it.
 
 'WikiPageFactory': Override WikiPage class used for a title
 $title: Title of the page
index 8091428..ee10a6d 100644 (file)
@@ -6623,6 +6623,13 @@ $wgCommandLineDarkBg = false;
  */
 $wgReadOnly = null;
 
+/**
+ * Set this to true to put the wiki watchlists into read-only mode.
+ * @var bool
+ * @since 1.31
+ */
+$wgReadOnlyWatchedItemStore = false;
+
 /**
  * If this lock file exists (size > 0), the wiki will be forced into read-only mode.
  * Its contents will be shown to users as part of the read-only warning
index 246b838..79e5b84 100644 (file)
@@ -166,6 +166,11 @@ return [
                        $services->getReadOnlyMode()
                );
                $store->setStatsdDataFactory( $services->getStatsdDataFactory() );
+
+               if ( $services->getMainConfig()->get( 'ReadOnlyWatchedItemStore' ) ) {
+                       $store = new NoWriteWatchedItemStore( $store );
+               }
+
                return $store;
        },
 
index 1749ce7..c637752 100644 (file)
@@ -112,7 +112,7 @@ class ApiErrorFormatter {
         * Add warnings and errors from a StatusValue object to the result
         * @param string|null $modulePath
         * @param StatusValue $status
-        * @param string[] $types 'warning' and/or 'error'
+        * @param string[]|string $types 'warning' and/or 'error'
         */
        public function addMessagesFromStatus(
                $modulePath, StatusValue $status, $types = [ 'warning', 'error' ]
index 0f8d7f7..6e171d5 100644 (file)
@@ -1,6 +1,6 @@
 <?php
 
-use Wikimedia\Rdbms\Database;
+use Wikimedia\Rdbms\IDatabase;
 use Wikimedia\Rdbms\LoadBalancer;
 
 /**
@@ -56,7 +56,7 @@ abstract class DBAccessBase implements IDBAccessObject {
         * @param int $id Which connection to use
         * @param array $groups Query groups
         *
-        * @return Database
+        * @return IDatabase
         */
        protected function getConnection( $id, $groups = [] ) {
                $loadBalancer = wfGetLB( $this->wiki );
@@ -71,9 +71,9 @@ abstract class DBAccessBase implements IDBAccessObject {
         *
         * @since 1.21
         *
-        * @param Database $db The database connection to release.
+        * @param IDatabase $db The database connection to release.
         */
-       protected function releaseConnection( Database $db ) {
+       protected function releaseConnection( IDatabase $db ) {
                if ( $this->wiki !== false ) {
                        $loadBalancer = $this->getLoadBalancer();
                        $loadBalancer->reuseConnection( $db );
diff --git a/includes/export/BaseDump.php b/includes/export/BaseDump.php
new file mode 100644 (file)
index 0000000..6a2d3bf
--- /dev/null
@@ -0,0 +1,219 @@
+<?php
+/**
+ * Helper class for the --prefetch option of dumpTextPass.php
+ *
+ * Copyright © 2005 Brion Vibber <brion@pobox.com>
+ * https://www.mediawiki.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Maintenance
+ */
+
+/**
+ * Readahead helper for making large MediaWiki data dumps;
+ * reads in a previous XML dump to sequentially prefetch text
+ * records already normalized and decompressed.
+ *
+ * This can save load on the external database servers, hopefully.
+ *
+ * Assumes that dumps will be recorded in the canonical order:
+ * - ascending by page_id
+ * - ascending by rev_id within each page
+ * - text contents are immutable and should not change once
+ *   recorded, so the previous dump is a reliable source
+ *
+ * @ingroup Maintenance
+ */
+class BaseDump {
+       /** @var XMLReader */
+       protected $reader = null;
+       protected $atEnd = false;
+       protected $atPageEnd = false;
+       protected $lastPage = 0;
+       protected $lastRev = 0;
+       protected $infiles = null;
+
+       public function __construct( $infile ) {
+               $this->infiles = explode( ';', $infile );
+               $this->reader = new XMLReader();
+               $infile = array_shift( $this->infiles );
+               if ( defined( 'LIBXML_PARSEHUGE' ) ) {
+                       $this->reader->open( $infile, null, LIBXML_PARSEHUGE );
+               } else {
+                       $this->reader->open( $infile );
+               }
+       }
+
+       /**
+        * Attempts to fetch the text of a particular page revision
+        * from the dump stream. May return null if the page is
+        * unavailable.
+        *
+        * @param int $page ID number of page to read
+        * @param int $rev ID number of revision to read
+        * @return string|null
+        */
+       function prefetch( $page, $rev ) {
+               $page = intval( $page );
+               $rev = intval( $rev );
+               while ( $this->lastPage < $page && !$this->atEnd ) {
+                       $this->debug( "BaseDump::prefetch at page $this->lastPage, looking for $page" );
+                       $this->nextPage();
+               }
+               if ( $this->lastPage > $page || $this->atEnd ) {
+                       $this->debug( "BaseDump::prefetch already past page $page "
+                               . "looking for rev $rev  [$this->lastPage, $this->lastRev]" );
+
+                       return null;
+               }
+               while ( $this->lastRev < $rev && !$this->atEnd && !$this->atPageEnd ) {
+                       $this->debug( "BaseDump::prefetch at page $this->lastPage, rev $this->lastRev, "
+                               . "looking for $page, $rev" );
+                       $this->nextRev();
+               }
+               if ( $this->lastRev == $rev && !$this->atEnd ) {
+                       $this->debug( "BaseDump::prefetch hit on $page, $rev [$this->lastPage, $this->lastRev]" );
+
+                       return $this->nextText();
+               } else {
+                       $this->debug( "BaseDump::prefetch already past rev $rev on page $page "
+                               . "[$this->lastPage, $this->lastRev]" );
+
+                       return null;
+               }
+       }
+
+       function debug( $str ) {
+               wfDebug( $str . "\n" );
+               // global $dumper;
+               // $dumper->progress( $str );
+       }
+
+       /**
+        * @access private
+        */
+       function nextPage() {
+               if ( $this->skipTo( 'page', 'mediawiki' ) ) {
+                       if ( $this->skipTo( 'id' ) ) {
+                               $this->lastPage = intval( $this->nodeContents() );
+                               $this->lastRev = 0;
+                               $this->atPageEnd = false;
+                       }
+               } else {
+                       $this->close();
+                       if ( count( $this->infiles ) ) {
+                               $infile = array_shift( $this->infiles );
+                               $this->reader->open( $infile );
+                               $this->atEnd = false;
+                       }
+               }
+       }
+
+       /**
+        * @access private
+        */
+       function nextRev() {
+               if ( $this->skipTo( 'revision' ) ) {
+                       if ( $this->skipTo( 'id' ) ) {
+                               $this->lastRev = intval( $this->nodeContents() );
+                       }
+               } else {
+                       $this->atPageEnd = true;
+               }
+       }
+
+       /**
+        * @access private
+        * @return string
+        */
+       function nextText() {
+               $this->skipTo( 'text' );
+
+               return strval( $this->nodeContents() );
+       }
+
+       /**
+        * @access private
+        * @param string $name
+        * @param string $parent
+        * @return bool|null
+        */
+       function skipTo( $name, $parent = 'page' ) {
+               if ( $this->atEnd ) {
+                       return false;
+               }
+               while ( $this->reader->read() ) {
+                       if ( $this->reader->nodeType == XMLReader::ELEMENT
+                               && $this->reader->name == $name
+                       ) {
+                               return true;
+                       }
+                       if ( $this->reader->nodeType == XMLReader::END_ELEMENT
+                               && $this->reader->name == $parent
+                       ) {
+                               $this->debug( "BaseDump::skipTo found </$parent> searching for <$name>" );
+
+                               return false;
+                       }
+               }
+
+               return $this->close();
+       }
+
+       /**
+        * Shouldn't something like this be built-in to XMLReader?
+        * Fetches text contents of the current element, assuming
+        * no sub-elements or such scary things.
+        *
+        * @return string
+        * @access private
+        */
+       function nodeContents() {
+               if ( $this->atEnd ) {
+                       return null;
+               }
+               if ( $this->reader->isEmptyElement ) {
+                       return "";
+               }
+               $buffer = "";
+               while ( $this->reader->read() ) {
+                       switch ( $this->reader->nodeType ) {
+                               case XMLReader::TEXT:
+                               // case XMLReader::WHITESPACE:
+                               case XMLReader::SIGNIFICANT_WHITESPACE:
+                                       $buffer .= $this->reader->value;
+                                       break;
+                               case XMLReader::END_ELEMENT:
+                                       return $buffer;
+                       }
+               }
+
+               return $this->close();
+       }
+
+       /**
+        * @access private
+        * @return null
+        */
+       function close() {
+               $this->reader->close();
+               $this->atEnd = true;
+
+               return null;
+       }
+}
index d2940e4..09ea9ea 100644 (file)
@@ -29,6 +29,7 @@
 use MediaWiki\Linker\LinkRenderer;
 use MediaWiki\Linker\LinkTarget;
 use MediaWiki\MediaWikiServices;
+use Wikimedia\Rdbms\DBReadOnlyError;
 
 /**
  * Provides the UI through which users can perform editing
@@ -451,6 +452,10 @@ class SpecialEditWatchlist extends UnlistedSpecialPage {
         * Remove all titles from a user's watchlist
         */
        private function clearWatchlist() {
+               if ( $this->getConfig()->get( 'ReadOnlyWatchedItemStore' ) ) {
+                       throw new DBReadOnlyError( null, 'The watchlist is currently readonly.' );
+               }
+
                $dbw = wfGetDB( DB_MASTER );
                $dbw->delete(
                        'watchlist',
diff --git a/includes/watcheditem/NoWriteWatchedItemStore.php b/includes/watcheditem/NoWriteWatchedItemStore.php
new file mode 100644 (file)
index 0000000..1439421
--- /dev/null
@@ -0,0 +1,134 @@
+<?php
+/**
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ * @ingroup Watchlist
+ */
+use MediaWiki\Linker\LinkTarget;
+use Wikimedia\Rdbms\DBReadOnlyError;
+
+/**
+ * @internal
+ * @since 1.31
+ */
+class NoWriteWatchedItemStore implements WatchedItemStoreInterface {
+
+       /**
+        * @var WatchedItemStoreInterface
+        */
+       private $actualStore;
+
+       /**
+        * Initialy set WatchedItemStore that will be used in cases where writing is not needed.
+        * @param WatchedItemStoreInterface $actualStore
+        */
+       public function __construct( WatchedItemStoreInterface $actualStore ) {
+               $this->actualStore = $actualStore;
+       }
+
+       public function countWatchedItems( User $user ) {
+               return $this->actualStore->countWatchedItems( $user );
+       }
+
+       public function countWatchers( LinkTarget $target ) {
+               return $this->actualStore->countWatchers( $target );
+       }
+
+       public function countVisitingWatchers( LinkTarget $target, $threshold ) {
+               return $this->actualStore->countVisitingWatchers( $target, $threshold );
+       }
+
+       public function countWatchersMultiple( array $targets, array $options = [] ) {
+               return $this->actualStore->countVisitingWatchersMultiple( $targets, $options );
+       }
+
+       public function countVisitingWatchersMultiple(
+               array $targetsWithVisitThresholds,
+               $minimumWatchers = null
+       ) {
+               return $this->actualStore->countVisitingWatchersMultiple(
+                       $targetsWithVisitThresholds,
+                       $minimumWatchers
+               );
+       }
+
+       public function getWatchedItem( User $user, LinkTarget $target ) {
+               return $this->actualStore->getWatchedItem( $user, $target );
+       }
+
+       public function loadWatchedItem( User $user, LinkTarget $target ) {
+               return $this->actualStore->loadWatchedItem( $user, $target );
+       }
+
+       public function getWatchedItemsForUser( User $user, array $options = [] ) {
+               return $this->actualStore->getWatchedItemsForUser( $user, $options );
+       }
+
+       public function isWatched( User $user, LinkTarget $target ) {
+               return $this->actualStore->isWatched( $user, $target );
+       }
+
+       public function getNotificationTimestampsBatch( User $user, array $targets ) {
+               return $this->actualStore->getNotificationTimestampsBatch( $user, $targets );
+       }
+
+       public function countUnreadNotifications( User $user, $unreadLimit = null ) {
+               return $this->actualStore->countUnreadNotifications( $user, $unreadLimit );
+       }
+
+       public function duplicateAllAssociatedEntries( LinkTarget $oldTarget, LinkTarget $newTarget ) {
+               throw new DBReadOnlyError( null, 'The watchlist is currently readonly.' );
+       }
+
+       public function duplicateEntry( LinkTarget $oldTarget, LinkTarget $newTarget ) {
+               throw new DBReadOnlyError( null, 'The watchlist is currently readonly.' );
+       }
+
+       public function addWatch( User $user, LinkTarget $target ) {
+               throw new DBReadOnlyError( null, 'The watchlist is currently readonly.' );
+       }
+
+       public function addWatchBatchForUser( User $user, array $targets ) {
+               throw new DBReadOnlyError( null, 'The watchlist is currently readonly.' );
+       }
+
+       public function removeWatch( User $user, LinkTarget $target ) {
+               throw new DBReadOnlyError( null, 'The watchlist is currently readonly.' );
+       }
+
+       public function setNotificationTimestampsForUser(
+               User $user,
+               $timestamp,
+               array $targets = []
+       ) {
+               throw new DBReadOnlyError( null, 'The watchlist is currently readonly.' );
+       }
+
+       public function updateNotificationTimestamp( User $editor, LinkTarget $target, $timestamp ) {
+               throw new DBReadOnlyError( null, 'The watchlist is currently readonly.' );
+       }
+
+       public function resetNotificationTimestamp(
+               User $user,
+               Title $title,
+               $force = '',
+               $oldid = 0
+       ) {
+               throw new DBReadOnlyError( null, 'The watchlist is currently readonly.' );
+       }
+
+}
diff --git a/maintenance/backupPrefetch.inc b/maintenance/backupPrefetch.inc
deleted file mode 100644 (file)
index 6a2d3bf..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-<?php
-/**
- * Helper class for the --prefetch option of dumpTextPass.php
- *
- * Copyright © 2005 Brion Vibber <brion@pobox.com>
- * https://www.mediawiki.org/
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- * http://www.gnu.org/copyleft/gpl.html
- *
- * @file
- * @ingroup Maintenance
- */
-
-/**
- * Readahead helper for making large MediaWiki data dumps;
- * reads in a previous XML dump to sequentially prefetch text
- * records already normalized and decompressed.
- *
- * This can save load on the external database servers, hopefully.
- *
- * Assumes that dumps will be recorded in the canonical order:
- * - ascending by page_id
- * - ascending by rev_id within each page
- * - text contents are immutable and should not change once
- *   recorded, so the previous dump is a reliable source
- *
- * @ingroup Maintenance
- */
-class BaseDump {
-       /** @var XMLReader */
-       protected $reader = null;
-       protected $atEnd = false;
-       protected $atPageEnd = false;
-       protected $lastPage = 0;
-       protected $lastRev = 0;
-       protected $infiles = null;
-
-       public function __construct( $infile ) {
-               $this->infiles = explode( ';', $infile );
-               $this->reader = new XMLReader();
-               $infile = array_shift( $this->infiles );
-               if ( defined( 'LIBXML_PARSEHUGE' ) ) {
-                       $this->reader->open( $infile, null, LIBXML_PARSEHUGE );
-               } else {
-                       $this->reader->open( $infile );
-               }
-       }
-
-       /**
-        * Attempts to fetch the text of a particular page revision
-        * from the dump stream. May return null if the page is
-        * unavailable.
-        *
-        * @param int $page ID number of page to read
-        * @param int $rev ID number of revision to read
-        * @return string|null
-        */
-       function prefetch( $page, $rev ) {
-               $page = intval( $page );
-               $rev = intval( $rev );
-               while ( $this->lastPage < $page && !$this->atEnd ) {
-                       $this->debug( "BaseDump::prefetch at page $this->lastPage, looking for $page" );
-                       $this->nextPage();
-               }
-               if ( $this->lastPage > $page || $this->atEnd ) {
-                       $this->debug( "BaseDump::prefetch already past page $page "
-                               . "looking for rev $rev  [$this->lastPage, $this->lastRev]" );
-
-                       return null;
-               }
-               while ( $this->lastRev < $rev && !$this->atEnd && !$this->atPageEnd ) {
-                       $this->debug( "BaseDump::prefetch at page $this->lastPage, rev $this->lastRev, "
-                               . "looking for $page, $rev" );
-                       $this->nextRev();
-               }
-               if ( $this->lastRev == $rev && !$this->atEnd ) {
-                       $this->debug( "BaseDump::prefetch hit on $page, $rev [$this->lastPage, $this->lastRev]" );
-
-                       return $this->nextText();
-               } else {
-                       $this->debug( "BaseDump::prefetch already past rev $rev on page $page "
-                               . "[$this->lastPage, $this->lastRev]" );
-
-                       return null;
-               }
-       }
-
-       function debug( $str ) {
-               wfDebug( $str . "\n" );
-               // global $dumper;
-               // $dumper->progress( $str );
-       }
-
-       /**
-        * @access private
-        */
-       function nextPage() {
-               if ( $this->skipTo( 'page', 'mediawiki' ) ) {
-                       if ( $this->skipTo( 'id' ) ) {
-                               $this->lastPage = intval( $this->nodeContents() );
-                               $this->lastRev = 0;
-                               $this->atPageEnd = false;
-                       }
-               } else {
-                       $this->close();
-                       if ( count( $this->infiles ) ) {
-                               $infile = array_shift( $this->infiles );
-                               $this->reader->open( $infile );
-                               $this->atEnd = false;
-                       }
-               }
-       }
-
-       /**
-        * @access private
-        */
-       function nextRev() {
-               if ( $this->skipTo( 'revision' ) ) {
-                       if ( $this->skipTo( 'id' ) ) {
-                               $this->lastRev = intval( $this->nodeContents() );
-                       }
-               } else {
-                       $this->atPageEnd = true;
-               }
-       }
-
-       /**
-        * @access private
-        * @return string
-        */
-       function nextText() {
-               $this->skipTo( 'text' );
-
-               return strval( $this->nodeContents() );
-       }
-
-       /**
-        * @access private
-        * @param string $name
-        * @param string $parent
-        * @return bool|null
-        */
-       function skipTo( $name, $parent = 'page' ) {
-               if ( $this->atEnd ) {
-                       return false;
-               }
-               while ( $this->reader->read() ) {
-                       if ( $this->reader->nodeType == XMLReader::ELEMENT
-                               && $this->reader->name == $name
-                       ) {
-                               return true;
-                       }
-                       if ( $this->reader->nodeType == XMLReader::END_ELEMENT
-                               && $this->reader->name == $parent
-                       ) {
-                               $this->debug( "BaseDump::skipTo found </$parent> searching for <$name>" );
-
-                               return false;
-                       }
-               }
-
-               return $this->close();
-       }
-
-       /**
-        * Shouldn't something like this be built-in to XMLReader?
-        * Fetches text contents of the current element, assuming
-        * no sub-elements or such scary things.
-        *
-        * @return string
-        * @access private
-        */
-       function nodeContents() {
-               if ( $this->atEnd ) {
-                       return null;
-               }
-               if ( $this->reader->isEmptyElement ) {
-                       return "";
-               }
-               $buffer = "";
-               while ( $this->reader->read() ) {
-                       switch ( $this->reader->nodeType ) {
-                               case XMLReader::TEXT:
-                               // case XMLReader::WHITESPACE:
-                               case XMLReader::SIGNIFICANT_WHITESPACE:
-                                       $buffer .= $this->reader->value;
-                                       break;
-                               case XMLReader::END_ELEMENT:
-                                       return $buffer;
-                       }
-               }
-
-               return $this->close();
-       }
-
-       /**
-        * @access private
-        * @return null
-        */
-       function close() {
-               $this->reader->close();
-               $this->atEnd = true;
-
-               return null;
-       }
-}
index 0604f48..e18d0b8 100644 (file)
@@ -143,8 +143,6 @@ TEXT
        }
 
        function processOptions() {
-               global $IP;
-
                parent::processOptions();
 
                if ( $this->hasOption( 'buffersize' ) ) {
@@ -152,7 +150,6 @@ TEXT
                }
 
                if ( $this->hasOption( 'prefetch' ) ) {
-                       require_once "$IP/maintenance/backupPrefetch.inc";
                        $url = $this->processFileOpt( $this->getOption( 'prefetch' ) );
                        $this->prefetch = new BaseDump( $url );
                }
index 0df8357..52a565c 100644 (file)
@@ -41,7 +41,6 @@ return [
                [
                        'maintenance/7zip.inc',
                        'maintenance/backup.inc',
-                       'maintenance/backupPrefetch.inc',
                        'maintenance/cleanupTable.inc',
                        'maintenance/CodeCleanerGlobalsPass.inc',
                        'maintenance/commandLine.inc',
diff --git a/tests/phpunit/includes/watcheditem/NoWriteWatchedItemStoreUnitTest.php b/tests/phpunit/includes/watcheditem/NoWriteWatchedItemStoreUnitTest.php
new file mode 100644 (file)
index 0000000..a8761e3
--- /dev/null
@@ -0,0 +1,246 @@
+<?php
+
+/**
+ * @author Addshore
+ *
+ * @covers NoWriteWatchedItemStore
+ */
+class NoWriteWatchedItemStoreUnitTest extends MediaWikiTestCase {
+
+       public function testAddWatch() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->never() )->method( 'addWatch' );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $this->setExpectedException( DBReadOnlyError::class );
+               $noWriteService->addWatch( $this->getTestSysop()->getUser(), new TitleValue( 0, 'Foo' ) );
+       }
+
+       public function testAddWatchBatchForUser() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->never() )->method( 'addWatchBatchForUser' );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $this->setExpectedException( DBReadOnlyError::class );
+               $noWriteService->addWatchBatchForUser( $this->getTestSysop()->getUser(), [] );
+       }
+
+       public function testRemoveWatch() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->never() )->method( 'removeWatch' );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $this->setExpectedException( DBReadOnlyError::class );
+               $noWriteService->removeWatch( $this->getTestSysop()->getUser(), new TitleValue( 0, 'Foo' ) );
+       }
+
+       public function testSetNotificationTimestampsForUser() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->never() )->method( 'setNotificationTimestampsForUser' );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $this->setExpectedException( DBReadOnlyError::class );
+               $noWriteService->setNotificationTimestampsForUser(
+                       $this->getTestSysop()->getUser(),
+                       'timestamp',
+                       []
+               );
+       }
+
+       public function testUpdateNotificationTimestamp() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->never() )->method( 'updateNotificationTimestamp' );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $this->setExpectedException( DBReadOnlyError::class );
+               $noWriteService->updateNotificationTimestamp(
+                       $this->getTestSysop()->getUser(),
+                       new TitleValue( 0, 'Foo' ),
+                       'timestamp'
+               );
+       }
+
+       public function testResetNotificationTimestamp() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->never() )->method( 'resetNotificationTimestamp' );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $this->setExpectedException( DBReadOnlyError::class );
+               $noWriteService->resetNotificationTimestamp(
+                       $this->getTestSysop()->getUser(),
+                       Title::newFromText( 'Foo' )
+               );
+       }
+
+       public function testCountWatchedItems() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->once() )->method( 'countWatchedItems' )->willReturn( __METHOD__ );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $return = $noWriteService->countWatchedItems(
+                       $this->getTestSysop()->getUser()
+               );
+               $this->assertEquals( __METHOD__, $return );
+       }
+
+       public function testCountWatchers() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->once() )->method( 'countWatchers' )->willReturn( __METHOD__ );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $return = $noWriteService->countWatchers(
+                       new TitleValue( 0, 'Foo' )
+               );
+               $this->assertEquals( __METHOD__, $return );
+       }
+
+       public function testCountVisitingWatchers() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->once() )
+                       ->method( 'countVisitingWatchers' )
+                       ->willReturn( __METHOD__ );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $return = $noWriteService->countVisitingWatchers(
+                       new TitleValue( 0, 'Foo' ),
+                       9
+               );
+               $this->assertEquals( __METHOD__, $return );
+       }
+
+       public function testCountWatchersMultiple() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->once() )
+                       ->method( 'countVisitingWatchersMultiple' )
+                       ->willReturn( __METHOD__ );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $return = $noWriteService->countWatchersMultiple(
+                       [ new TitleValue( 0, 'Foo' ) ],
+                       []
+               );
+               $this->assertEquals( __METHOD__, $return );
+       }
+
+       public function testCountVisitingWatchersMultiple() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->once() )
+                       ->method( 'countVisitingWatchersMultiple' )
+                       ->willReturn( __METHOD__ );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $return = $noWriteService->countVisitingWatchersMultiple(
+                       [ [ new TitleValue( 0, 'Foo' ), 99 ] ],
+                       11
+               );
+               $this->assertEquals( __METHOD__, $return );
+       }
+
+       public function testGetWatchedItem() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->once() )->method( 'getWatchedItem' )->willReturn( __METHOD__ );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $return = $noWriteService->getWatchedItem(
+                       $this->getTestSysop()->getUser(),
+                       new TitleValue( 0, 'Foo' )
+               );
+               $this->assertEquals( __METHOD__, $return );
+       }
+
+       public function testLoadWatchedItem() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->once() )->method( 'loadWatchedItem' )->willReturn( __METHOD__ );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $return = $noWriteService->loadWatchedItem(
+                       $this->getTestSysop()->getUser(),
+                       new TitleValue( 0, 'Foo' )
+               );
+               $this->assertEquals( __METHOD__, $return );
+       }
+
+       public function testGetWatchedItemsForUser() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->once() )
+                       ->method( 'getWatchedItemsForUser' )
+                       ->willReturn( __METHOD__ );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $return = $noWriteService->getWatchedItemsForUser(
+                       $this->getTestSysop()->getUser(),
+                       []
+               );
+               $this->assertEquals( __METHOD__, $return );
+       }
+
+       public function testIsWatched() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->once() )->method( 'isWatched' )->willReturn( __METHOD__ );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $return = $noWriteService->isWatched(
+                       $this->getTestSysop()->getUser(),
+                       new TitleValue( 0, 'Foo' )
+               );
+               $this->assertEquals( __METHOD__, $return );
+       }
+
+       public function testGetNotificationTimestampsBatch() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->once() )
+                       ->method( 'getNotificationTimestampsBatch' )
+                       ->willReturn( __METHOD__ );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $return = $noWriteService->getNotificationTimestampsBatch(
+                       $this->getTestSysop()->getUser(),
+                       [ new TitleValue( 0, 'Foo' ) ]
+               );
+               $this->assertEquals( __METHOD__, $return );
+       }
+
+       public function testCountUnreadNotifications() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $innerService->expects( $this->once() )
+                       ->method( 'countUnreadNotifications' )
+                       ->willReturn( __METHOD__ );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $return = $noWriteService->countUnreadNotifications(
+                       $this->getTestSysop()->getUser(),
+                       88
+               );
+               $this->assertEquals( __METHOD__, $return );
+       }
+
+       public function testDuplicateAllAssociatedEntries() {
+               /** @var WatchedItemStoreInterface|PHPUnit_Framework_MockObject_MockObject $innerService */
+               $innerService = $this->getMockForAbstractClass( WatchedItemStoreInterface::class );
+               $noWriteService = new NoWriteWatchedItemStore( $innerService );
+
+               $this->setExpectedException( DBReadOnlyError::class );
+               $noWriteService->duplicateAllAssociatedEntries(
+                       new TitleValue( 0, 'Foo' ),
+                       new TitleValue( 0, 'Bar' )
+               );
+       }
+
+}
index 010bb17..0e2e145 100644 (file)
@@ -1,7 +1,5 @@
 <?php
 
-require_once __DIR__ . "/../../../maintenance/backupPrefetch.inc";
-
 /**
  * Tests for BaseDump
  *