]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - tests/phpunit/includes/api/ApiQueryWatchlistIntegrationTest.php
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / tests / phpunit / includes / api / ApiQueryWatchlistIntegrationTest.php
1 <?php
2
3 use MediaWiki\Linker\LinkTarget;
4 use MediaWiki\MediaWikiServices;
5
6 /**
7  * @group API
8  * @group Database
9  * @group medium
10  *
11  * @covers ApiQueryWatchlist
12  */
13 class ApiQueryWatchlistIntegrationTest extends ApiTestCase {
14
15         public function __construct( $name = null, array $data = [], $dataName = '' ) {
16                 parent::__construct( $name, $data, $dataName );
17                 $this->tablesUsed = array_unique(
18                         array_merge( $this->tablesUsed, [ 'watchlist', 'recentchanges', 'page' ] )
19                 );
20         }
21
22         protected function setUp() {
23                 parent::setUp();
24                 self::$users['ApiQueryWatchlistIntegrationTestUser'] = $this->getMutableTestUser();
25                 self::$users['ApiQueryWatchlistIntegrationTestUser2'] = $this->getMutableTestUser();
26                 $this->doLogin( 'ApiQueryWatchlistIntegrationTestUser' );
27         }
28
29         private function getLoggedInTestUser() {
30                 return self::$users['ApiQueryWatchlistIntegrationTestUser']->getUser();
31         }
32
33         private function getNonLoggedInTestUser() {
34                 return self::$users['ApiQueryWatchlistIntegrationTestUser2']->getUser();
35         }
36
37         private function doPageEdit( User $user, LinkTarget $target, $content, $summary ) {
38                 $title = Title::newFromLinkTarget( $target );
39                 $page = WikiPage::factory( $title );
40                 $page->doEditContent(
41                         ContentHandler::makeContent( $content, $title ),
42                         $summary,
43                         0,
44                         false,
45                         $user
46                 );
47         }
48
49         private function doMinorPageEdit( User $user, LinkTarget $target, $content, $summary ) {
50                 $title = Title::newFromLinkTarget( $target );
51                 $page = WikiPage::factory( $title );
52                 $page->doEditContent(
53                         ContentHandler::makeContent( $content, $title ),
54                         $summary,
55                         EDIT_MINOR,
56                         false,
57                         $user
58                 );
59         }
60
61         private function doBotPageEdit( User $user, LinkTarget $target, $content, $summary ) {
62                 $title = Title::newFromLinkTarget( $target );
63                 $page = WikiPage::factory( $title );
64                 $page->doEditContent(
65                         ContentHandler::makeContent( $content, $title ),
66                         $summary,
67                         EDIT_FORCE_BOT,
68                         false,
69                         $user
70                 );
71         }
72
73         private function doAnonPageEdit( LinkTarget $target, $content, $summary ) {
74                 $title = Title::newFromLinkTarget( $target );
75                 $page = WikiPage::factory( $title );
76                 $page->doEditContent(
77                         ContentHandler::makeContent( $content, $title ),
78                         $summary,
79                         0,
80                         false,
81                         User::newFromId( 0 )
82                 );
83         }
84
85         private function doPatrolledPageEdit(
86                 User $user,
87                 LinkTarget $target,
88                 $content,
89                 $summary,
90                 User $patrollingUser
91         ) {
92                 $title = Title::newFromLinkTarget( $target );
93                 $page = WikiPage::factory( $title );
94                 $status = $page->doEditContent(
95                         ContentHandler::makeContent( $content, $title ),
96                         $summary,
97                         0,
98                         false,
99                         $user
100                 );
101                 /** @var Revision $rev */
102                 $rev = $status->value['revision'];
103                 $rc = $rev->getRecentChange();
104                 $rc->doMarkPatrolled( $patrollingUser, false, [] );
105         }
106
107         private function deletePage( LinkTarget $target, $reason ) {
108                 $title = Title::newFromLinkTarget( $target );
109                 $page = WikiPage::factory( $title );
110                 $page->doDeleteArticleReal( $reason );
111         }
112
113         /**
114          * Performs a batch of page edits as a specified user
115          * @param User $user
116          * @param array $editData associative array, keys:
117          *                        - target    => LinkTarget page to edit
118          *                        - content   => string new content
119          *                        - summary   => string edit summary
120          *                        - minorEdit => bool mark as minor edit if true (defaults to false)
121          *                        - botEdit   => bool mark as bot edit if true (defaults to false)
122          */
123         private function doPageEdits( User $user, array $editData ) {
124                 foreach ( $editData as $singleEditData ) {
125                         if ( array_key_exists( 'minorEdit', $singleEditData ) && $singleEditData['minorEdit'] ) {
126                                 $this->doMinorPageEdit(
127                                         $user,
128                                         $singleEditData['target'],
129                                         $singleEditData['content'],
130                                         $singleEditData['summary']
131                                 );
132                                 continue;
133                         }
134                         if ( array_key_exists( 'botEdit', $singleEditData ) && $singleEditData['botEdit'] ) {
135                                 $this->doBotPageEdit(
136                                         $user,
137                                         $singleEditData['target'],
138                                         $singleEditData['content'],
139                                         $singleEditData['summary']
140                                 );
141                                 continue;
142                         }
143                         $this->doPageEdit(
144                                 $user,
145                                 $singleEditData['target'],
146                                 $singleEditData['content'],
147                                 $singleEditData['summary']
148                         );
149                 }
150         }
151
152         private function getWatchedItemStore() {
153                 return MediaWikiServices::getInstance()->getWatchedItemStore();
154         }
155
156         /**
157          * @param User $user
158          * @param LinkTarget[] $targets
159          */
160         private function watchPages( User $user, array $targets ) {
161                 $store = $this->getWatchedItemStore();
162                 $store->addWatchBatchForUser( $user, $targets );
163         }
164
165         private function doListWatchlistRequest( array $params = [], $user = null ) {
166                 return $this->doApiRequest(
167                         array_merge(
168                                 [ 'action' => 'query', 'list' => 'watchlist' ],
169                                 $params
170                         ), null, false, $user
171                 );
172         }
173
174         private function doGeneratorWatchlistRequest( array $params = [] ) {
175                 return $this->doApiRequest(
176                         array_merge(
177                                 [ 'action' => 'query', 'generator' => 'watchlist' ],
178                                 $params
179                         )
180                 );
181         }
182
183         private function getItemsFromApiResponse( array $response ) {
184                 return $response[0]['query']['watchlist'];
185         }
186
187         /**
188          * Convenience method to assert that actual items array fetched from API is equal to the expected
189          * array, Unlike assertEquals this only checks if values of specified keys are equal in both
190          * arrays. This could be used e.g. not to compare IDs that could change between test run
191          * but only stable keys.
192          * Optionally this also checks that specified keys are present in the actual item without
193          * performing any checks on the related values.
194          *
195          * @param array $actualItems               array of actual items (associative arrays)
196          * @param array $expectedItems             array of expected items (associative arrays),
197          *                                         those items have less keys than actual items
198          * @param array $keysUsedInValueComparison list of keys of the actual item that will be used
199          *                                         in the comparison of values
200          * @param array $requiredKeys              optional, list of keys that must be present in the
201          *                                         actual items. Values of those keys are not checked.
202          */
203         private function assertArraySubsetsEqual(
204                 array $actualItems,
205                 array $expectedItems,
206                 array $keysUsedInValueComparison,
207                 array $requiredKeys = []
208         ) {
209                 $this->assertCount( count( $expectedItems ), $actualItems );
210
211                 // not checking values of all keys of the actual item, so removing unwanted keys from comparison
212                 $actualItemsOnlyComparedValues = array_map(
213                         function ( array $item ) use ( $keysUsedInValueComparison ) {
214                                 return array_intersect_key( $item, array_flip( $keysUsedInValueComparison ) );
215                         },
216                         $actualItems
217                 );
218
219                 $this->assertEquals(
220                         $expectedItems,
221                         $actualItemsOnlyComparedValues
222                 );
223
224                 // Check that each item in $actualItems contains all of keys specified in $requiredKeys
225                 $actualItemsKeysOnly = array_map( 'array_keys', $actualItems );
226                 foreach ( $actualItemsKeysOnly as $keysOfTheItem ) {
227                         $this->assertEmpty( array_diff( $requiredKeys, $keysOfTheItem ) );
228                 }
229         }
230
231         private function getTitleFormatter() {
232                 return new MediaWikiTitleCodec(
233                         Language::factory( 'en' ),
234                         MediaWikiServices::getInstance()->getGenderCache()
235                 );
236         }
237
238         private function getPrefixedText( LinkTarget $target ) {
239                 $formatter = $this->getTitleFormatter();
240                 return $formatter->getPrefixedText( $target );
241         }
242
243         private function cleanTestUsersWatchlist() {
244                 $user = $this->getLoggedInTestUser();
245                 $store = $this->getWatchedItemStore();
246                 $items = $store->getWatchedItemsForUser( $user );
247                 foreach ( $items as $item ) {
248                         $store->removeWatch( $user, $item->getLinkTarget() );
249                 }
250         }
251
252         public function testListWatchlist_returnsWatchedItemsWithRCInfo() {
253                 // Clean up after previous tests that might have added something to the watchlist of
254                 // the user with the same user ID as user used here as the test user
255                 $this->cleanTestUsersWatchlist();
256
257                 $user = $this->getLoggedInTestUser();
258                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
259                 $this->doPageEdit(
260                         $user,
261                         $target,
262                         'Some Content',
263                         'Create the page'
264                 );
265                 $this->watchPages( $user, [ $target ] );
266
267                 $result = $this->doListWatchlistRequest();
268
269                 $this->assertArrayHasKey( 'query', $result[0] );
270                 $this->assertArrayHasKey( 'watchlist', $result[0]['query'] );
271
272                 $this->assertArraySubsetsEqual(
273                         $this->getItemsFromApiResponse( $result ),
274                         [
275                                 [
276                                         'type' => 'new',
277                                         'ns' => $target->getNamespace(),
278                                         'title' => $this->getPrefixedText( $target ),
279                                         'bot' => false,
280                                         'new' => true,
281                                         'minor' => false,
282                                 ]
283                         ],
284                         [ 'type', 'ns', 'title', 'bot', 'new', 'minor' ],
285                         [ 'pageid', 'revid', 'old_revid' ]
286                 );
287         }
288
289         public function testIdsPropParameter() {
290                 $user = $this->getLoggedInTestUser();
291                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
292                 $this->doPageEdit(
293                         $user,
294                         $target,
295                         'Some Content',
296                         'Create the page'
297                 );
298                 $this->watchPages( $user, [ $target ] );
299
300                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'ids', ] );
301                 $items = $this->getItemsFromApiResponse( $result );
302
303                 $this->assertCount( 1, $items );
304                 $this->assertArrayHasKey( 'pageid', $items[0] );
305                 $this->assertArrayHasKey( 'revid', $items[0] );
306                 $this->assertArrayHasKey( 'old_revid', $items[0] );
307                 $this->assertEquals( 'new', $items[0]['type'] );
308         }
309
310         public function testTitlePropParameter() {
311                 $user = $this->getLoggedInTestUser();
312                 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
313                 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
314                 $this->doPageEdits(
315                         $user,
316                         [
317                                 [
318                                         'target' => $subjectTarget,
319                                         'content' => 'Some Content',
320                                         'summary' => 'Create the page',
321                                 ],
322                                 [
323                                         'target' => $talkTarget,
324                                         'content' => 'Some Talk Page Content',
325                                         'summary' => 'Create Talk page',
326                                 ],
327                         ]
328                 );
329                 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
330
331                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', ] );
332
333                 $this->assertEquals(
334                         [
335                                 [
336                                         'type' => 'new',
337                                         'ns' => $talkTarget->getNamespace(),
338                                         'title' => $this->getPrefixedText( $talkTarget ),
339                                 ],
340                                 [
341                                         'type' => 'new',
342                                         'ns' => $subjectTarget->getNamespace(),
343                                         'title' => $this->getPrefixedText( $subjectTarget ),
344                                 ],
345                         ],
346                         $this->getItemsFromApiResponse( $result )
347                 );
348         }
349
350         public function testFlagsPropParameter() {
351                 $user = $this->getLoggedInTestUser();
352                 $normalEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
353                 $minorEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageM' );
354                 $botEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageB' );
355                 $this->doPageEdits(
356                         $user,
357                         [
358                                 [
359                                         'target' => $normalEditTarget,
360                                         'content' => 'Some Content',
361                                         'summary' => 'Create the page',
362                                 ],
363                                 [
364                                         'target' => $minorEditTarget,
365                                         'content' => 'Some Content',
366                                         'summary' => 'Create the page',
367                                 ],
368                                 [
369                                         'target' => $minorEditTarget,
370                                         'content' => 'Slightly Better Content',
371                                         'summary' => 'Change content',
372                                         'minorEdit' => true,
373                                 ],
374                                 [
375                                         'target' => $botEditTarget,
376                                         'content' => 'Some Content',
377                                         'summary' => 'Create the page with a bot',
378                                         'botEdit' => true,
379                                 ],
380                         ]
381                 );
382                 $this->watchPages( $user, [ $normalEditTarget, $minorEditTarget, $botEditTarget ] );
383
384                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'flags', ] );
385
386                 $this->assertEquals(
387                         [
388                                 [
389                                         'type' => 'new',
390                                         'new' => true,
391                                         'minor' => false,
392                                         'bot' => true,
393                                 ],
394                                 [
395                                         'type' => 'edit',
396                                         'new' => false,
397                                         'minor' => true,
398                                         'bot' => false,
399                                 ],
400                                 [
401                                         'type' => 'new',
402                                         'new' => true,
403                                         'minor' => false,
404                                         'bot' => false,
405                                 ],
406                         ],
407                         $this->getItemsFromApiResponse( $result )
408                 );
409         }
410
411         public function testUserPropParameter() {
412                 $user = $this->getLoggedInTestUser();
413                 $userEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
414                 $anonEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageA' );
415                 $this->doPageEdit(
416                         $user,
417                         $userEditTarget,
418                         'Some Content',
419                         'Create the page'
420                 );
421                 $this->doAnonPageEdit(
422                         $anonEditTarget,
423                         'Some Content',
424                         'Create the page'
425                 );
426                 $this->watchPages( $user, [ $userEditTarget, $anonEditTarget ] );
427
428                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'user', ] );
429
430                 $this->assertEquals(
431                         [
432                                 [
433                                         'type' => 'new',
434                                         'anon' => true,
435                                         'user' => User::newFromId( 0 )->getName(),
436                                 ],
437                                 [
438                                         'type' => 'new',
439                                         'user' => $user->getName(),
440                                 ],
441                         ],
442                         $this->getItemsFromApiResponse( $result )
443                 );
444         }
445
446         public function testUserIdPropParameter() {
447                 $user = $this->getLoggedInTestUser();
448                 $userEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
449                 $anonEditTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPageA' );
450                 $this->doPageEdit(
451                         $user,
452                         $userEditTarget,
453                         'Some Content',
454                         'Create the page'
455                 );
456                 $this->doAnonPageEdit(
457                         $anonEditTarget,
458                         'Some Content',
459                         'Create the page'
460                 );
461                 $this->watchPages( $user, [ $userEditTarget, $anonEditTarget ] );
462
463                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'userid', ] );
464
465                 $this->assertEquals(
466                         [
467                                 [
468                                         'type' => 'new',
469                                         'anon' => true,
470                                         'user' => 0,
471                                         'userid' => 0,
472                                 ],
473                                 [
474                                         'type' => 'new',
475                                         'user' => $user->getId(),
476                                         'userid' => $user->getId(),
477                                 ],
478                         ],
479                         $this->getItemsFromApiResponse( $result )
480                 );
481         }
482
483         public function testCommentPropParameter() {
484                 $user = $this->getLoggedInTestUser();
485                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
486                 $this->doPageEdit(
487                         $user,
488                         $target,
489                         'Some Content',
490                         'Create the <b>page</b>'
491                 );
492                 $this->watchPages( $user, [ $target ] );
493
494                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'comment', ] );
495
496                 $this->assertEquals(
497                         [
498                                 [
499                                         'type' => 'new',
500                                         'comment' => 'Create the <b>page</b>',
501                                 ],
502                         ],
503                         $this->getItemsFromApiResponse( $result )
504                 );
505         }
506
507         public function testParsedCommentPropParameter() {
508                 $user = $this->getLoggedInTestUser();
509                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
510                 $this->doPageEdit(
511                         $user,
512                         $target,
513                         'Some Content',
514                         'Create the <b>page</b>'
515                 );
516                 $this->watchPages( $user, [ $target ] );
517
518                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'parsedcomment', ] );
519
520                 $this->assertEquals(
521                         [
522                                 [
523                                         'type' => 'new',
524                                         'parsedcomment' => 'Create the &lt;b&gt;page&lt;/b&gt;',
525                                 ],
526                         ],
527                         $this->getItemsFromApiResponse( $result )
528                 );
529         }
530
531         public function testTimestampPropParameter() {
532                 $user = $this->getLoggedInTestUser();
533                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
534                 $this->doPageEdit(
535                         $user,
536                         $target,
537                         'Some Content',
538                         'Create the page'
539                 );
540                 $this->watchPages( $user, [ $target ] );
541
542                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'timestamp', ] );
543                 $items = $this->getItemsFromApiResponse( $result );
544
545                 $this->assertCount( 1, $items );
546                 $this->assertArrayHasKey( 'timestamp', $items[0] );
547                 $this->assertInternalType( 'string', $items[0]['timestamp'] );
548         }
549
550         public function testSizesPropParameter() {
551                 $user = $this->getLoggedInTestUser();
552                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
553                 $this->doPageEdit(
554                         $user,
555                         $target,
556                         'Some Content',
557                         'Create the page'
558                 );
559                 $this->watchPages( $user, [ $target ] );
560
561                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'sizes', ] );
562
563                 $this->assertEquals(
564                         [
565                                 [
566                                         'type' => 'new',
567                                         'oldlen' => 0,
568                                         'newlen' => 12,
569                                 ],
570                         ],
571                         $this->getItemsFromApiResponse( $result )
572                 );
573         }
574
575         public function testNotificationTimestampPropParameter() {
576                 $otherUser = $this->getNonLoggedInTestUser();
577                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
578                 $this->doPageEdit(
579                         $otherUser,
580                         $target,
581                         'Some Content',
582                         'Create the page'
583                 );
584                 $store = $this->getWatchedItemStore();
585                 $store->addWatch( $this->getLoggedInTestUser(), $target );
586                 $store->updateNotificationTimestamp(
587                         $otherUser,
588                         $target,
589                         '20151212010101'
590                 );
591
592                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'notificationtimestamp', ] );
593
594                 $this->assertEquals(
595                         [
596                                 [
597                                         'type' => 'new',
598                                         'notificationtimestamp' => '2015-12-12T01:01:01Z',
599                                 ],
600                         ],
601                         $this->getItemsFromApiResponse( $result )
602                 );
603         }
604
605         private function setupPatrolledSpecificFixtures( User $user ) {
606                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
607
608                 $this->doPatrolledPageEdit(
609                         $user,
610                         $target,
611                         'Some Content',
612                         'Create the page (this gets patrolled)',
613                         $user
614                 );
615
616                 $this->watchPages( $user, [ $target ] );
617         }
618
619         public function testPatrolPropParameter() {
620                 $testUser = static::getTestSysop();
621                 $user = $testUser->getUser();
622                 $this->setupPatrolledSpecificFixtures( $user );
623
624                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'patrol', ], $user );
625
626                 $this->assertEquals(
627                         [
628                                 [
629                                         'type' => 'new',
630                                         'patrolled' => true,
631                                         'unpatrolled' => false,
632                                 ]
633                         ],
634                         $this->getItemsFromApiResponse( $result )
635                 );
636         }
637
638         private function createPageAndDeleteIt( LinkTarget $target ) {
639                 $this->doPageEdit(
640                         $this->getLoggedInTestUser(),
641                         $target,
642                         'Some Content',
643                         'Create the page that will be deleted'
644                 );
645                 $this->deletePage( $target, 'Important Reason' );
646         }
647
648         public function testLoginfoPropParameter() {
649                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
650                 $this->createPageAndDeleteIt( $target );
651
652                 $this->watchPages( $this->getLoggedInTestUser(), [ $target ] );
653
654                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'loginfo', ] );
655
656                 $this->assertArraySubsetsEqual(
657                         $this->getItemsFromApiResponse( $result ),
658                         [
659                                 [
660                                         'type' => 'log',
661                                         'logtype' => 'delete',
662                                         'logaction' => 'delete',
663                                         'logparams' => [],
664                                 ],
665                         ],
666                         [ 'type', 'logtype', 'logaction', 'logparams' ],
667                         [ 'logid' ]
668                 );
669         }
670
671         public function testEmptyPropParameter() {
672                 $user = $this->getLoggedInTestUser();
673                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
674                 $this->doPageEdit(
675                         $user,
676                         $target,
677                         'Some Content',
678                         'Create the page'
679                 );
680                 $this->watchPages( $user, [ $target ] );
681
682                 $result = $this->doListWatchlistRequest( [ 'wlprop' => '', ] );
683
684                 $this->assertEquals(
685                         [
686                                 [
687                                         'type' => 'new',
688                                 ]
689                         ],
690                         $this->getItemsFromApiResponse( $result )
691                 );
692         }
693
694         public function testNamespaceParam() {
695                 $user = $this->getLoggedInTestUser();
696                 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
697                 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
698                 $this->doPageEdits(
699                         $user,
700                         [
701                                 [
702                                         'target' => $subjectTarget,
703                                         'content' => 'Some Content',
704                                         'summary' => 'Create the page',
705                                 ],
706                                 [
707                                         'target' => $talkTarget,
708                                         'content' => 'Some Content',
709                                         'summary' => 'Create the talk page',
710                                 ],
711                         ]
712                 );
713                 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
714
715                 $result = $this->doListWatchlistRequest( [ 'wlnamespace' => '0', ] );
716
717                 $this->assertArraySubsetsEqual(
718                         $this->getItemsFromApiResponse( $result ),
719                         [
720                                 [
721                                         'ns' => 0,
722                                         'title' => $this->getPrefixedText( $subjectTarget ),
723                                 ],
724                         ],
725                         [ 'ns', 'title' ]
726                 );
727         }
728
729         public function testUserParam() {
730                 $user = $this->getLoggedInTestUser();
731                 $otherUser = $this->getNonLoggedInTestUser();
732                 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
733                 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
734                 $this->doPageEdit(
735                         $user,
736                         $subjectTarget,
737                         'Some Content',
738                         'Create the page'
739                 );
740                 $this->doPageEdit(
741                         $otherUser,
742                         $talkTarget,
743                         'What is this page about?',
744                         'Create the talk page'
745                 );
746                 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
747
748                 $result = $this->doListWatchlistRequest( [
749                         'wlprop' => 'user|title',
750                         'wluser' => $otherUser->getName(),
751                 ] );
752
753                 $this->assertEquals(
754                         [
755                                 [
756                                         'type' => 'new',
757                                         'ns' => $talkTarget->getNamespace(),
758                                         'title' => $this->getPrefixedText( $talkTarget ),
759                                         'user' => $otherUser->getName(),
760                                 ],
761                         ],
762                         $this->getItemsFromApiResponse( $result )
763                 );
764         }
765
766         public function testExcludeUserParam() {
767                 $user = $this->getLoggedInTestUser();
768                 $otherUser = $this->getNonLoggedInTestUser();
769                 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
770                 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
771                 $this->doPageEdit(
772                         $user,
773                         $subjectTarget,
774                         'Some Content',
775                         'Create the page'
776                 );
777                 $this->doPageEdit(
778                         $otherUser,
779                         $talkTarget,
780                         'What is this page about?',
781                         'Create the talk page'
782                 );
783                 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
784
785                 $result = $this->doListWatchlistRequest( [
786                         'wlprop' => 'user|title',
787                         'wlexcludeuser' => $otherUser->getName(),
788                 ] );
789
790                 $this->assertEquals(
791                         [
792                                 [
793                                         'type' => 'new',
794                                         'ns' => $subjectTarget->getNamespace(),
795                                         'title' => $this->getPrefixedText( $subjectTarget ),
796                                         'user' => $user->getName(),
797                                 ]
798                         ],
799                         $this->getItemsFromApiResponse( $result )
800                 );
801         }
802
803         public function testShowMinorParams() {
804                 $user = $this->getLoggedInTestUser();
805                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
806                 $this->doPageEdits(
807                         $user,
808                         [
809                                 [
810                                         'target' => $target,
811                                         'content' => 'Some Content',
812                                         'summary' => 'Create the page',
813                                 ],
814                                 [
815                                         'target' => $target,
816                                         'content' => 'Slightly Better Content',
817                                         'summary' => 'Change content',
818                                         'minorEdit' => true,
819                                 ],
820                         ]
821                 );
822                 $this->watchPages( $user, [ $target ] );
823
824                 $resultMinor = $this->doListWatchlistRequest( [
825                         'wlshow' => WatchedItemQueryService::FILTER_MINOR,
826                         'wlprop' => 'flags'
827                 ] );
828                 $resultNotMinor = $this->doListWatchlistRequest( [
829                         'wlshow' => WatchedItemQueryService::FILTER_NOT_MINOR, 'wlprop' => 'flags'
830                 ] );
831
832                 $this->assertArraySubsetsEqual(
833                         $this->getItemsFromApiResponse( $resultMinor ),
834                         [
835                                 [ 'minor' => true, ]
836                         ],
837                         [ 'minor' ]
838                 );
839                 $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotMinor ) );
840         }
841
842         public function testShowBotParams() {
843                 $user = $this->getLoggedInTestUser();
844                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
845                 $this->doBotPageEdit(
846                         $user,
847                         $target,
848                         'Some Content',
849                         'Create the page'
850                 );
851                 $this->watchPages( $user, [ $target ] );
852
853                 $resultBot = $this->doListWatchlistRequest( [
854                         'wlshow' => WatchedItemQueryService::FILTER_BOT
855                 ] );
856                 $resultNotBot = $this->doListWatchlistRequest( [
857                         'wlshow' => WatchedItemQueryService::FILTER_NOT_BOT
858                 ] );
859
860                 $this->assertArraySubsetsEqual(
861                         $this->getItemsFromApiResponse( $resultBot ),
862                         [
863                                 [ 'bot' => true ],
864                         ],
865                         [ 'bot' ]
866                 );
867                 $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotBot ) );
868         }
869
870         public function testShowAnonParams() {
871                 $user = $this->getLoggedInTestUser();
872                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
873                 $this->doAnonPageEdit(
874                         $target,
875                         'Some Content',
876                         'Create the page'
877                 );
878                 $this->watchPages( $user, [ $target ] );
879
880                 $resultAnon = $this->doListWatchlistRequest( [
881                         'wlprop' => 'user',
882                         'wlshow' => WatchedItemQueryService::FILTER_ANON
883                 ] );
884                 $resultNotAnon = $this->doListWatchlistRequest( [
885                         'wlprop' => 'user',
886                         'wlshow' => WatchedItemQueryService::FILTER_NOT_ANON
887                 ] );
888
889                 $this->assertArraySubsetsEqual(
890                         $this->getItemsFromApiResponse( $resultAnon ),
891                         [
892                                 [ 'anon' => true ],
893                         ],
894                         [ 'anon' ]
895                 );
896                 $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotAnon ) );
897         }
898
899         public function testShowUnreadParams() {
900                 $user = $this->getLoggedInTestUser();
901                 $otherUser = $this->getNonLoggedInTestUser();
902                 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
903                 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
904                 $this->doPageEdit(
905                         $user,
906                         $subjectTarget,
907                         'Some Content',
908                         'Create the page'
909                 );
910                 $this->doPageEdit(
911                         $otherUser,
912                         $talkTarget,
913                         'Some Content',
914                         'Create the talk page'
915                 );
916                 $store = $this->getWatchedItemStore();
917                 $store->addWatchBatchForUser( $user, [ $subjectTarget, $talkTarget ] );
918                 $store->updateNotificationTimestamp(
919                         $otherUser,
920                         $talkTarget,
921                         '20151212010101'
922                 );
923
924                 $resultUnread = $this->doListWatchlistRequest( [
925                         'wlprop' => 'notificationtimestamp|title',
926                         'wlshow' => WatchedItemQueryService::FILTER_UNREAD
927                 ] );
928                 $resultNotUnread = $this->doListWatchlistRequest( [
929                         'wlprop' => 'notificationtimestamp|title',
930                         'wlshow' => WatchedItemQueryService::FILTER_NOT_UNREAD
931                 ] );
932
933                 $this->assertEquals(
934                         [
935                                 [
936                                         'type' => 'new',
937                                         'notificationtimestamp' => '2015-12-12T01:01:01Z',
938                                         'ns' => $talkTarget->getNamespace(),
939                                         'title' => $this->getPrefixedText( $talkTarget )
940                                 ]
941                         ],
942                         $this->getItemsFromApiResponse( $resultUnread )
943                 );
944                 $this->assertEquals(
945                         [
946                                 [
947                                         'type' => 'new',
948                                         'notificationtimestamp' => '',
949                                         'ns' => $subjectTarget->getNamespace(),
950                                         'title' => $this->getPrefixedText( $subjectTarget )
951                                 ]
952                         ],
953                         $this->getItemsFromApiResponse( $resultNotUnread )
954                 );
955         }
956
957         public function testShowPatrolledParams() {
958                 $user = static::getTestSysop()->getUser();
959                 $this->setupPatrolledSpecificFixtures( $user );
960
961                 $resultPatrolled = $this->doListWatchlistRequest( [
962                         'wlprop' => 'patrol',
963                         'wlshow' => WatchedItemQueryService::FILTER_PATROLLED
964                 ], $user );
965                 $resultNotPatrolled = $this->doListWatchlistRequest( [
966                         'wlprop' => 'patrol',
967                         'wlshow' => WatchedItemQueryService::FILTER_NOT_PATROLLED
968                 ], $user );
969
970                 $this->assertEquals(
971                         [
972                                 [
973                                         'type' => 'new',
974                                         'patrolled' => true,
975                                         'unpatrolled' => false,
976                                 ]
977                         ],
978                         $this->getItemsFromApiResponse( $resultPatrolled )
979                 );
980                 $this->assertEmpty( $this->getItemsFromApiResponse( $resultNotPatrolled ) );
981         }
982
983         public function testNewAndEditTypeParameters() {
984                 $user = $this->getLoggedInTestUser();
985                 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
986                 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
987                 $this->doPageEdits(
988                         $user,
989                         [
990                                 [
991                                         'target' => $subjectTarget,
992                                         'content' => 'Some Content',
993                                         'summary' => 'Create the page',
994                                 ],
995                                 [
996                                         'target' => $subjectTarget,
997                                         'content' => 'Some Other Content',
998                                         'summary' => 'Change the content',
999                                 ],
1000                                 [
1001                                         'target' => $talkTarget,
1002                                         'content' => 'Some Talk Page Content',
1003                                         'summary' => 'Create Talk page',
1004                                 ],
1005                         ]
1006                 );
1007                 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
1008
1009                 $resultNew = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'new' ] );
1010                 $resultEdit = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'edit' ] );
1011
1012                 $this->assertEquals(
1013                         [
1014                                 [
1015                                         'type' => 'new',
1016                                         'ns' => $talkTarget->getNamespace(),
1017                                         'title' => $this->getPrefixedText( $talkTarget ),
1018                                 ],
1019                         ],
1020                         $this->getItemsFromApiResponse( $resultNew )
1021                 );
1022                 $this->assertEquals(
1023                         [
1024                                 [
1025                                         'type' => 'edit',
1026                                         'ns' => $subjectTarget->getNamespace(),
1027                                         'title' => $this->getPrefixedText( $subjectTarget ),
1028                                 ],
1029                         ],
1030                         $this->getItemsFromApiResponse( $resultEdit )
1031                 );
1032         }
1033
1034         public function testLogTypeParameters() {
1035                 $user = $this->getLoggedInTestUser();
1036                 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1037                 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
1038                 $this->createPageAndDeleteIt( $subjectTarget );
1039                 $this->doPageEdit(
1040                         $user,
1041                         $talkTarget,
1042                         'Some Talk Page Content',
1043                         'Create Talk page'
1044                 );
1045                 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
1046
1047                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'log' ] );
1048
1049                 $this->assertEquals(
1050                         [
1051                                 [
1052                                         'type' => 'log',
1053                                         'ns' => $subjectTarget->getNamespace(),
1054                                         'title' => $this->getPrefixedText( $subjectTarget ),
1055                                 ],
1056                         ],
1057                         $this->getItemsFromApiResponse( $result )
1058                 );
1059         }
1060
1061         private function getExternalRC( LinkTarget $target ) {
1062                 $title = Title::newFromLinkTarget( $target );
1063
1064                 $rc = new RecentChange;
1065                 $rc->mTitle = $title;
1066                 $rc->mAttribs = [
1067                         'rc_timestamp' => wfTimestamp( TS_MW ),
1068                         'rc_namespace' => $title->getNamespace(),
1069                         'rc_title' => $title->getDBkey(),
1070                         'rc_type' => RC_EXTERNAL,
1071                         'rc_source' => 'foo',
1072                         'rc_minor' => 0,
1073                         'rc_cur_id' => $title->getArticleID(),
1074                         'rc_user' => 0,
1075                         'rc_user_text' => 'External User',
1076                         'rc_comment' => '',
1077                         'rc_comment_text' => '',
1078                         'rc_comment_data' => null,
1079                         'rc_this_oldid' => $title->getLatestRevID(),
1080                         'rc_last_oldid' => $title->getLatestRevID(),
1081                         'rc_bot' => 0,
1082                         'rc_ip' => '',
1083                         'rc_patrolled' => 0,
1084                         'rc_new' => 0,
1085                         'rc_old_len' => $title->getLength(),
1086                         'rc_new_len' => $title->getLength(),
1087                         'rc_deleted' => 0,
1088                         'rc_logid' => 0,
1089                         'rc_log_type' => null,
1090                         'rc_log_action' => '',
1091                         'rc_params' => '',
1092                 ];
1093                 $rc->mExtra = [
1094                         'prefixedDBkey' => $title->getPrefixedDBkey(),
1095                         'lastTimestamp' => 0,
1096                         'oldSize' => $title->getLength(),
1097                         'newSize' => $title->getLength(),
1098                         'pageStatus' => 'changed'
1099                 ];
1100
1101                 return $rc;
1102         }
1103
1104         public function testExternalTypeParameters() {
1105                 $user = $this->getLoggedInTestUser();
1106                 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1107                 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
1108                 $this->doPageEdit(
1109                         $user,
1110                         $subjectTarget,
1111                         'Some Content',
1112                         'Create the page'
1113                 );
1114                 $this->doPageEdit(
1115                         $user,
1116                         $talkTarget,
1117                         'Some Talk Page Content',
1118                         'Create Talk page'
1119                 );
1120
1121                 $rc = $this->getExternalRC( $subjectTarget );
1122                 $rc->save();
1123
1124                 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
1125
1126                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'external' ] );
1127
1128                 $this->assertEquals(
1129                         [
1130                                 [
1131                                         'type' => 'external',
1132                                         'ns' => $subjectTarget->getNamespace(),
1133                                         'title' => $this->getPrefixedText( $subjectTarget ),
1134                                 ],
1135                         ],
1136                         $this->getItemsFromApiResponse( $result )
1137                 );
1138         }
1139
1140         public function testCategorizeTypeParameter() {
1141                 $user = $this->getLoggedInTestUser();
1142                 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1143                 $categoryTarget = new TitleValue( NS_CATEGORY, 'ApiQueryWatchlistIntegrationTestCategory' );
1144                 $this->doPageEdits(
1145                         $user,
1146                         [
1147                                 [
1148                                         'target' => $categoryTarget,
1149                                         'content' => 'Some Content',
1150                                         'summary' => 'Create the category',
1151                                 ],
1152                                 [
1153                                         'target' => $subjectTarget,
1154                                         'content' => 'Some Content [[Category:ApiQueryWatchlistIntegrationTestCategory]]t',
1155                                         'summary' => 'Create the page and add it to the category',
1156                                 ],
1157                         ]
1158                 );
1159                 $title = Title::newFromLinkTarget( $subjectTarget );
1160                 $revision = Revision::newFromTitle( $title );
1161
1162                 $rc = RecentChange::newForCategorization(
1163                         $revision->getTimestamp(),
1164                         Title::newFromLinkTarget( $categoryTarget ),
1165                         $user,
1166                         $revision->getComment(),
1167                         $title,
1168                         0,
1169                         $revision->getId(),
1170                         null,
1171                         false
1172                 );
1173                 $rc->save();
1174
1175                 $this->watchPages( $user, [ $subjectTarget, $categoryTarget ] );
1176
1177                 $result = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wltype' => 'categorize' ] );
1178
1179                 $this->assertEquals(
1180                         [
1181                                 [
1182                                         'type' => 'categorize',
1183                                         'ns' => $categoryTarget->getNamespace(),
1184                                         'title' => $this->getPrefixedText( $categoryTarget ),
1185                                 ],
1186                         ],
1187                         $this->getItemsFromApiResponse( $result )
1188                 );
1189         }
1190
1191         public function testLimitParam() {
1192                 $user = $this->getLoggedInTestUser();
1193                 $target1 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1194                 $target2 = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
1195                 $target3 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage2' );
1196                 $this->doPageEdits(
1197                         $user,
1198                         [
1199                                 [
1200                                         'target' => $target1,
1201                                         'content' => 'Some Content',
1202                                         'summary' => 'Create the page',
1203                                 ],
1204                                 [
1205                                         'target' => $target2,
1206                                         'content' => 'Some Talk Page Content',
1207                                         'summary' => 'Create Talk page',
1208                                 ],
1209                                 [
1210                                         'target' => $target3,
1211                                         'content' => 'Some Other Content',
1212                                         'summary' => 'Create the page',
1213                                 ],
1214                         ]
1215                 );
1216                 $this->watchPages( $user, [ $target1, $target2, $target3 ] );
1217
1218                 $resultWithoutLimit = $this->doListWatchlistRequest( [ 'wlprop' => 'title' ] );
1219                 $resultWithLimit = $this->doListWatchlistRequest( [ 'wllimit' => 2, 'wlprop' => 'title' ] );
1220
1221                 $this->assertEquals(
1222                         [
1223                                 [
1224                                         'type' => 'new',
1225                                         'ns' => $target3->getNamespace(),
1226                                         'title' => $this->getPrefixedText( $target3 )
1227                                 ],
1228                                 [
1229                                         'type' => 'new',
1230                                         'ns' => $target2->getNamespace(),
1231                                         'title' => $this->getPrefixedText( $target2 )
1232                                 ],
1233                                 [
1234                                         'type' => 'new',
1235                                         'ns' => $target1->getNamespace(),
1236                                         'title' => $this->getPrefixedText( $target1 )
1237                                 ],
1238                         ],
1239                         $this->getItemsFromApiResponse( $resultWithoutLimit )
1240                 );
1241                 $this->assertEquals(
1242                         [
1243                                 [
1244                                         'type' => 'new',
1245                                         'ns' => $target3->getNamespace(),
1246                                         'title' => $this->getPrefixedText( $target3 )
1247                                 ],
1248                                 [
1249                                         'type' => 'new',
1250                                         'ns' => $target2->getNamespace(),
1251                                         'title' => $this->getPrefixedText( $target2 )
1252                                 ],
1253                         ],
1254                         $this->getItemsFromApiResponse( $resultWithLimit )
1255                 );
1256                 $this->assertArrayHasKey( 'continue', $resultWithLimit[0] );
1257                 $this->assertArrayHasKey( 'wlcontinue', $resultWithLimit[0]['continue'] );
1258         }
1259
1260         public function testAllRevParam() {
1261                 $user = $this->getLoggedInTestUser();
1262                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1263                 $this->doPageEdits(
1264                         $user,
1265                         [
1266                                 [
1267                                         'target' => $target,
1268                                         'content' => 'Some Content',
1269                                         'summary' => 'Create the page',
1270                                 ],
1271                                 [
1272                                         'target' => $target,
1273                                         'content' => 'Some Other Content',
1274                                         'summary' => 'Change the content',
1275                                 ],
1276                         ]
1277                 );
1278                 $this->watchPages( $user, [ $target ] );
1279
1280                 $resultAllRev = $this->doListWatchlistRequest( [ 'wlprop' => 'title', 'wlallrev' => '', ] );
1281                 $resultNoAllRev = $this->doListWatchlistRequest( [ 'wlprop' => 'title' ] );
1282
1283                 $this->assertEquals(
1284                         [
1285                                 [
1286                                         'type' => 'edit',
1287                                         'ns' => $target->getNamespace(),
1288                                         'title' => $this->getPrefixedText( $target ),
1289                                 ],
1290                         ],
1291                         $this->getItemsFromApiResponse( $resultNoAllRev )
1292                 );
1293                 $this->assertEquals(
1294                         [
1295                                 [
1296                                         'type' => 'edit',
1297                                         'ns' => $target->getNamespace(),
1298                                         'title' => $this->getPrefixedText( $target ),
1299                                 ],
1300                                 [
1301                                         'type' => 'new',
1302                                         'ns' => $target->getNamespace(),
1303                                         'title' => $this->getPrefixedText( $target ),
1304                                 ],
1305                         ],
1306                         $this->getItemsFromApiResponse( $resultAllRev )
1307                 );
1308         }
1309
1310         public function testDirParams() {
1311                 $user = $this->getLoggedInTestUser();
1312                 $subjectTarget = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1313                 $talkTarget = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
1314                 $this->doPageEdits(
1315                         $user,
1316                         [
1317                                 [
1318                                         'target' => $subjectTarget,
1319                                         'content' => 'Some Content',
1320                                         'summary' => 'Create the page',
1321                                 ],
1322                                 [
1323                                         'target' => $talkTarget,
1324                                         'content' => 'Some Talk Page Content',
1325                                         'summary' => 'Create Talk page',
1326                                 ],
1327                         ]
1328                 );
1329                 $this->watchPages( $user, [ $subjectTarget, $talkTarget ] );
1330
1331                 $resultDirOlder = $this->doListWatchlistRequest( [ 'wldir' => 'older', 'wlprop' => 'title' ] );
1332                 $resultDirNewer = $this->doListWatchlistRequest( [ 'wldir' => 'newer', 'wlprop' => 'title' ] );
1333
1334                 $this->assertEquals(
1335                         [
1336                                 [
1337                                         'type' => 'new',
1338                                         'ns' => $talkTarget->getNamespace(),
1339                                         'title' => $this->getPrefixedText( $talkTarget )
1340                                 ],
1341                                 [
1342                                         'type' => 'new',
1343                                         'ns' => $subjectTarget->getNamespace(),
1344                                         'title' => $this->getPrefixedText( $subjectTarget )
1345                                 ],
1346                         ],
1347                         $this->getItemsFromApiResponse( $resultDirOlder )
1348                 );
1349                 $this->assertEquals(
1350                         [
1351                                 [
1352                                         'type' => 'new',
1353                                         'ns' => $subjectTarget->getNamespace(),
1354                                         'title' => $this->getPrefixedText( $subjectTarget )
1355                                 ],
1356                                 [
1357                                         'type' => 'new',
1358                                         'ns' => $talkTarget->getNamespace(),
1359                                         'title' => $this->getPrefixedText( $talkTarget )
1360                                 ],
1361                         ],
1362                         $this->getItemsFromApiResponse( $resultDirNewer )
1363                 );
1364         }
1365
1366         public function testStartEndParams() {
1367                 $user = $this->getLoggedInTestUser();
1368                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1369                 $this->doPageEdit(
1370                         $user,
1371                         $target,
1372                         'Some Content',
1373                         'Create the page'
1374                 );
1375                 $this->watchPages( $user, [ $target ] );
1376
1377                 $resultStart = $this->doListWatchlistRequest( [
1378                         'wlstart' => '20010115000000',
1379                         'wldir' => 'newer',
1380                         'wlprop' => 'title',
1381                 ] );
1382                 $resultEnd = $this->doListWatchlistRequest( [
1383                         'wlend' => '20010115000000',
1384                         'wldir' => 'newer',
1385                         'wlprop' => 'title',
1386                 ] );
1387
1388                 $this->assertEquals(
1389                         [
1390                                 [
1391                                         'type' => 'new',
1392                                         'ns' => $target->getNamespace(),
1393                                         'title' => $this->getPrefixedText( $target ),
1394                                 ]
1395                         ],
1396                         $this->getItemsFromApiResponse( $resultStart )
1397                 );
1398                 $this->assertEmpty( $this->getItemsFromApiResponse( $resultEnd ) );
1399         }
1400
1401         public function testContinueParam() {
1402                 $user = $this->getLoggedInTestUser();
1403                 $target1 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1404                 $target2 = new TitleValue( 1, 'ApiQueryWatchlistIntegrationTestPage' );
1405                 $target3 = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage2' );
1406                 $this->doPageEdits(
1407                         $user,
1408                         [
1409                                 [
1410                                         'target' => $target1,
1411                                         'content' => 'Some Content',
1412                                         'summary' => 'Create the page',
1413                                 ],
1414                                 [
1415                                         'target' => $target2,
1416                                         'content' => 'Some Talk Page Content',
1417                                         'summary' => 'Create Talk page',
1418                                 ],
1419                                 [
1420                                         'target' => $target3,
1421                                         'content' => 'Some Other Content',
1422                                         'summary' => 'Create the page',
1423                                 ],
1424                         ]
1425                 );
1426                 $this->watchPages( $user, [ $target1, $target2, $target3 ] );
1427
1428                 $firstResult = $this->doListWatchlistRequest( [ 'wllimit' => 2, 'wlprop' => 'title' ] );
1429                 $this->assertArrayHasKey( 'continue', $firstResult[0] );
1430                 $this->assertArrayHasKey( 'wlcontinue', $firstResult[0]['continue'] );
1431
1432                 $continuationParam = $firstResult[0]['continue']['wlcontinue'];
1433
1434                 $continuedResult = $this->doListWatchlistRequest(
1435                         [ 'wlcontinue' => $continuationParam, 'wlprop' => 'title' ]
1436                 );
1437
1438                 $this->assertEquals(
1439                         [
1440                                 [
1441                                         'type' => 'new',
1442                                         'ns' => $target3->getNamespace(),
1443                                         'title' => $this->getPrefixedText( $target3 ),
1444                                 ],
1445                                 [
1446                                         'type' => 'new',
1447                                         'ns' => $target2->getNamespace(),
1448                                         'title' => $this->getPrefixedText( $target2 ),
1449                                 ],
1450                         ],
1451                         $this->getItemsFromApiResponse( $firstResult )
1452                 );
1453                 $this->assertEquals(
1454                         [
1455                                 [
1456                                         'type' => 'new',
1457                                         'ns' => $target1->getNamespace(),
1458                                         'title' => $this->getPrefixedText( $target1 )
1459                                 ]
1460                         ],
1461                         $this->getItemsFromApiResponse( $continuedResult )
1462                 );
1463         }
1464
1465         public function testOwnerAndTokenParams() {
1466                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1467                 $this->doPageEdit(
1468                         $this->getLoggedInTestUser(),
1469                         $target,
1470                         'Some Content',
1471                         'Create the page'
1472                 );
1473
1474                 $otherUser = $this->getNonLoggedInTestUser();
1475                 $otherUser->setOption( 'watchlisttoken', '1234567890' );
1476                 $otherUser->saveSettings();
1477
1478                 $this->watchPages( $otherUser, [ $target ] );
1479
1480                 $reloadedUser = User::newFromName( $otherUser->getName() );
1481                 $this->assertEquals( '1234567890', $reloadedUser->getOption( 'watchlisttoken' ) );
1482
1483                 $result = $this->doListWatchlistRequest( [
1484                         'wlowner' => $otherUser->getName(),
1485                         'wltoken' => '1234567890',
1486                         'wlprop' => 'title',
1487                 ] );
1488
1489                 $this->assertEquals(
1490                         [
1491                                 [
1492                                         'type' => 'new',
1493                                         'ns' => $target->getNamespace(),
1494                                         'title' => $this->getPrefixedText( $target )
1495                                 ]
1496                         ],
1497                         $this->getItemsFromApiResponse( $result )
1498                 );
1499         }
1500
1501         public function testOwnerAndTokenParams_wrongToken() {
1502                 $otherUser = $this->getNonLoggedInTestUser();
1503                 $otherUser->setOption( 'watchlisttoken', '1234567890' );
1504                 $otherUser->saveSettings();
1505
1506                 $this->setExpectedException( ApiUsageException::class, 'Incorrect watchlist token provided' );
1507
1508                 $this->doListWatchlistRequest( [
1509                         'wlowner' => $otherUser->getName(),
1510                         'wltoken' => 'wrong-token',
1511                 ] );
1512         }
1513
1514         public function testOwnerAndTokenParams_noWatchlistTokenSet() {
1515                 $this->setExpectedException( ApiUsageException::class, 'Incorrect watchlist token provided' );
1516
1517                 $this->doListWatchlistRequest( [
1518                         'wlowner' => $this->getNonLoggedInTestUser()->getName(),
1519                         'wltoken' => 'some-token',
1520                 ] );
1521         }
1522
1523         public function testGeneratorWatchlistPropInfo_returnsWatchedPages() {
1524                 $user = $this->getLoggedInTestUser();
1525                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1526                 $this->doPageEdit(
1527                         $user,
1528                         $target,
1529                         'Some Content',
1530                         'Create the page'
1531                 );
1532                 $this->watchPages( $user, [ $target ] );
1533
1534                 $result = $this->doGeneratorWatchlistRequest( [ 'prop' => 'info' ] );
1535
1536                 $this->assertArrayHasKey( 'query', $result[0] );
1537                 $this->assertArrayHasKey( 'pages', $result[0]['query'] );
1538
1539                 // $result[0]['query']['pages'] uses page ids as keys. Page ids don't matter here, so drop them
1540                 $pages = array_values( $result[0]['query']['pages'] );
1541
1542                 $this->assertArraySubsetsEqual(
1543                         $pages,
1544                         [
1545                                 [
1546                                         'ns' => $target->getNamespace(),
1547                                         'title' => $this->getPrefixedText( $target ),
1548                                         'new' => true,
1549                                 ]
1550                         ],
1551                         [ 'ns', 'title', 'new' ]
1552                 );
1553         }
1554
1555         public function testGeneratorWatchlistPropRevisions_returnsWatchedItemsRevisions() {
1556                 $user = $this->getLoggedInTestUser();
1557                 $target = new TitleValue( 0, 'ApiQueryWatchlistIntegrationTestPage' );
1558                 $this->doPageEdits(
1559                         $user,
1560                         [
1561                                 [
1562                                         'target' => $target,
1563                                         'content' => 'Some Content',
1564                                         'summary' => 'Create the page',
1565                                 ],
1566                                 [
1567                                         'target' => $target,
1568                                         'content' => 'Some Other Content',
1569                                         'summary' => 'Change the content',
1570                                 ],
1571                         ]
1572                 );
1573                 $this->watchPages( $user, [ $target ] );
1574
1575                 $result = $this->doGeneratorWatchlistRequest( [ 'prop' => 'revisions', 'gwlallrev' => '' ] );
1576
1577                 $this->assertArrayHasKey( 'query', $result[0] );
1578                 $this->assertArrayHasKey( 'pages', $result[0]['query'] );
1579
1580                 // $result[0]['query']['pages'] uses page ids as keys. Page ids don't matter here, so drop them
1581                 $pages = array_values( $result[0]['query']['pages'] );
1582
1583                 $this->assertCount( 1, $pages );
1584                 $this->assertEquals( 0, $pages[0]['ns'] );
1585                 $this->assertEquals( $this->getPrefixedText( $target ), $pages[0]['title'] );
1586                 $this->assertArraySubsetsEqual(
1587                         $pages[0]['revisions'],
1588                         [
1589                                 [
1590                                         'comment' => 'Create the page',
1591                                         'user' => $user->getName(),
1592                                         'minor' => false,
1593                                 ],
1594                                 [
1595                                         'comment' => 'Change the content',
1596                                         'user' => $user->getName(),
1597                                         'minor' => false,
1598                                 ],
1599                         ],
1600                         [ 'comment', 'user', 'minor' ]
1601                 );
1602         }
1603
1604 }