584b141c2cb87ccf5e23180b48952f3caa9ba7cd
[lhc/web/wiklou.git] / tests / phpunit / includes / specialpage / ChangesListSpecialPageTest.php
1 <?php
2
3 use Wikimedia\TestingAccessWrapper;
4
5 /**
6 * Test class for ChangesListSpecialPage class
7 *
8 * Copyright © 2011-, Antoine Musso, Stephane Bisson, Matthew Flaschen
9 *
10 * @author Antoine Musso
11 * @author Stephane Bisson
12 * @author Matthew Flaschen
13 * @group Database
14 *
15 * @covers ChangesListSpecialPage
16 */
17 class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase {
18 protected function getPage() {
19 $mock = $this->getMockBuilder( ChangesListSpecialPage::class )
20 ->setConstructorArgs(
21 [
22 'ChangesListSpecialPage',
23 ''
24 ]
25 )
26 ->setMethods( [ 'getPageTitle' ] )
27 ->getMockForAbstractClass();
28
29 $mock->method( 'getPageTitle' )->willReturn(
30 Title::makeTitle( NS_SPECIAL, 'ChangesListSpecialPage' )
31 );
32
33 $mock = TestingAccessWrapper::newFromObject(
34 $mock
35 );
36
37 return $mock;
38 }
39
40 private function buildQuery(
41 $requestOptions = null,
42 $user = null
43 ) {
44 $context = new RequestContext;
45 $context->setRequest( new FauxRequest( $requestOptions ) );
46 if ( $user ) {
47 $context->setUser( $user );
48 }
49
50 $this->changesListSpecialPage->setContext( $context );
51 $this->changesListSpecialPage->filterGroups = [];
52 $formOptions = $this->changesListSpecialPage->setup( null );
53
54 #  Filter out rc_timestamp conditions which depends on the test runtime
55 # This condition is not needed as of march 2, 2011 -- hashar
56 # @todo FIXME: Find a way to generate the correct rc_timestamp
57
58 $tables = [];
59 $fields = [];
60 $queryConditions = [];
61 $query_options = [];
62 $join_conds = [];
63
64 call_user_func_array(
65 [ $this->changesListSpecialPage, 'buildQuery' ],
66 [
67 &$tables,
68 &$fields,
69 &$queryConditions,
70 &$query_options,
71 &$join_conds,
72 $formOptions
73 ]
74 );
75
76 $queryConditions = array_filter(
77 $queryConditions,
78 'ChangesListSpecialPageTest::filterOutRcTimestampCondition'
79 );
80
81 return $queryConditions;
82 }
83
84 /** helper to test SpecialRecentchanges::buildQuery() */
85 private function assertConditions(
86 $expected,
87 $requestOptions = null,
88 $message = '',
89 $user = null
90 ) {
91 $queryConditions = $this->buildQuery( $requestOptions, $user );
92
93 $this->assertEquals(
94 self::normalizeCondition( $expected ),
95 self::normalizeCondition( $queryConditions ),
96 $message
97 );
98 }
99
100 private static function normalizeCondition( $conds ) {
101 $dbr = wfGetDB( DB_REPLICA );
102 $normalized = array_map(
103 function ( $k, $v ) use ( $dbr ) {
104 if ( is_array( $v ) ) {
105 sort( $v );
106 }
107 // (Ab)use makeList() to format only this entry
108 return $dbr->makeList( [ $k => $v ], Database::LIST_AND );
109 },
110 array_keys( $conds ),
111 $conds
112 );
113 sort( $normalized );
114 return $normalized;
115 }
116
117 /** return false if condition begins with 'rc_timestamp ' */
118 private static function filterOutRcTimestampCondition( $var ) {
119 return ( is_array( $var ) || strpos( $var, 'rc_timestamp ' ) === false );
120 }
121
122 public function testRcNsFilter() {
123 $this->assertConditions(
124 [ # expected
125 "rc_namespace = '0'",
126 ],
127 [
128 'namespace' => NS_MAIN,
129 ],
130 "rc conditions with one namespace"
131 );
132 }
133
134 public function testRcNsFilterInversion() {
135 $this->assertConditions(
136 [ # expected
137 "rc_namespace != '0'",
138 ],
139 [
140 'namespace' => NS_MAIN,
141 'invert' => 1,
142 ],
143 "rc conditions with namespace inverted"
144 );
145 }
146
147 public function testRcNsFilterMultiple() {
148 $this->assertConditions(
149 [ # expected
150 "rc_namespace IN ('1','2','3')",
151 ],
152 [
153 'namespace' => '1;2;3',
154 ],
155 "rc conditions with multiple namespaces"
156 );
157 }
158
159 public function testRcNsFilterMultipleAssociated() {
160 $this->assertConditions(
161 [ # expected
162 "rc_namespace IN ('0','1','4','5','6','7')",
163 ],
164 [
165 'namespace' => '1;4;7',
166 'associated' => 1,
167 ],
168 "rc conditions with multiple namespaces and associated"
169 );
170 }
171
172 public function testRcNsFilterMultipleAssociatedInvert() {
173 $this->assertConditions(
174 [ # expected
175 "rc_namespace NOT IN ('2','3','8','9')",
176 ],
177 [
178 'namespace' => '2;3;9',
179 'associated' => 1,
180 'invert' => 1
181 ],
182 "rc conditions with multiple namespaces, associated and inverted"
183 );
184 }
185
186 public function testRcNsFilterMultipleInvert() {
187 $this->assertConditions(
188 [ # expected
189 "rc_namespace NOT IN ('1','2','3')",
190 ],
191 [
192 'namespace' => '1;2;3',
193 'invert' => 1,
194 ],
195 "rc conditions with multiple namespaces inverted"
196 );
197 }
198
199 public function testRcHidemyselfFilter() {
200 $this->setMwGlobals(
201 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
202 );
203 $this->overrideMwServices();
204
205 $user = $this->getTestUser()->getUser();
206 $user->getActorId( wfGetDB( DB_MASTER ) );
207 $this->assertConditions(
208 [ # expected
209 "NOT((rc_user = '{$user->getId()}'))",
210 ],
211 [
212 'hidemyself' => 1,
213 ],
214 "rc conditions: hidemyself=1 (logged in)",
215 $user
216 );
217
218 $user = User::newFromName( '10.11.12.13', false );
219 $id = $user->getActorId( wfGetDB( DB_MASTER ) );
220 $this->assertConditions(
221 [ # expected
222 "NOT((rc_user_text = '10.11.12.13'))",
223 ],
224 [
225 'hidemyself' => 1,
226 ],
227 "rc conditions: hidemyself=1 (anon)",
228 $user
229 );
230 }
231
232 public function testRcHidebyothersFilter() {
233 $this->setMwGlobals(
234 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
235 );
236 $this->overrideMwServices();
237
238 $user = $this->getTestUser()->getUser();
239 $user->getActorId( wfGetDB( DB_MASTER ) );
240 $this->assertConditions(
241 [ # expected
242 "(rc_user_text = '{$user->getName()}')",
243 ],
244 [
245 'hidebyothers' => 1,
246 ],
247 "rc conditions: hidebyothers=1 (logged in)",
248 $user
249 );
250
251 $user = User::newFromName( '10.11.12.13', false );
252 $id = $user->getActorId( wfGetDB( DB_MASTER ) );
253 $this->assertConditions(
254 [ # expected
255 "(rc_user_text = '10.11.12.13')",
256 ],
257 [
258 'hidebyothers' => 1,
259 ],
260 "rc conditions: hidebyothers=1 (anon)",
261 $user
262 );
263 }
264
265 public function testRcHidepageedits() {
266 $this->assertConditions(
267 [ # expected
268 "rc_type != '0'",
269 ],
270 [
271 'hidepageedits' => 1,
272 ],
273 "rc conditions: hidepageedits=1"
274 );
275 }
276
277 public function testRcHidenewpages() {
278 $this->assertConditions(
279 [ # expected
280 "rc_type != '1'",
281 ],
282 [
283 'hidenewpages' => 1,
284 ],
285 "rc conditions: hidenewpages=1"
286 );
287 }
288
289 public function testRcHidelog() {
290 $this->assertConditions(
291 [ # expected
292 "rc_type != '3'",
293 ],
294 [
295 'hidelog' => 1,
296 ],
297 "rc conditions: hidelog=1"
298 );
299 }
300
301 public function testRcHidehumans() {
302 $this->assertConditions(
303 [ # expected
304 'rc_bot' => 1,
305 ],
306 [
307 'hidebots' => 0,
308 'hidehumans' => 1,
309 ],
310 "rc conditions: hidebots=0 hidehumans=1"
311 );
312 }
313
314 public function testRcHidepatrolledDisabledFilter() {
315 $this->setMwGlobals( 'wgUseRCPatrol', false );
316 $user = $this->getTestUser()->getUser();
317 $this->assertConditions(
318 [ # expected
319 ],
320 [
321 'hidepatrolled' => 1,
322 ],
323 "rc conditions: hidepatrolled=1 (user not allowed)",
324 $user
325 );
326 }
327
328 public function testRcHideunpatrolledDisabledFilter() {
329 $this->setMwGlobals( 'wgUseRCPatrol', false );
330 $user = $this->getTestUser()->getUser();
331 $this->assertConditions(
332 [ # expected
333 ],
334 [
335 'hideunpatrolled' => 1,
336 ],
337 "rc conditions: hideunpatrolled=1 (user not allowed)",
338 $user
339 );
340 }
341 public function testRcHidepatrolledFilter() {
342 $user = $this->getTestSysop()->getUser();
343 $this->assertConditions(
344 [ # expected
345 'rc_patrolled' => 0,
346 ],
347 [
348 'hidepatrolled' => 1,
349 ],
350 "rc conditions: hidepatrolled=1",
351 $user
352 );
353 }
354
355 public function testRcHideunpatrolledFilter() {
356 $user = $this->getTestSysop()->getUser();
357 $this->assertConditions(
358 [ # expected
359 'rc_patrolled' => [ 1, 2 ],
360 ],
361 [
362 'hideunpatrolled' => 1,
363 ],
364 "rc conditions: hideunpatrolled=1",
365 $user
366 );
367 }
368
369 public function testRcReviewStatusFilter() {
370 $user = $this->getTestSysop()->getUser();
371 $this->assertConditions(
372 [ #expected
373 'rc_patrolled' => 1,
374 ],
375 [
376 'reviewStatus' => 'manual'
377 ],
378 "rc conditions: reviewStatus=manual",
379 $user
380 );
381 $this->assertConditions(
382 [ #expected
383 'rc_patrolled' => [ 0, 2 ],
384 ],
385 [
386 'reviewStatus' => 'unpatrolled;auto'
387 ],
388 "rc conditions: reviewStatus=unpatrolled;auto",
389 $user
390 );
391 }
392
393 public function testRcHideminorFilter() {
394 $this->assertConditions(
395 [ # expected
396 "rc_minor = 0",
397 ],
398 [
399 'hideminor' => 1,
400 ],
401 "rc conditions: hideminor=1"
402 );
403 }
404
405 public function testRcHidemajorFilter() {
406 $this->assertConditions(
407 [ # expected
408 "rc_minor = 1",
409 ],
410 [
411 'hidemajor' => 1,
412 ],
413 "rc conditions: hidemajor=1"
414 );
415 }
416
417 public function testHideCategorization() {
418 $this->assertConditions(
419 [
420 # expected
421 "rc_type != '6'"
422 ],
423 [
424 'hidecategorization' => 1
425 ],
426 "rc conditions: hidecategorization=1"
427 );
428 }
429
430 public function testFilterUserExpLevelAll() {
431 $this->assertConditions(
432 [
433 # expected
434 ],
435 [
436 'userExpLevel' => 'registered;unregistered;newcomer;learner;experienced',
437 ],
438 "rc conditions: userExpLevel=registered;unregistered;newcomer;learner;experienced"
439 );
440 }
441
442 public function testFilterUserExpLevelRegisteredUnregistered() {
443 $this->assertConditions(
444 [
445 # expected
446 ],
447 [
448 'userExpLevel' => 'registered;unregistered',
449 ],
450 "rc conditions: userExpLevel=registered;unregistered"
451 );
452 }
453
454 public function testFilterUserExpLevelRegisteredUnregisteredLearner() {
455 $this->assertConditions(
456 [
457 # expected
458 ],
459 [
460 'userExpLevel' => 'registered;unregistered;learner',
461 ],
462 "rc conditions: userExpLevel=registered;unregistered;learner"
463 );
464 }
465
466 public function testFilterUserExpLevelAllExperienceLevels() {
467 $this->setMwGlobals(
468 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
469 );
470 $this->overrideMwServices();
471
472 $this->assertConditions(
473 [
474 # expected
475 'rc_user != 0',
476 ],
477 [
478 'userExpLevel' => 'newcomer;learner;experienced',
479 ],
480 "rc conditions: userExpLevel=newcomer;learner;experienced"
481 );
482 }
483
484 public function testFilterUserExpLevelRegistrered() {
485 $this->setMwGlobals(
486 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
487 );
488 $this->overrideMwServices();
489
490 $this->assertConditions(
491 [
492 # expected
493 'rc_user != 0',
494 ],
495 [
496 'userExpLevel' => 'registered',
497 ],
498 "rc conditions: userExpLevel=registered"
499 );
500 }
501
502 public function testFilterUserExpLevelUnregistrered() {
503 $this->setMwGlobals(
504 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
505 );
506 $this->overrideMwServices();
507
508 $this->assertConditions(
509 [
510 # expected
511 'rc_user = 0',
512 ],
513 [
514 'userExpLevel' => 'unregistered',
515 ],
516 "rc conditions: userExpLevel=unregistered"
517 );
518 }
519
520 public function testFilterUserExpLevelRegistreredOrLearner() {
521 $this->setMwGlobals(
522 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
523 );
524 $this->overrideMwServices();
525
526 $this->assertConditions(
527 [
528 # expected
529 'rc_user != 0',
530 ],
531 [
532 'userExpLevel' => 'registered;learner',
533 ],
534 "rc conditions: userExpLevel=registered;learner"
535 );
536 }
537
538 public function testFilterUserExpLevelUnregistreredOrExperienced() {
539 $this->setMwGlobals(
540 'wgActorTableSchemaMigrationStage', SCHEMA_COMPAT_WRITE_BOTH | SCHEMA_COMPAT_READ_OLD
541 );
542 $this->overrideMwServices();
543
544 $conds = $this->buildQuery( [ 'userExpLevel' => 'unregistered;experienced' ] );
545
546 $this->assertRegExp(
547 '/\(rc_user = 0\) OR '
548 . '\(\(user_editcount >= 500\) AND \(user_registration <= \'[^\']+\'\)\)/',
549 reset( $conds ),
550 "rc conditions: userExpLevel=unregistered;experienced"
551 );
552 }
553
554 public function testFilterUserExpLevel() {
555 $now = time();
556 $this->setMwGlobals( [
557 'wgLearnerEdits' => 10,
558 'wgLearnerMemberSince' => 4,
559 'wgExperiencedUserEdits' => 500,
560 'wgExperiencedUserMemberSince' => 30,
561 ] );
562
563 $this->createUsers( [
564 'Newcomer1' => [ 'edits' => 2, 'days' => 2 ],
565 'Newcomer2' => [ 'edits' => 12, 'days' => 3 ],
566 'Newcomer3' => [ 'edits' => 8, 'days' => 5 ],
567 'Learner1' => [ 'edits' => 15, 'days' => 10 ],
568 'Learner2' => [ 'edits' => 450, 'days' => 20 ],
569 'Learner3' => [ 'edits' => 460, 'days' => 33 ],
570 'Learner4' => [ 'edits' => 525, 'days' => 28 ],
571 'Experienced1' => [ 'edits' => 538, 'days' => 33 ],
572 ], $now );
573
574 // newcomers only
575 $this->assertArrayEquals(
576 [ 'Newcomer1', 'Newcomer2', 'Newcomer3' ],
577 $this->fetchUsers( [ 'newcomer' ], $now )
578 );
579
580 // newcomers and learner
581 $this->assertArrayEquals(
582 [
583 'Newcomer1', 'Newcomer2', 'Newcomer3',
584 'Learner1', 'Learner2', 'Learner3', 'Learner4',
585 ],
586 $this->fetchUsers( [ 'newcomer', 'learner' ], $now )
587 );
588
589 // newcomers and more learner
590 $this->assertArrayEquals(
591 [
592 'Newcomer1', 'Newcomer2', 'Newcomer3',
593 'Experienced1',
594 ],
595 $this->fetchUsers( [ 'newcomer', 'experienced' ], $now )
596 );
597
598 // learner only
599 $this->assertArrayEquals(
600 [ 'Learner1', 'Learner2', 'Learner3', 'Learner4' ],
601 $this->fetchUsers( [ 'learner' ], $now )
602 );
603
604 // more experienced only
605 $this->assertArrayEquals(
606 [ 'Experienced1' ],
607 $this->fetchUsers( [ 'experienced' ], $now )
608 );
609
610 // learner and more experienced
611 $this->assertArrayEquals(
612 [
613 'Learner1', 'Learner2', 'Learner3', 'Learner4',
614 'Experienced1',
615 ],
616 $this->fetchUsers( [ 'learner', 'experienced' ], $now ),
617 'Learner and more experienced'
618 );
619 }
620
621 private function createUsers( $specs, $now ) {
622 $dbw = wfGetDB( DB_MASTER );
623 foreach ( $specs as $name => $spec ) {
624 User::createNew(
625 $name,
626 [
627 'editcount' => $spec['edits'],
628 'registration' => $dbw->timestamp( $this->daysAgo( $spec['days'], $now ) ),
629 'email' => 'ut',
630 ]
631 );
632 }
633 }
634
635 private function fetchUsers( $filters, $now ) {
636 $tables = [];
637 $conds = [];
638 $fields = [];
639 $query_options = [];
640 $join_conds = [];
641
642 sort( $filters );
643
644 call_user_func_array(
645 [ $this->changesListSpecialPage, 'filterOnUserExperienceLevel' ],
646 [
647 get_class( $this->changesListSpecialPage ),
648 $this->changesListSpecialPage->getContext(),
649 $this->changesListSpecialPage->getDB(),
650 &$tables,
651 &$fields,
652 &$conds,
653 &$query_options,
654 &$join_conds,
655 $filters,
656 $now
657 ]
658 );
659
660 // @todo: This is not at all safe or sane. It just blindly assumes
661 // nothing in $conds depends on any other tables.
662 $result = wfGetDB( DB_MASTER )->select(
663 'user',
664 'user_name',
665 array_filter( $conds ) + [ 'user_email' => 'ut' ]
666 );
667
668 $usernames = [];
669 foreach ( $result as $row ) {
670 $usernames[] = $row->user_name;
671 }
672
673 return $usernames;
674 }
675
676 private function daysAgo( $days, $now ) {
677 $secondsPerDay = 86400;
678 return $now - $days * $secondsPerDay;
679 }
680
681 public function testGetStructuredFilterJsData() {
682 $this->changesListSpecialPage->filterGroups = [];
683
684 $definition = [
685 [
686 'name' => 'gub-group',
687 'title' => 'gub-group-title',
688 'class' => ChangesListBooleanFilterGroup::class,
689 'filters' => [
690 [
691 'name' => 'hidefoo',
692 'label' => 'foo-label',
693 'description' => 'foo-description',
694 'default' => true,
695 'showHide' => 'showhidefoo',
696 'priority' => 2,
697 ],
698 [
699 'name' => 'hidebar',
700 'label' => 'bar-label',
701 'description' => 'bar-description',
702 'default' => false,
703 'priority' => 4,
704 ]
705 ],
706 ],
707
708 [
709 'name' => 'des-group',
710 'title' => 'des-group-title',
711 'class' => ChangesListStringOptionsFilterGroup::class,
712 'isFullCoverage' => true,
713 'filters' => [
714 [
715 'name' => 'grault',
716 'label' => 'grault-label',
717 'description' => 'grault-description',
718 ],
719 [
720 'name' => 'garply',
721 'label' => 'garply-label',
722 'description' => 'garply-description',
723 ],
724 ],
725 'queryCallable' => function () {
726 },
727 'default' => ChangesListStringOptionsFilterGroup::NONE,
728 ],
729
730 [
731 'name' => 'unstructured',
732 'class' => ChangesListBooleanFilterGroup::class,
733 'filters' => [
734 [
735 'name' => 'hidethud',
736 'showHide' => 'showhidethud',
737 'default' => true,
738 ],
739
740 [
741 'name' => 'hidemos',
742 'showHide' => 'showhidemos',
743 'default' => false,
744 ],
745 ],
746 ],
747
748 ];
749
750 $this->changesListSpecialPage->registerFiltersFromDefinitions( $definition );
751
752 $this->assertArrayEquals(
753 [
754 // Filters that only display in the unstructured UI are
755 // are not included, and neither are groups that would
756 // be empty due to the above.
757 'groups' => [
758 [
759 'name' => 'gub-group',
760 'title' => 'gub-group-title',
761 'type' => ChangesListBooleanFilterGroup::TYPE,
762 'priority' => -1,
763 'filters' => [
764 [
765 'name' => 'hidebar',
766 'label' => 'bar-label',
767 'description' => 'bar-description',
768 'default' => false,
769 'priority' => 4,
770 'cssClass' => null,
771 'conflicts' => [],
772 'subset' => [],
773 'defaultHighlightColor' => null
774 ],
775 [
776 'name' => 'hidefoo',
777 'label' => 'foo-label',
778 'description' => 'foo-description',
779 'default' => true,
780 'priority' => 2,
781 'cssClass' => null,
782 'conflicts' => [],
783 'subset' => [],
784 'defaultHighlightColor' => null
785 ],
786 ],
787 'fullCoverage' => true,
788 'conflicts' => [],
789 ],
790
791 [
792 'name' => 'des-group',
793 'title' => 'des-group-title',
794 'type' => ChangesListStringOptionsFilterGroup::TYPE,
795 'priority' => -2,
796 'fullCoverage' => true,
797 'filters' => [
798 [
799 'name' => 'grault',
800 'label' => 'grault-label',
801 'description' => 'grault-description',
802 'cssClass' => null,
803 'priority' => -2,
804 'conflicts' => [],
805 'subset' => [],
806 'defaultHighlightColor' => null
807 ],
808 [
809 'name' => 'garply',
810 'label' => 'garply-label',
811 'description' => 'garply-description',
812 'cssClass' => null,
813 'priority' => -3,
814 'conflicts' => [],
815 'subset' => [],
816 'defaultHighlightColor' => null
817 ],
818 ],
819 'conflicts' => [],
820 'separator' => ';',
821 'default' => ChangesListStringOptionsFilterGroup::NONE,
822 ],
823 ],
824 'messageKeys' => [
825 'gub-group-title',
826 'bar-label',
827 'bar-description',
828 'foo-label',
829 'foo-description',
830 'des-group-title',
831 'grault-label',
832 'grault-description',
833 'garply-label',
834 'garply-description',
835 ],
836 ],
837 $this->changesListSpecialPage->getStructuredFilterJsData(),
838 /** ordered= */ false,
839 /** named= */ true
840 );
841 }
842
843 public function provideParseParameters() {
844 return [
845 [ 'hidebots', [ 'hidebots' => true ] ],
846
847 [ 'bots', [ 'hidebots' => false ] ],
848
849 [ 'hideminor', [ 'hideminor' => true ] ],
850
851 [ 'minor', [ 'hideminor' => false ] ],
852
853 [ 'hidemajor', [ 'hidemajor' => true ] ],
854
855 [ 'hideliu', [ 'hideliu' => true ] ],
856
857 [ 'hidepatrolled', [ 'hidepatrolled' => true ] ],
858
859 [ 'hideunpatrolled', [ 'hideunpatrolled' => true ] ],
860
861 [ 'hideanons', [ 'hideanons' => true ] ],
862
863 [ 'hidemyself', [ 'hidemyself' => true ] ],
864
865 [ 'hidebyothers', [ 'hidebyothers' => true ] ],
866
867 [ 'hidehumans', [ 'hidehumans' => true ] ],
868
869 [ 'hidepageedits', [ 'hidepageedits' => true ] ],
870
871 [ 'pagedits', [ 'hidepageedits' => false ] ],
872
873 [ 'hidenewpages', [ 'hidenewpages' => true ] ],
874
875 [ 'hidecategorization', [ 'hidecategorization' => true ] ],
876
877 [ 'hidelog', [ 'hidelog' => true ] ],
878
879 [
880 'userExpLevel=learner;experienced',
881 [
882 'userExpLevel' => 'learner;experienced'
883 ],
884 ],
885
886 // A few random combos
887 [
888 'bots,hideliu,hidemyself',
889 [
890 'hidebots' => false,
891 'hideliu' => true,
892 'hidemyself' => true,
893 ],
894 ],
895
896 [
897 'minor,hideanons,categorization',
898 [
899 'hideminor' => false,
900 'hideanons' => true,
901 'hidecategorization' => false,
902 ]
903 ],
904
905 [
906 'hidehumans,bots,hidecategorization',
907 [
908 'hidehumans' => true,
909 'hidebots' => false,
910 'hidecategorization' => true,
911 ],
912 ],
913
914 [
915 'hidemyself,userExpLevel=newcomer;learner,hideminor',
916 [
917 'hidemyself' => true,
918 'hideminor' => true,
919 'userExpLevel' => 'newcomer;learner',
920 ],
921 ],
922 ];
923 }
924
925 public function provideGetFilterConflicts() {
926 return [
927 [
928 "parameters" => [],
929 "expectedConflicts" => false,
930 ],
931 [
932 "parameters" => [
933 "hideliu" => true,
934 "userExpLevel" => "newcomer",
935 ],
936 "expectedConflicts" => false,
937 ],
938 [
939 "parameters" => [
940 "hideanons" => true,
941 "userExpLevel" => "learner",
942 ],
943 "expectedConflicts" => false,
944 ],
945 [
946 "parameters" => [
947 "hidemajor" => true,
948 "hidenewpages" => true,
949 "hidepageedits" => true,
950 "hidecategorization" => false,
951 "hidelog" => true,
952 "hideWikidata" => true,
953 ],
954 "expectedConflicts" => true,
955 ],
956 [
957 "parameters" => [
958 "hidemajor" => true,
959 "hidenewpages" => false,
960 "hidepageedits" => true,
961 "hidecategorization" => false,
962 "hidelog" => false,
963 "hideWikidata" => true,
964 ],
965 "expectedConflicts" => true,
966 ],
967 [
968 "parameters" => [
969 "hidemajor" => true,
970 "hidenewpages" => false,
971 "hidepageedits" => false,
972 "hidecategorization" => true,
973 "hidelog" => true,
974 "hideWikidata" => true,
975 ],
976 "expectedConflicts" => false,
977 ],
978 [
979 "parameters" => [
980 "hideminor" => true,
981 "hidenewpages" => true,
982 "hidepageedits" => true,
983 "hidecategorization" => false,
984 "hidelog" => true,
985 "hideWikidata" => true,
986 ],
987 "expectedConflicts" => false,
988 ],
989 ];
990 }
991
992 /**
993 * @dataProvider provideGetFilterConflicts
994 */
995 public function testGetFilterConflicts( $parameters, $expectedConflicts ) {
996 $context = new RequestContext;
997 $context->setRequest( new FauxRequest( $parameters ) );
998 $this->changesListSpecialPage->setContext( $context );
999
1000 $this->assertEquals(
1001 $expectedConflicts,
1002 $this->changesListSpecialPage->areFiltersInConflict()
1003 );
1004 }
1005
1006 public function validateOptionsProvider() {
1007 return [
1008 [
1009 [ 'hideanons' => 1, 'hideliu' => 1, 'hidebots' => 1 ],
1010 true,
1011 [ 'userExpLevel' => 'unregistered', 'hidebots' => 1, ],
1012 true,
1013 ],
1014 [
1015 [ 'hideanons' => 1, 'hideliu' => 1, 'hidebots' => 0 ],
1016 true,
1017 [ 'hidebots' => 0, 'hidehumans' => 1 ],
1018 true,
1019 ],
1020 [
1021 [ 'hideanons' => 1 ],
1022 true,
1023 [ 'userExpLevel' => 'registered' ],
1024 true,
1025 ],
1026 [
1027 [ 'hideliu' => 1 ],
1028 true,
1029 [ 'userExpLevel' => 'unregistered' ],
1030 true,
1031 ],
1032 [
1033 [ 'hideanons' => 1, 'hidebots' => 1 ],
1034 true,
1035 [ 'userExpLevel' => 'registered', 'hidebots' => 1 ],
1036 true,
1037 ],
1038 [
1039 [ 'hideliu' => 1, 'hidebots' => 0 ],
1040 true,
1041 [ 'userExpLevel' => 'unregistered', 'hidebots' => 0 ],
1042 true,
1043 ],
1044 [
1045 [ 'hidemyself' => 1, 'hidebyothers' => 1 ],
1046 true,
1047 [],
1048 true,
1049 ],
1050 [
1051 [ 'hidebots' => 1, 'hidehumans' => 1 ],
1052 true,
1053 [],
1054 true,
1055 ],
1056 [
1057 [ 'hidepatrolled' => 1, 'hideunpatrolled' => 1 ],
1058 true,
1059 [],
1060 true,
1061 ],
1062 [
1063 [ 'hideminor' => 1, 'hidemajor' => 1 ],
1064 true,
1065 [],
1066 true,
1067 ],
1068 [
1069 // changeType
1070 [ 'hidepageedits' => 1, 'hidenewpages' => 1, 'hidecategorization' => 1, 'hidelog' => 1, ],
1071 true,
1072 [],
1073 true,
1074 ],
1075 ];
1076 }
1077 }