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