jenkins-bot has submitted this change and it was merged.

Change subject: lstprop=owner and a few bug fixes
......................................................................


lstprop=owner and a few bug fixes

* Added lstprop=owner to get owner only when needed
* Added $wgGatherAllowPublicWatchlist global
* Optimized lists query's owner retrieval
* Fixed obscure bug with multiple watchlists showing in a list
* Fixed continuation bug when several IDs given
* Fixed format=xml counting bug (thx Anomie)
* Fixed slow filesort in several mysql queries
* ApiEditList::updateInfo() was called with 3 params instead of 2
* More tests

Change-Id: Id18e7c92110dae5e690e7a6cc5d386c639b3de32
(cherry picked from commit 23af469379423565e7a939f01c7275be1971dab5)
---
M Gather.php
M includes/api/ApiEditList.php
M includes/api/ApiQueryLists.php
M includes/specials/SpecialGatherLists.php
M tests/phpunit/api/GatherTests.php
5 files changed, 339 insertions(+), 167 deletions(-)

Approvals:
  Phuedx: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/Gather.php b/Gather.php
index dca7fa2..3803be9 100644
--- a/Gather.php
+++ b/Gather.php
@@ -97,5 +97,10 @@
 $wgGroupPermissions['*']['gather-hidelist'] = false;
 $wgGroupPermissions['sysop']['gather-hidelist'] = true;
 
+/**
+ * If true, user's watchlist can be made public
+ */
+$wgGatherAllowPublicWatchlist = false;
+
 // ResourceLoader modules
 require_once __DIR__ . "/resources/Resources.php";
diff --git a/includes/api/ApiEditList.php b/includes/api/ApiEditList.php
index 0f7f17b..8fbd89b 100644
--- a/includes/api/ApiEditList.php
+++ b/includes/api/ApiEditList.php
@@ -99,10 +99,7 @@
                                        // ACTION: delete list (items + list 
itself)
                                        $dbw->delete( 'gather_list_item', 
array( 'gli_gl_id' => $listId ), __METHOD__ );
                                        $dbw->delete( 'gather_list', array( 
'gl_id' => $listId ), __METHOD__ );
-                                       $this->getResult()->addValue( null, 
$this->getModuleName(), array(
-                                               'status' => 'deleted',
-                                               'id' => $listId,
-                                       ) );
+                                       $this->setResultStatus( $listId, 
'deleted' );
                                        break;
                                case 'hidelist':
                                case 'showlist':
@@ -177,21 +174,20 @@
                }
 
                if ( $isWatchlist ) {
+                       global $wgGatherAllowPublicWatchlist;
                        if ( $label !== null ) {
                                $this->dieUsage( "{$p}label cannot be set for a 
watchlist", 'invalidparammix' );
                        } elseif ( $mode === 'deletelist' ) {
                                $this->dieUsage( "Watchlist may not be 
deleted", 'invalidparammix' );
-                       } elseif ( $params['perm'] === 'public' ) {
+                       } elseif ( !$wgGatherAllowPublicWatchlist ) {
                                // Per team discussion, introducing artificial 
limitation for now
                                // until we establish that making watchlist 
public would cause no harm.
-                               // This check can be deleted at any time since 
all other API code supports it.
-                               $this->dieUsage( 'Making watchlist public is 
not supported for security reasons',
-                                       'publicwatchlist' );
-                       } elseif ( $isNoUpdatesMode ) {
-                               // Per team discussion, introducing artificial 
limitation for now
-                               // until we establish that making watchlist 
public would cause no harm.
-                               // This check can be deleted at any time since 
all other API code supports it.
-                               $this->dieUsage( "{$p}mode=$mode is not allowed 
for watchlist", 'watchlist' );
+                               if ( $isNoUpdatesMode ) {
+                                       $this->dieUsage( "{$p}mode=$mode is not 
allowed for watchlist", 'watchlist' );
+                               } elseif ( $params['perm'] === 'public' ) {
+                                       $this->dieUsage( 'Making watchlist 
public is not supported for security reasons',
+                                               'publicwatchlist' );
+                               }
                        }
                }
                if ( $isNew ) {
@@ -393,8 +389,8 @@
         */
        private function createRow( DatabaseBase $dbw, User $user, array 
$params, &$isWatchlist ) {
                $label = $isWatchlist ? '' : $params['label'];
-               $info = $this->updateInfo( new stdClass(), $params, 
$isWatchlist );
-               $createRow = !$isWatchlist || $info;
+               $info = $this->updateInfo( new stdClass(), $params );
+               $createRow = !$isWatchlist || $info || $params['perm'] === 
'public';
 
                if ( $createRow ) {
                        $id = $dbw->nextSequenceValue( 'gather_list_gl_id_seq' 
);
@@ -425,16 +421,10 @@
                                $this->dieDebug( "List was not found", 'badid' 
);
                        } else {
                                // Watchlist, no changes
-                               $this->getResult()->addValue( null, 
$this->getModuleName(), array(
-                                       'status' => 'nochanges',
-                                       'id' => 0,
-                               ) );
+                               $this->setResultStatus( 0, 'nochanges' );
                        }
                } else {
-                       $this->getResult()->addValue( null, 
$this->getModuleName(), array(
-                               'status' => 'created',
-                               'id' => $id,
-                       ) );
+                       $this->setResultStatus( $id, 'created' );
                }
                return $id;
        }
@@ -449,7 +439,7 @@
        private function updateListDb( DatabaseBase $dbw, array $params, $row ) 
{
                $update = array();
                $info = self::parseListInfo( $row->gl_info, $row->gl_id, true );
-               $info = $this->updateInfo( $info, $params, $row->gl_label === 
'' );
+               $info = $this->updateInfo( $info, $params );
                if ( $info ) {
                        $update['gl_info'] = $info;
                }
@@ -495,8 +485,7 @@
                $titles->append( new ArrayIterator( $pageSet->getGoodTitles() ) 
);
                $titles->append( new ArrayIterator( 
$pageSet->getMissingTitles() ) );
 
-               $mode = $params['mode'];
-               $isRemoving = $mode === 'remove';
+               $isRemoving = $params['mode'] === 'remove';
                if ( $isWatchlist ) {
                        // Legacy watchlist - watch/unwatch
                        foreach ( $titles as $title ) {
@@ -675,9 +664,17 @@
                } else {
                        $status = 'nochanges';
                }
+               $this->setResultStatus( $row->gl_id, $status );
+       }
+
+       /**
+        * @param int $id
+        * @param string $status
+        */
+       private function setResultStatus( $id, $status ) {
                $this->getResult()->addValue( null, $this->getModuleName(), 
array(
                        'status' => $status,
-                       'id' => $row->gl_id,
+                       'id' => $id,
                ) );
        }
 }
diff --git a/includes/api/ApiQueryLists.php b/includes/api/ApiQueryLists.php
index cb18e16..a087c2e 100644
--- a/includes/api/ApiQueryLists.php
+++ b/includes/api/ApiQueryLists.php
@@ -56,6 +56,8 @@
                $fld_public = in_array( 'public', $params['prop'] );
                $fld_image = in_array( 'image', $params['prop'] );
                $fld_updated = in_array( 'updated', $params['prop'] );
+               $fld_owner = in_array( 'owner', $params['prop'] );
+               $fld_count = in_array( 'count', $params['prop'] );
 
                // Watchlist, having the label set to '', should always appear 
first
                // If it doesn't, make sure to insert a fake one in the result
@@ -77,9 +79,8 @@
                        }
                        $injectWatchlist = false;
                        $findWatchlist = false;
-                       $owner = false;
+                       $owner = null;
                        $showPrivate = false;
-                       $userId = 0;
                } else {
                        if ( $ids ) {
                                $findWatchlist = array_search( 0, $ids );
@@ -96,7 +97,6 @@
 
                        /** @var User $owner */
                        list( $owner, $showPrivate ) = $this->calcPermissions( 
$params, $ids );
-                       $userId = $owner ? $owner->getId() : 
$this->getUser()->getId();
                        if ( $showPrivate !== true ) {
                                $injectWatchlist = false;
                        }
@@ -105,13 +105,28 @@
                $db = $this->getDB();
                $this->addTables( 'gather_list' );
                $this->addFields( 'gl_id' );
-               $this->addFieldsIf( 'gl_label', $fld_label || !$mode );
+               if ( $fld_label || !$mode ) {
+                       $this->addFields( 'gl_label' );
+               } else {
+                       $this->addFields( array( 'isWl' => "gl_label=''" ) );
+               }
                $this->addFieldsIf( 'gl_updated', $fld_updated || $mode );
-               $this->addFieldsIf( 'gl_user', $mode );
                $this->addFieldsIf( 'gl_perm', $fld_public );
+
+               if ( $fld_owner && !$owner ) {
+                       // Join user table to get user name
+                       // else - we already know the user to return, no need 
to join tables
+                       $this->addTables( 'user' );
+                       $this->addJoinConds( array( 'user' => array( 'INNER 
JOIN', 'user_id=gl_user' ) ) );
+                       $this->addFields( 'user_name' );
+               }
 
                if ( $owner ) {
                        $this->addWhereFld( 'gl_user', $owner->getId() );
+                       $singleUser = true;
+               } else {
+                       $owner = $this->getUser();
+                       $singleUser = false;
                }
 
                if ( $ids || $findWatchlist ) {
@@ -120,17 +135,22 @@
                                $cond['gl_id'] = $ids;
                        }
                        if ( $findWatchlist ) {
-                               $cond['gl_label'] = '';
+                               if ( $singleUser ) {
+                                       $cond['gl_label'] = '';
+                               } else {
+                                       $cond[] =
+                                               $db->makeList( array( 
'gl_label' => '', 'gl_user' => $owner->getId() ),
+                                                       LIST_AND );
+                                       if ( !$ids ) {
+                                               $singleUser = true;
+                                       }
+                               }
                        }
                        $this->addWhere( $db->makeList( $cond, LIST_OR ) );
                }
 
                if ( $mode === 'allhidden' ) {
                        $this->addWhereFld( 'gl_perm', ApiEditList::PERM_HIDDEN 
);
-                       if ( !$this->getUser()->isAllowed( 'gather-hidelist' ) 
) {
-                               // Show only the lists for the current user
-                               $this->addWhereFld( 'gl_user', 
$this->getUser()->getId() );
-                       }
                } elseif ( $showPrivate !== true ) {
                        $cond = array( 'gl_perm' => ApiEditList::PERM_PUBLIC );
                        if ( $showPrivate === null ) {
@@ -140,18 +160,30 @@
                }
 
                if ( $continue ) {
-                       if ( $mode ) {
-                               $cont = explode( '|', $params['continue'] );
-                               $this->dieContinueUsageIf( count( $cont ) != 2 
);
-                               $cont_upd = $db->addQuotes( $cont[0] );
-                               $cont_id = intval( $cont[1] );
-                               $this->dieContinueUsageIf( strval( $cont_id ) 
!== $cont[1] );
-                               $cont_id = $db->addQuotes( $cont_id );
-                               $this->addWhere( "gl_updated < $cont_upd OR " .
-                                                                "(gl_updated = 
$cont_upd AND gl_id <= $cont_id)" );
+                       if ( $singleUser ) {
+                               // Single value continue
+                               $contLabel = $db->addQuotes( 
$params['continue'] );
+                               $this->addWhere( "gl_label >= $contLabel" );
                        } else {
-                               $cont = $db->addQuotes( $continue );
-                               $this->addWhere( "gl_label >= $cont" );
+                               if ( $mode ) {
+                                       $cont = explode( '|', 
$params['continue'] );
+                                       $this->dieContinueUsageIf( count( $cont 
) != 2 );
+                                       $contUpd = $db->addQuotes( $cont[0] );
+                                       $contId = intval( $cont[1] );
+                                       $this->dieContinueUsageIf( strval( 
$contId ) !== $cont[1] );
+                                       $contId = $db->addQuotes( $contId );
+                                       $this->addWhere( "gl_updated < $contUpd 
OR " .
+                                                                        
"(gl_updated = $contUpd AND gl_id <= $contId)" );
+                               } else {
+                                       $cont = explode( '|', 
$params['continue'], 2 ); // label may contain '|'
+                                       $this->dieContinueUsageIf( count( $cont 
) != 2 );
+                                       $contUser = intval( $cont[0] );
+                                       $this->dieContinueUsageIf( strval( 
$contUser ) !== $cont[0] );
+                                       $contUser = $db->addQuotes( $contUser );
+                                       $contLabel = $db->addQuotes( $cont[1] );
+                                       $this->addWhere( "gl_user > $contUser 
OR " .
+                                                                        
"(gl_user = $contUser AND gl_label >= $contLabel)" );
+                               }
                        }
                }
                if ( $mode ) {
@@ -161,8 +193,14 @@
                        $setContinue = function( $row ) use ( $self ) {
                                $self->setContinueEnumParameter( 'continue', 
"{$row->gl_updated}|{$row->gl_id}" );
                        };
-               } else {
+               } elseif ( !$singleUser ) {
+                       $this->addFields( 'gl_user' );
                        $this->addOption( 'ORDER BY', 'gl_user, gl_label' );
+                       $setContinue = function( $row ) use ( $self ) {
+                               $self->setContinueEnumParameter( 'continue', 
"{$row->gl_user}|{$row->gl_label}" );
+                       };
+               } else {
+                       $this->addOption( 'ORDER BY', 'gl_label' );
                        $setContinue = function( $row ) use ( $self ) {
                                $self->setContinueEnumParameter( 'continue', 
$row->gl_label );
                        };
@@ -183,10 +221,8 @@
                                $subsql = $db->selectSQLText( 
'gather_list_item', 'gli_gl_id', $cond, __METHOD__ );
                                $subsql = "($subsql)";
                                $this->addFields( array( 'isIn' => $subsql ) );
-                       } else {
-                               // Avoid subquery because there would be no 
results - searching for watchlist
-                               $this->addFields( array( 'isIn' => 'NULL' ) );
                        }
+                       // else - avoid subquery because there would be no 
results - searching for watchlist
                }
 
                $useInfo = $fld_description || $fld_image;
@@ -200,15 +236,14 @@
 
                // This closure will process one row, even if that row is fake 
watchlist
                $processRow = function( $row ) use ( $self, &$count, $mode, 
$limit,  $useInfo, $title,
-                       $fld_label, $fld_description, $fld_public, $fld_image, 
$fld_updated, $path, $userId,
-                       $setContinue
+                       $fld_label, $fld_description, $fld_public, $fld_image, 
$fld_updated, $fld_owner,
+                       $path, $owner, $setContinue
                ) {
                        if ( $row === null ) {
                                // Fake watchlist row
                                $row = (object) array(
                                        'gl_id' => 0,
                                        'gl_label' => '',
-                                       'gl_user' => false,
                                        'gl_perm' => ApiEditList::PERM_PRIVATE,
                                        'gl_updated' => '',
                                        'gl_info' => '',
@@ -225,7 +260,7 @@
                                return false;
                        }
 
-                       $isWatchlist = $row->gl_label === '';
+                       $isWatchlist = property_exists( $row, 'isWl' ) ? 
$row->isWl : $row->gl_label === '';
 
                        $data = array( 'id' => $row->gl_id );
                        if ( $isWatchlist ) {
@@ -235,14 +270,15 @@
                                // TODO: check if this is the right wfMessage 
to show
                                $data['label'] = !$isWatchlist ? $row->gl_label 
: wfMessage( 'watchlist' )->plain();
                        }
-                       if ( $mode ) {
-                               $data['owner'] = User::newFromId( $row->gl_user 
)->getName();
+                       if ( $fld_owner ) {
+                               $data['owner'] = property_exists( $row, 
'user_name' ) ?
+                                       $row->user_name : $owner->getName();
                        }
                        if ( $title ) {
                                if ( $isWatchlist ) {
-                                       $data['title'] = 
$self->isTitleInWatchlist( $userId, $title );
+                                       $data['title'] = 
$self->isTitleInWatchlist( $owner, $title );
                                } else {
-                                       $data['title'] = $row->isIn !== null;
+                                       $data['title'] = isset( $row->isIn );
                                }
                        }
                        if ( $fld_public ) {
@@ -297,7 +333,7 @@
 
                foreach ( $this->select( __METHOD__ ) as $row ) {
                        if ( $injectWatchlist ) {
-                               if ( $row->gl_label !== '' ) {
+                               if ( property_exists( $row, 'isWl' ) ? 
!$row->isWl : $row->gl_label !== '' ) {
                                        // The very first DB row already has a 
label, so inject a fake
                                        if ( !$processRow( null ) ) {
                                                break;
@@ -317,7 +353,9 @@
 
                $this->getResult()->setIndexedTagName_internal( $path, 'c' );
 
-               $this->updateCounts( $params, $userId );
+               if ( $fld_count ) {
+                       $this->updateCounts( $owner );
+               }
        }
 
        public function getCacheMode( $params ) {
@@ -342,6 +380,7 @@
                                        'image',
                                        'count',
                                        'updated',
+                                       'owner',
                                )
                        ),
                        'ids' => array(
@@ -417,7 +456,7 @@
                        // ids given - will need to validate each id to belong 
to the current user for privacy
                        $owner = false;
                        if ( !$this->getUser()->isLoggedIn() ) {
-                               $showPrivate = false;
+                               $showPrivate = false; // Anonymous user - 
optimize, none of the results are private
                        } else {
                                $showPrivate = null; // check each id against 
current user's ID
                        }
@@ -434,13 +473,9 @@
 
        /**
         * Update result lists with their page counts
-        * @param $params
-        * @param int $userId
+        * @param User $wlOwner In case there is a watchlist, this is the user 
it belongs to
         */
-       private function updateCounts( $params, $userId ) {
-               if ( !in_array( 'count', $params['prop'] ) ) {
-                       return;
-               }
+       private function updateCounts( User $wlOwner ) {
                $data = $this->getResult()->getData();
                if ( !isset( $data['query'] ) || !isset( 
$data['query'][$this->getModuleName()] ) ) {
                        return;
@@ -449,13 +484,13 @@
 
                $ids = array();
                $wlListId = false;
-               $wlUserId = false;
                foreach ( $data as $page ) {
-                       if ( $page['id'] === 0 || isset( $page['watchlist'] ) ) 
{
-                               $wlListId = $page['id'];
-                               $wlUserId = $userId;
-                       } else {
-                               $ids[] = $page['id'];
+                       if ( is_array( $page ) ) {
+                               if ( $page['id'] === 0 || isset( 
$page['watchlist'] ) ) {
+                                       $wlListId = $page['id'];
+                               } else {
+                                       $ids[] = $page['id'];
+                               }
                        }
                }
 
@@ -465,7 +500,7 @@
                        $db = $this->getQuery()->getNamedDB( 'watchlist', 
DB_SLAVE, 'watchlist' );
                        // Must divide in two because of duplicate talk pages 
(same as the special page)
                        $counts[$wlListId] = intval( floor(
-                               $db->selectRowCount( 'watchlist', '*', array( 
'wl_user' => $wlUserId ),
+                               $db->selectRowCount( 'watchlist', '*', array( 
'wl_user' => $wlOwner->getId() ),
                                        __METHOD__ ) / 2 ) );
                }
                if ( count( $ids ) > 0 ) {
@@ -482,8 +517,10 @@
                }
 
                foreach ( $data as &$page ) {
-                       $id = $page['id'];
-                       $page['count'] = isset( $counts[$id] ) ? $counts[$id] : 
0;
+                       if ( is_array( $page ) ) {
+                               $id = $page['id'];
+                               $page['count'] = isset( $counts[$id] ) ? 
$counts[$id] : 0;
+                       }
                }
                // Replace result with the results with counts
                $this->getResult()->addValue( 'query', $this->getModuleName(), 
$data,
@@ -491,15 +528,15 @@
        }
 
        /**
-        * @param int $userId
+        * @param User $user
         * @param Title $title
         * @return bool
         * @throws \DBUnexpectedError
         */
-       private function isTitleInWatchlist( $userId, $title ) {
+       private function isTitleInWatchlist( User $user, Title $title ) {
                $db = $this->getQuery()->getNamedDB( 'watchlist', DB_SLAVE, 
'watchlist' );
                return (bool)$db->selectField( 'watchlist', '1', array(
-                       'wl_user' => $userId,
+                       'wl_user' => $user->getId(),
                        'wl_namespace' => $title->getNamespace(),
                        'wl_title' => $title->getDBkey(),
                ), __METHOD__ );
diff --git a/includes/specials/SpecialGatherLists.php 
b/includes/specials/SpecialGatherLists.php
index 555ce11..032156b 100644
--- a/includes/specials/SpecialGatherLists.php
+++ b/includes/specials/SpecialGatherLists.php
@@ -56,7 +56,7 @@
                        'list' => 'lists',
                        'lstmode' => $subPage === 'hidden' ? 'allhidden' : 
'allpublic',
                        // FIXME: Need owner to link to collection
-                       'lstprop' => 'label|description|image|count|updated',
+                       'lstprop' => 
'label|description|image|count|updated|owner',
                        // TODO: Pagination
                        'continue' => '',
                ) ) );
diff --git a/tests/phpunit/api/GatherTests.php 
b/tests/phpunit/api/GatherTests.php
index fd9cb1a..c81f9ef 100644
--- a/tests/phpunit/api/GatherTests.php
+++ b/tests/phpunit/api/GatherTests.php
@@ -65,17 +65,89 @@
                                'GatherWlOnly2',
                                'GatherE1',
                                'GatherE2',
+                               'GatherE3',
                        ) as $name ) {
                                self::$wlUsers[$name] = new TestUser( $name );
                        }
                }
                self::$users = array_merge( self::$users, self::$wlUsers );
+               global $wgGatherAllowPublicWatchlist;
+               $wgGatherAllowPublicWatchlist = false;
+       }
+
+       protected function tearDown() {
+               global $wgGatherAllowPublicWatchlist;
+               $wgGatherAllowPublicWatchlist = false;
+               $this->db->delete( 'gather_list_item', '*' );
+               $this->db->delete( 'gather_list', '*' );
+               parent::tearDown();
+       }
+
+
+       public function testMultiUser() {
+               $usrA = User::newFromId( 0 ); // Anonymous user
+               $n = 'GatherE1';
+               $n2 = 'GatherE2';
+               $n3 = 'GatherE3';
+               $nS = 'sysop';
+               $usr = self::$users[$n]->getUser();
+               $usr2 = self::$users[$n2]->getUser();
+               $usr3 = self::$users[$n3]->getUser();
+               $usrS = self::$users[$nS]->getUser();
+               $token = $this->getToken( $usr );
+               $token2 = $this->getToken( $usr2 );
+               $token3 = $this->getToken( $usr3 );
+               $tokenS = $this->getToken( $usrS );
+               $tokenA = $this->getToken( $usrA );
+
+               global $wgGatherAllowPublicWatchlist;
+               $wgGatherAllowPublicWatchlist = true;
+
+               $res = $this->editList( 'mu-a1', $usr, $token, 
'"id":0,"perm":"public"' );
+               $idWl = $this->getVal( 'mu-a1', '"id"', $res );
+               $this->assertNotEquals( 0, $idWl, 'mu-a1' );
+
+               $res = $this->editList( 'mu-a2', $usr2, $token2, 
'"id":0,"perm":"public"' );
+               $id2Wl = $this->getVal( 'mu-a2', '"id"', $res );
+               $this->assertNotEquals( 0, $id2Wl, 'mu-a1' );
+
+               $res = $this->editList( 'mu-a3', $usr3, $token3, 
'"id":0,"description":"aa"' );
+               $id3Wl = $this->getVal( 'mu-a3', '"id"', $res );
+               $this->assertNotEquals( 0, $id3Wl, 'mu-a1' );
+
+               $pS = array( 'watchlist' => true, 'label' => 'Watchlist' );
+               $p1 = (object) array_merge( array( 'id' => $idWl ), $pS );
+               $p2 = (object) array_merge( array( 'id' => $id2Wl ), $pS );
+               $p3 = (object) array_merge( array( 'id' => $id3Wl ), $pS );
+               $pS = (object) array_merge( array( 'id' => 0 ), $pS );
+
+               $this->assertLists( 'mu-b1', $usr, 0, $p1 );
+               $this->assertLists( 'mu-b2', $usr2, 0, $p2 );
+               $this->assertLists( 'mu-b2', $usr3, 0, $p3 );
+               $this->assertLists( 'mu-b3', $usrS, 0, $pS );
+               $this->assertLists( 'mu-b4', $usr3,
+                       '"lstids":"' . $idWl . '|' . $id2Wl . '"', array( $p1, 
$p2 ) );
+               $this->assertLists( 'mu-b5', $usr2,
+                       '"lstids":"' . $idWl . '|' . 0 . '"', array( $p1, $p2 ) 
);
+               $this->assertLists( 'mu-b6', $usr3,
+                       '"lstids":"' . $idWl . '|' . 0 . '"', array( $p1, $p3 ) 
);
+               $this->assertLists( 'mu-b7', $usrA,
+                       '"lstids":"' . $idWl . '|' . 0 . '"', array( $p1 ) );
+               $this->assertLists( 'mu-b8', $usr3, '"lstmode":"allpublic"', 
array( $p2, $p1 ) );
+               $this->assertLists( 'mu-b9', $usrS, '"lstmode":"allhidden"', 
null );
        }
 
        public function testListEditAndPages() {
                $n = 'GatherE1';
                $n2 = 'GatherE2';
+               $n3 = 'GatherE3';
                $nS = 'sysop';
+               $usr = self::$users[$n]->getUser();
+               $usr2 = self::$users[$n2]->getUser();
+               $usr3 = self::$users[$n3]->getUser();
+               $usrS = self::$users[$nS]->getUser();
+               $usrA = User::newFromId( 0 ); // Anonymous user
+
                $pageW = array( 'ns' => 0, 'title' => 'Gather-ListW' );
                $pageTW = array( 'ns' => 1, 'title' => 'Talk:Gather-ListW' );
                $pageWA = array( 'ns' => 0, 'title' => 'Gather-ListWA' );
@@ -89,18 +161,19 @@
 
                $usr = self::$users[$n]->getUser();
                $usr2 = self::$users[$n2]->getUser();
+               $usr3 = self::$users[$n3]->getUser();
                $usrS = self::$users[$nS]->getUser();
                $usrA = User::newFromId( 0 ); // Anonymous user
 
                $token = $this->getToken( $usr );
                $token2 = $this->getToken( $usr2 );
+               $token3 = $this->getToken( $usr3 );
                $tokenS = $this->getToken( $usrS );
                $tokenA = $this->getToken( $usrA );
 
                // Make sure there are no watchlists yet for these users 
(starting from clean slate)
                foreach ( array( $usr, $usr2 ) as $user ) {
-                       $res = $this->getLists( 'ed-a0', $user, '{}' );
-                       $this->assertListsEquals( 'ed-a0', $res,
+                       $this->assertLists( 'ed-a0', $user, '{}',
                                '[{"id":0, "watchlist":true, 
"label":"Watchlist"}]' );
                        $this->assertPages( 'ed-a1', $user, null, array(), 
array() );
                }
@@ -139,15 +212,22 @@
                $this->badUseEdit( 'ed-ba16', $usrS, $tokenS, $idWL . ', 
"mode": "hidelist"' );
                $this->badUseEdit( 'ed-ba17', $usrS, $tokenS, $idWL . ', 
"mode": "showlist"' );
 
-               $expListsW = array( 'id' => 0, 'watchlist' => true, 'label' => 
'Watchlist' );
-               $expListsW2 = array_merge( $expListsW, array(
+               $this->assertLists( 'ed-bb1', $usr, '"lstmode":"allpublic"', 
null );
+               $this->assertLists( 'ed-bb2', $usrA, '"lstmode":"allpublic"', 
null );
+               $this->assertLists( 'ed-bb3', $usrS, '"lstmode":"allpublic"', 
null );
+               $this->badUseLists( 'ed-bb4', $usr, '"lstmode":"allhidden"' );
+               $this->badUseLists( 'ed-bb5', $usrA, '"lstmode":"allhidden"' );
+               $this->assertLists( 'ed-bb6', $usrS, '"lstmode":"allhidden"', 
null );
+
+               $expListsW = (object) array( 'id' => 0, 'watchlist' => true, 
'label' => 'Watchlist' );
+               $expListsW2 = (object) array_merge( (array) $expListsW, array(
                        'public' => false,
                        'perm' => 'private',
                        'description' => '',
                        'image' => false,
                        'count' => 0,
                ) );
-               $this->assertOneList( 'ed-bb1', $usr, 0, $expListsW, 
$expListsW2 );
+               $this->assertLists( 'ed-bb1', $usr, 0, $expListsW, $expListsW2 
);
 
                //
                // Add one page to the non-created watchlist
@@ -157,29 +237,29 @@
                $this->getVal( 'ed-c1', '"pages", 0, "title"', $res, 
'Gather-ListW' );
                $this->getVal( 'ed-c1', '"pages", 0, "added"', $res, '' );
 
-               $expListsW2['count'] = 1;
+               $expListsW2->count = 1;
                $expPagesW = array( $pageW, $pageTW );
 
                $this->assertPages( 'ed-c2', $usr, null, $expPagesW );
                $this->assertPages( 'ed-c3', $usr, 0, $expPagesW );
-               $this->assertOneList( 'ed-c4', $usr, 0, $expListsW, $expListsW2 
);
+               $this->assertLists( 'ed-c4', $usr, 0, $expListsW, $expListsW2 );
 
                //
                // Create Watchlist row
                $res = $this->editList( 'ed-d1', $usr, $token, '"id":0, 
"description": "x"' );
                $id0 = $this->getVal( 'ed-d1', '"id"', $res );
                $idWL = '"id":' . $id0;
-               $expListsW['id'] = $id0;
-               $expListsW2['id'] = $id0;
-               $expListsW2['description'] = 'x';
+               $expListsW->id = $id0;
+               $expListsW2->id = $id0;
+               $expListsW2->description = 'x';
 
                $this->assertPages( 'ed-d2', $usr, 0, $expPagesW );
                $this->assertPages( 'ed-d3', $usr, $id0, $expPagesW );
-               $this->assertOneList( 'ed-d4', $usr, 0, $expListsW, $expListsW2 
);
-               $this->assertOneList( 'ed-d5', $usr, $id0, $expListsW, 
$expListsW2 );
-               $this->assertOneList( 'ed-d6', $usrA, $id0, null );
-               $this->assertOneList( 'ed-d7', $usr2, $id0, null );
-               $this->assertOneList( 'ed-d7a', $usrS, $id0, null );
+               $this->assertLists( 'ed-d4', $usr, 0, $expListsW, $expListsW2 );
+               $this->assertLists( 'ed-d5', $usr, $id0, $expListsW, 
$expListsW2 );
+               $this->assertLists( 'ed-d6', $usrA, $id0, null );
+               $this->assertLists( 'ed-d7', $usr2, $id0, null );
+               $this->assertLists( 'ed-d7a', $usrS, $id0, null );
                $this->badUsePage( 'ed-d8', $usrA, '"lspid": ' . $id0 );
                $this->badUsePage( 'ed-d9', $usr2, '"lspid": ' . $id0 );
                $this->badUsePage( 'ed-d10', $usrS, '"lspid": ' . $id0 );
@@ -204,6 +284,13 @@
                $this->badUseEdit( 'ed-da16', $usrS, $tokenS, $idWL . ', 
"mode": "hidelist"' );
                $this->badUseEdit( 'ed-da17', $usrS, $tokenS, $idWL . ', 
"mode": "showlist"' );
 
+               $this->assertLists( 'ed-da21', $usr, '"lstmode":"allpublic"', 
null );
+               $this->assertLists( 'ed-da22', $usrA, '"lstmode":"allpublic"', 
null );
+               $this->assertLists( 'ed-da23', $usrS, '"lstmode":"allpublic"', 
null );
+               $this->badUseLists( 'ed-da24', $usr, '"lstmode":"allhidden"' );
+               $this->badUseLists( 'ed-da25', $usrA, '"lstmode":"allhidden"' );
+               $this->assertLists( 'ed-da26', $usrS, '"lstmode":"allhidden"', 
null );
+
                //
                // Add Gather-ListWA to the created watchlist
                $res = $this->editList( 'ed-e1', $usr, $token, $idWL . ', 
"titles": "Gather-ListWA"' );
@@ -212,14 +299,14 @@
                $this->getVal( 'ed-e1', '"pages", 0, "title"', $res, 
'Gather-ListWA' );
                $this->getVal( 'ed-e1', '"pages", 0, "added"', $res, '' );
 
-               $expListsW2['count'] = 2;
+               $expListsW2->count = 2;
                $expPagesW = array( $pageW, $pageWA, $pageTW, $pageTWA );
 
                $this->assertPages( 'ed-e2', $usr, null, $expPagesW );
                $this->assertPages( 'ed-e3', $usr, 0, $expPagesW );
                $this->assertPages( 'ed-e4', $usr, $id0, $expPagesW );
-               $this->assertOneList( 'ed-e5', $usr, 0, $expListsW, $expListsW2 
);
-               $this->assertOneList( 'ed-e6', $usr, $id0, $expListsW, 
$expListsW2 );
+               $this->assertLists( 'ed-e5', $usr, 0, $expListsW, $expListsW2 );
+               $this->assertLists( 'ed-e6', $usr, $id0, $expListsW, 
$expListsW2 );
 
                //
                // Add Gather-ListWAB to the created watchlist with ID=0 and 
description change
@@ -230,15 +317,15 @@
                $this->getVal( 'ed-f1', '"pages", 0, "title"', $res, 
'Gather-ListWAB' );
                $this->getVal( 'ed-f1', '"pages", 0, "added"', $res, '' );
 
-               $expListsW2['count'] = 3;
-               $expListsW2['description'] = 'y';
+               $expListsW2->count = 3;
+               $expListsW2->description = 'y';
                $expPagesW = array( $pageW, $pageWA, $pageWAB, $pageTW, 
$pageTWA, $pageTWAB );
 
                $this->assertPages( 'ed-f2', $usr, null, $expPagesW );
                $this->assertPages( 'ed-f3', $usr, 0, $expPagesW );
                $this->assertPages( 'ed-f4', $usr, $id0, $expPagesW );
-               $this->assertOneList( 'ed-f5', $usr, 0, $expListsW, $expListsW2 
);
-               $this->assertOneList( 'ed-f6', $usr, $id0, $expListsW, 
$expListsW2 );
+               $this->assertLists( 'ed-f5', $usr, 0, $expListsW, $expListsW2 );
+               $this->assertLists( 'ed-f6', $usr, $id0, $expListsW, 
$expListsW2 );
 
                //
                // Create new list A
@@ -246,8 +333,8 @@
                $this->getVal( 'ed-i1', '"status"', $res, 'created' );
                $idA = $this->getVal( 'ed-i1', '"id"', $res );
                $idAs = '"id":' . $idA;
-               $expListsA = array( 'id' => $idA, 'label' => 'A' );
-               $expListsA2 = array_merge( $expListsA, array(
+               $expListsA = (object) array( 'id' => $idA, 'label' => 'A' );
+               $expListsA2 = (object) array_merge( (array) $expListsA, array(
                        'public' => false,
                        'perm' => 'private',
                        'description' => '',
@@ -257,10 +344,10 @@
                $expPagesA = array();
 
                $this->assertPages( 'ed-i2', $usr, $idA, $expPagesA );
-               $this->assertOneList( 'ed-i3', $usr, $idA, $expListsA, 
$expListsA2 );
-               $this->assertOneList( 'ed-i4', $usrA, $idA, null );
-               $this->assertOneList( 'ed-i5', $usr2, $idA, null );
-               $this->assertOneList( 'ed-i6', $usrS, $idA, null );
+               $this->assertLists( 'ed-i3', $usr, $idA, $expListsA, 
$expListsA2 );
+               $this->assertLists( 'ed-i4', $usrA, $idA, null );
+               $this->assertLists( 'ed-i5', $usr2, $idA, null );
+               $this->assertLists( 'ed-i6', $usrS, $idA, null );
 
                $this->badUsePage( 'ed-ia1', $usrA, '"lspid": ' . $idA );
                $this->badUsePage( 'ed-ia2', $usr2, '"lspid": ' . $idA );
@@ -281,19 +368,26 @@
                $this->badUseEdit( 'ed-ia16', $usrS, $tokenS, $idAs . ', 
"mode": "hidelist"' );
                $this->badUseEdit( 'ed-ia17', $usrS, $tokenS, $idAs . ', 
"mode": "showlist"' );
 
+               $this->assertLists( 'ed-ia21', $usr, '"lstmode":"allpublic"', 
null );
+               $this->assertLists( 'ed-ia22', $usrA, '"lstmode":"allpublic"', 
null );
+               $this->assertLists( 'ed-ia23', $usrS, '"lstmode":"allpublic"', 
null );
+               $this->badUseLists( 'ed-ia24', $usr, '"lstmode":"allhidden"' );
+               $this->badUseLists( 'ed-ia25', $usrA, '"lstmode":"allhidden"' );
+               $this->assertLists( 'ed-ia26', $usrS, '"lstmode":"allhidden"', 
null );
+
                //
                // Rename list A to 'a'
                $res = $this->editList( 'ed-j1', $usr, $token, $idAs . ', 
"label": "a"' );
                $this->getVal( 'ed-j1', '"status"', $res, 'updated' );
                $this->getVal( 'ed-j1', '"id"', $res, $idA );
-               $expListsA['label'] = 'a';
-               $expListsA2['label'] = 'a';
+               $expListsA->label = 'a';
+               $expListsA2->label = 'a';
 
                $this->assertPages( 'ed-j2', $usr, $idA, $expPagesA );
-               $this->assertOneList( 'ed-j3', $usr, $idA, $expListsA, 
$expListsA2 );
-               $this->assertOneList( 'ed-j4', $usrA, $id0, null );
-               $this->assertOneList( 'ed-j5', $usr2, $id0, null );
-               $this->assertOneList( 'ed-j6', $usrS, $id0, null );
+               $this->assertLists( 'ed-j3', $usr, $idA, $expListsA, 
$expListsA2 );
+               $this->assertLists( 'ed-j4', $usrA, $id0, null );
+               $this->assertLists( 'ed-j5', $usr2, $id0, null );
+               $this->assertLists( 'ed-j6', $usrS, $id0, null );
 
                $this->badUsePage( 'ed-ja1', $usrA, '"lspid": ' . $idA );
                $this->badUsePage( 'ed-ja2', $usr2, '"lspid": ' . $idA );
@@ -314,17 +408,17 @@
                $res = $this->editList( 'ed-k1', $usr, $token, '"label": "a", 
"perm": "public"' );
                $this->getVal( 'ed-k1', '"status"', $res, 'updated' );
                $this->getVal( 'ed-k1', '"id"', $res, $idA );
-               $expListsA2['public'] = true;
-               $expListsA2['perm'] = 'public';
+               $expListsA2->public = true;
+               $expListsA2->perm = 'public';
 
                $this->assertPages( 'ed-k2', $usr, $idA, $expPagesA );
                $this->assertPages( 'ed-k2a', $usr2, $idA, $expPagesA );
                $this->assertPages( 'ed-k2b', $usrA, $idA, $expPagesA );
                $this->assertPages( 'ed-k2c', $usrS, $idA, $expPagesA );
-               $this->assertOneList( 'ed-k3', $usr, $idA, $expListsA, 
$expListsA2 );
-               $this->assertOneList( 'ed-k4', $usrA, $idA, $expListsA, 
$expListsA2 );
-               $this->assertOneList( 'ed-k5', $usr2, $idA, $expListsA, 
$expListsA2 );
-               $this->assertOneList( 'ed-k6', $usrS, $idA, $expListsA, 
$expListsA2 );
+               $this->assertLists( 'ed-k3', $usr, $idA, $expListsA, 
$expListsA2 );
+               $this->assertLists( 'ed-k4', $usrA, $idA, $expListsA, 
$expListsA2 );
+               $this->assertLists( 'ed-k5', $usr2, $idA, $expListsA, 
$expListsA2 );
+               $this->assertLists( 'ed-k6', $usrS, $idA, $expListsA, 
$expListsA2 );
 
                $this->badUseEdit( 'ed-ka1', $usr, false, $idAs . ', 
"description": "x"' );
                $this->badUseEdit( 'ed-ka2', $usrA, false, $idAs . ', 
"description": "x"' );
@@ -347,6 +441,13 @@
                $this->badUseEdit( 'ed-ka18', $usr2, $token2, $idAs . ', 
"mode": "hidelist"' );
                $this->badUseEdit( 'ed-ka19', $usr2, $token2, $idAs . ', 
"mode": "showlist"' );
 
+               $this->assertLists( 'ed-ka21', $usr, '"lstmode":"allpublic"', 
$expListsA, $expListsA2 );
+               $this->assertLists( 'ed-ka22', $usrA, '"lstmode":"allpublic"', 
$expListsA, $expListsA2 );
+               $this->assertLists( 'ed-ka23', $usrS, '"lstmode":"allpublic"', 
$expListsA, $expListsA2 );
+               $this->badUseLists( 'ed-ka24', $usr, '"lstmode":"allhidden"' );
+               $this->badUseLists( 'ed-ka25', $usrA, '"lstmode":"allhidden"' );
+               $this->assertLists( 'ed-ka26', $usrS, '"lstmode":"allhidden"', 
null );
+
                //
                // Delete list A
                $res = $this->editList( 'ed-l1', $usr, $token, $idAs . ', 
"mode": "deletelist"' );
@@ -357,10 +458,10 @@
                $this->badUsePage( 'ed-l3', $usr2, '"lspid": ' . $idA );
                $this->badUsePage( 'ed-l3a', $usrS, '"lspid": ' . $idA );
                $this->badUsePage( 'ed-l4', $usrA, '"lspid": ' . $idA );
-               $this->assertOneList( 'ed-l5', $usr, $idA, null );
-               $this->assertOneList( 'ed-l6', $usrA, $idA, null );
-               $this->assertOneList( 'ed-l7', $usr2, $idA, null );
-               $this->assertOneList( 'ed-l7a', $usrS, $idA, null );
+               $this->assertLists( 'ed-l5', $usr, $idA, null );
+               $this->assertLists( 'ed-l6', $usrA, $idA, null );
+               $this->assertLists( 'ed-l7', $usr2, $idA, null );
+               $this->assertLists( 'ed-l7a', $usrS, $idA, null );
 
                $this->badUseEdit( 'ed-l8', $usr, $token, $idAs . ', "titles": 
"ABC"' );
                $this->badUseEdit( 'ed-l9', $usr, $token, $idAs . ', "label": 
"x"' );
@@ -375,8 +476,9 @@
                $this->getVal( 'ed-n1', '"status"', $res, 'created' );
                $idB = $this->getVal( 'ed-n1', '"id"', $res );
                $idBs = '"id":' . $idB;
-               $expListsB = array( 'id' => $idB, 'label' => 'B' );
-               $expListsB2 = array_merge( $expListsB, array(
+
+               $expListsB = (object) array( 'id' => $idB, 'label' => 'B' );
+               $expListsB2 = (object) array_merge( (array) $expListsB, array(
                        'public' => true,
                        'perm' => 'public',
                        'description' => '',
@@ -390,10 +492,10 @@
                $this->assertPages( 'ed-n3', $usr2, $idB, $expPagesB );
                $this->assertPages( 'ed-n3a', $usrS, $idB, $expPagesB );
                $this->assertPages( 'ed-n4', $usrA, $idB, $expPagesB );
-               $this->assertOneList( 'ed-n5', $usr, $idB, $expListsB, 
$expListsB2 );
-               $this->assertOneList( 'ed-n6', $usrA, $idB, $expListsB, 
$expListsB2 );
-               $this->assertOneList( 'ed-n7', $usr2, $idB, $expListsB, 
$expListsB2 );
-               $this->assertOneList( 'ed-n8', $usrS, $idB, $expListsB, 
$expListsB2 );
+               $this->assertLists( 'ed-n5', $usr, $idB, $expListsB, 
$expListsB2 );
+               $this->assertLists( 'ed-n6', $usrA, $idB, $expListsB, 
$expListsB2 );
+               $this->assertLists( 'ed-n7', $usr2, $idB, $expListsB, 
$expListsB2 );
+               $this->assertLists( 'ed-n8', $usrS, $idB, $expListsB, 
$expListsB2 );
                $this->badUseEdit( 'ed-na1', $usr, $token, '"label": "B", 
"mode": "hidelist"' );
                $this->badUseEdit( 'ed-na2', $usr, $token, '"label": "B", 
"mode": "showlist"' );
                $this->badUseEdit( 'ed-na3', $usrA, $tokenA, '"label": "B", 
"mode": "hidelist"' );
@@ -420,14 +522,16 @@
                $res = $this->editList( 'ed-o2', $usrS, $tokenS, $idBs . ', 
"mode":"hidelist"' );
                $this->getVal( 'ed-o2', '"status"', $res, 'updated' );
                $this->getVal( 'ed-o2', '"id"', $res, $idB );
-               $expListsB2['public'] = false;
-               $expListsB2['perm'] = 'hidden';
+               $expListsB2->public = false;
+               $expListsB2->perm = 'hidden';
 
                $this->assertPages( 'ed-o3', $usr, $idB, $expPagesB );
-               $this->assertOneList( 'ed-o4', $usr, $idB, $expListsB, 
$expListsB2 );
-               $this->assertOneList( 'ed-o5', $usrA, $idB, null );
-               $this->assertOneList( 'ed-o6', $usr2, $idB, null );
-               $this->assertOneList( 'ed-o7', $usrS, $idB, null );
+               $this->assertLists( 'ed-o4', $usr, $idB, $expListsB, 
$expListsB2 );
+               $this->assertLists( 'ed-o4a', $usr, '{}', array( $expListsW, 
$expListsB ),
+                       array( $expListsW2, $expListsB2 ) );
+               $this->assertLists( 'ed-o5', $usrA, $idB, null );
+               $this->assertLists( 'ed-o6', $usr2, $idB, null );
+               $this->assertLists( 'ed-o7', $usrS, $idB, null );
 
                $this->badUsePage( 'ed-oa1', $usrA, '"lspid": ' . $idB );
                $this->badUsePage( 'ed-oa2', $usr2, '"lspid": ' . $idB );
@@ -453,11 +557,11 @@
                $res = $this->editList( 'ed-p1', $usrS, $tokenS, $idBs . ', 
"mode":"showlist"' );
                $this->getVal( 'ed-p1', '"status"', $res, 'updated' );
                $this->getVal( 'ed-p1', '"id"', $res, $idB );
-               $expListsB2['public'] = true;
-               $expListsB2['perm'] = 'public';
+               $expListsB2->public = true;
+               $expListsB2->perm = 'public';
 
                $this->assertPages( 'ed-p2', $usr, $idB, $expPagesB );
-               $this->assertOneList( 'ed-p3', $usr, $idB, $expListsB, 
$expListsB2 );
+               $this->assertLists( 'ed-p3', $usr, $idB, $expListsB, 
$expListsB2 );
        }
 
        public function testMultipleLists() {
@@ -567,15 +671,13 @@
                //
                // Use owner param
                // user: get all with owner=user
-               $res = $this->getLists( "$p i0", $u, '"lstowner":' . $n );
-               $this->assertListsEquals( "$p i0", $res,
+               $this->assertLists( "$p i0", $u, '"lstowner":' . $n,
                        '[{"id":' . $wlId . ', 
"watchlist":true,"label":"Watchlist"}, ' .
                        '{"id":' . $idA . ', "label":"A"},' . '{"id":' . $idB . 
', "label":"B"}]' );
 
                // user: get by idA with owner=user
-               $res = $this->getLists( "$p i0a", $u,
-                       '"lstowner": ' . $n . ', "lstids": ' . $idA );
-               $this->assertListsEquals( "$p i0a", $res, '[{"id":' . $idA . ', 
"label":"A"}]' );
+               $this->assertLists( "$p i0a", $u, '"lstowner": ' . $n . ', 
"lstids": ' . $idA,
+                       '[{"id":' . $idA . ', "label":"A"}]' );
 
                // anon: get all with owner=user
                $res = $this->getLists( "$p i1", $a, '"lstowner":' . $n );
@@ -600,6 +702,10 @@
                // user2: get by idB with owner=user
                $res = $this->getLists( "$p i5", $u2, '"lstowner": ' . $n . ', 
"lstids": ' . $idB );
                $this->assertListNoId( "$p i5", $res, '[{"label":"B"}]' );
+
+               $res = $this->editList( "$p j1", $u, $token, '"id":' . $idB . 
', "mode":"deletelist"' );
+               $this->getVal( "$p j1", '"status"', $res, 'deleted' );
+               $this->getVal( "$p j1", '"id"', $res, $idB );
        }
 
        public function testWatchlistOnly() {
@@ -688,20 +794,13 @@
 
                $wlOnly = array( array( 'id' => $id, 'watchlist' => true, 
'label' => 'Watchlist' ) );
 
-               $res = $this->getLists( 'nc-f2', $u, '{}' );
-               $this->assertListsEquals( 'nc-f2', $res, $wlOnly );
-
-               $res = $this->getLists( 'nc-f3', $u, '"lstids": 0' );
-               $this->assertListsEquals( 'nc-f3', $res, $wlOnly );
-
-               $res = $this->getLists( 'nc-f4', $u, '"lstprop": 
"label|description|public|count"' );
-               $this->assertListsEquals( 'nc-f4', $res,
+               $this->assertLists( 'nc-f2', $u, '{}', $wlOnly );
+               $this->assertLists( 'nc-f3', $u, '"lstids": 0', $wlOnly );
+               $this->assertLists( 'nc-f4', $u, '"lstprop": 
"label|description|public|count"',
                        '[{"id":' . $id .
                        
',"watchlist":true,"count":1,"label":"Watchlist","description":"aa",' .
                        '"public":false,"perm":"private"}]' );
-
-               $res = $this->getLists( 'nc-f5', $u, '"lsttitle": 
"Gather-ListW"' );
-               $this->assertListsEquals( 'nc-f5', $res, '[{"id":' . $id .
+               $this->assertLists( 'nc-f5', $u, '"lsttitle": "Gather-ListW"', 
'[{"id":' . $id .
                        ',"watchlist":true,"label":"Watchlist","title":true}]' 
);
 
                //
@@ -820,7 +919,6 @@
                }
        }
 
-
        private function toApiParams( $message, $default, $token, $params ) {
                $params = $this->toArr( $message, $params, true );
                if ( !isset( $params['action'] ) ) {
@@ -888,9 +986,12 @@
 
        /**
         * Debugging function to track the sate of the table during test 
development
-        * @param string $table
+        * @param bool|string $table
         */
-       private function dumpTable( $table ) {
+       private function dumpTable( $table = false ) {
+               if ( !$table ) {
+                       $table = 'gather_list';
+               }
                echo "\nTable dump $table:\n";
                foreach ( $this->db->select( $table, '*' ) as $row ) {
                        echo $this->toStr( $row ) . "\n";
@@ -898,24 +999,56 @@
                echo "\nEnd of the table dump $table\n";
        }
 
-       private function assertOneList( $message, $u, $id, $expected, 
$expectedProp = null ) {
-               $params = '"lstids":' . $id;
+       /**
+        * @param $message
+        * @param User $u
+        * @param $params
+        * @param null|array|object $expected  if null, expect empty, if 
object, expect one page,
+        *        if array, expect several pages
+        * @param null|array|object $expectedProp
+        */
+       private function assertLists( $message, $u, $params, $expected, 
$expectedProp = null ) {
+               if ( is_integer( $params ) ) {
+                       $params = '"lstids":' . $params;
+               }
+               $params = $this->toArr( $message, $params, true );
+               if ( $expected ) {
+                       if ( is_object( $expected ) ) {
+                               $expected = array( (array)$expected );
+                       } elseif ( is_string( $expected ) ) {
+                               $expected = $this->toArr( $message, $expected );
+                       } elseif( is_array( $expected ) ) {
+                               $expected = array_map( function ( $v ) {
+                                       return (array)$v;
+                               }, $expected );
+                       }
+               }
+               if ( $expectedProp ) {
+                       if ( is_object( $expectedProp ) ) {
+                               $expectedProp = array( (array)$expectedProp );
+                       } elseif ( is_string( $expectedProp ) ) {
+                               $expectedProp = $this->toArr( $message, 
$expectedProp );
+                       } elseif( is_array( $expectedProp ) ) {
+                               $expectedProp = array_map( function ( $v ) {
+                                       return (array)$v;
+                               }, $expectedProp );
+                       }
+               }
                $res = $this->getLists( $message, $u, $params );
                $lst = $this->getVal( $message, '"query", "lists"', $res );
+
                if ( $expected === null ) {
                        $this->assertCount( 0, $lst, $message );
                } else {
-                       $this->assertCount( 1, $lst, $message );
-                       $this->assertEquals( $expected, $lst[0], $message );
+                       $this->assertEquals( $expected, $lst, $message );
                }
 
                if ( $expectedProp ) {
-                       $params .= ', 
"lstprop":"label|description|public|image|count"';
+                       $params['lstprop'] = 
'label|description|public|image|count';
                        $message .= '-p';
                        $res = $this->getLists( $message, $u, $params );
                        $lst = $this->getVal( $message, '"query", "lists"', 
$res );
-                       $this->assertCount( 1, $lst, $message );
-                       $this->assertEquals( $expectedProp, $lst[0], $message );
+                       $this->assertEquals( $expectedProp, $lst, $message );
                }
        }
 

-- 
To view, visit https://gerrit.wikimedia.org/r/201118
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Id18e7c92110dae5e690e7a6cc5d386c639b3de32
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Gather
Gerrit-Branch: wmf/1.25wmf22
Gerrit-Owner: Jdlrobson <jrob...@wikimedia.org>
Gerrit-Reviewer: Phuedx <g...@samsmith.io>
Gerrit-Reviewer: Yurik <yu...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to