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