3use Wikimedia\TestingAccessWrapper;
19 $mock = $this->getMockBuilder( ChangesListSpecialPage::class )
22 'ChangesListSpecialPage',
26 ->setMethods( [
'getPageTitle' ] )
27 ->getMockForAbstractClass();
29 $mock->method(
'getPageTitle' )->willReturn(
30 Title::makeTitle(
NS_SPECIAL,
'ChangesListSpecialPage' )
33 $mock = TestingAccessWrapper::newFromObject(
41 $requestOptions =
null,
50 $this->changesListSpecialPage->setContext(
$context );
51 $this->changesListSpecialPage->filterGroups = [];
52 $formOptions = $this->changesListSpecialPage->setup(
null );
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
60 $queryConditions = [];
65 [ $this->changesListSpecialPage,
'buildQuery' ],
76 $queryConditions = array_filter(
78 'ChangesListSpecialPageTest::filterOutRcTimestampCondition'
81 return $queryConditions;
87 $requestOptions =
null,
91 $queryConditions = $this->
buildQuery( $requestOptions, $user );
94 self::normalizeCondition( $expected ),
95 self::normalizeCondition( $queryConditions ),
101 $normalized = array_map(
102 function ( $k, $v ) {
103 return is_numeric( $k ) ? $v :
"$k = $v";
105 array_keys( $conds ),
114 return (
false === strpos( $var,
'rc_timestamp ' ) );
120 "rc_namespace = '0'",
125 "rc conditions with one namespace"
132 "rc_namespace != '0'",
138 "rc conditions with namespace inverted"
145 "rc_namespace IN ('1','2','3')",
148 'namespace' =>
'1;2;3',
150 "rc conditions with multiple namespaces"
157 "rc_namespace IN ('0','1','4','5','6','7')",
160 'namespace' =>
'1;4;7',
163 "rc conditions with multiple namespaces and associated"
170 "rc_namespace NOT IN ('2','3','8','9')",
173 'namespace' =>
'2;3;9',
177 "rc conditions with multiple namespaces, associated and inverted"
184 "rc_namespace NOT IN ('1','2','3')",
187 'namespace' =>
'1;2;3',
190 "rc conditions with multiple namespaces inverted"
198 "rc_user_text != '{$user->getName()}'",
203 "rc conditions: hidemyself=1 (logged in)",
207 $user = User::newFromName(
'10.11.12.13',
false );
210 "rc_user_text != '10.11.12.13'",
215 "rc conditions: hidemyself=1 (anon)",
224 "rc_user_text = '{$user->getName()}'",
229 "rc conditions: hidebyothers=1 (logged in)",
233 $user = User::newFromName(
'10.11.12.13',
false );
236 "rc_user_text = '10.11.12.13'",
241 "rc conditions: hidebyothers=1 (anon)",
252 'hidepageedits' => 1,
254 "rc conditions: hidepageedits=1"
266 "rc conditions: hidenewpages=1"
278 "rc conditions: hidelog=1"
291 "rc conditions: hidebots=0 hidehumans=1"
301 'hidepatrolled' => 1,
303 "rc conditions: hidepatrolled=1 (user not allowed)",
314 'hideunpatrolled' => 1,
316 "rc conditions: hideunpatrolled=1 (user not allowed)",
327 'hidepatrolled' => 1,
329 "rc conditions: hidepatrolled=1",
341 'hideunpatrolled' => 1,
343 "rc conditions: hideunpatrolled=1",
356 "rc conditions: hideminor=1"
368 "rc conditions: hidemajor=1"
379 'hidecategorization' => 1
381 "rc conditions: hidecategorization=1"
391 'userExpLevel' =>
'registered;unregistered;newcomer;learner;experienced',
393 "rc conditions: userExpLevel=registered;unregistered;newcomer;learner;experienced"
403 'userExpLevel' =>
'registered;unregistered',
405 "rc conditions: userExpLevel=registered;unregistered"
415 'userExpLevel' =>
'registered;unregistered;learner',
417 "rc conditions: userExpLevel=registered;unregistered;learner"
428 'userExpLevel' =>
'newcomer;learner;experienced',
430 "rc conditions: userExpLevel=newcomer;learner;experienced"
441 'userExpLevel' =>
'registered',
443 "rc conditions: userExpLevel=registered"
454 'userExpLevel' =>
'unregistered',
456 "rc conditions: userExpLevel=unregistered"
467 'userExpLevel' =>
'registered;learner',
469 "rc conditions: userExpLevel=registered;learner"
474 $conds = $this->
buildQuery( [
'userExpLevel' =>
'unregistered;experienced' ] );
477 '/\(rc_user = 0\) OR \(\(user_editcount >= 500\) AND \(user_registration <= \'[^\']+\'\)\)/',
479 "rc conditions: userExpLevel=unregistered;experienced"
486 'wgLearnerEdits' => 10,
487 'wgLearnerMemberSince' => 4,
488 'wgExperiencedUserEdits' => 500,
489 'wgExperiencedUserMemberSince' => 30,
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 ],
505 [
'Newcomer1',
'Newcomer2',
'Newcomer3' ],
512 'Newcomer1',
'Newcomer2',
'Newcomer3',
513 'Learner1',
'Learner2',
'Learner3',
'Learner4',
515 $this->
fetchUsers( [
'newcomer',
'learner' ], $now )
521 'Newcomer1',
'Newcomer2',
'Newcomer3',
524 $this->
fetchUsers( [
'newcomer',
'experienced' ], $now )
529 [
'Learner1',
'Learner2',
'Learner3',
'Learner4' ],
542 'Learner1',
'Learner2',
'Learner3',
'Learner4',
545 $this->
fetchUsers( [
'learner',
'experienced' ], $now ),
546 'Learner and more experienced'
552 foreach ( $specs as $name => $spec ) {
556 'editcount' => $spec[
'edits'],
557 'registration' => $dbw->timestamp( $this->daysAgo( $spec[
'days'], $now ) ),
573 call_user_func_array(
574 [ $this->changesListSpecialPage,
'filterOnUserExperienceLevel' ],
576 get_class( $this->changesListSpecialPage ),
577 $this->changesListSpecialPage->getContext(),
578 $this->changesListSpecialPage->getDB(),
592 array_filter( $conds ) + [
'user_email' =>
'ut' ]
596 foreach ( $result as $row ) {
597 $usernames[] = $row->user_name;
604 $secondsPerDay = 86400;
605 return $now - $days * $secondsPerDay;
611 'msg' =>
'showhidefoo',
616 'msg' =>
'showhidebar',
623 'name' =>
'unstructured',
624 'class' => ChangesListBooleanFilterGroup::class,
629 'showHide' =>
'showhidefoo',
634 'showHide' =>
'showhidebar',
639 $this->changesListSpecialPage->getFilterGroupDefinitionFromLegacyCustomFilters(
646 $this->changesListSpecialPage->filterGroups = [];
650 'name' =>
'gub-group',
651 'title' =>
'gub-group-title',
652 'class' => ChangesListBooleanFilterGroup::class,
656 'label' =>
'foo-label',
657 'description' =>
'foo-description',
659 'showHide' =>
'showhidefoo',
664 'label' =>
'bar-label',
665 'description' =>
'bar-description',
673 'name' =>
'des-group',
674 'title' =>
'des-group-title',
675 'class' => ChangesListStringOptionsFilterGroup::class,
676 'isFullCoverage' =>
true,
680 'label' =>
'grault-label',
681 'description' =>
'grault-description',
685 'label' =>
'garply-label',
686 'description' =>
'garply-description',
689 'queryCallable' =>
function () {
695 'name' =>
'unstructured',
696 'class' => ChangesListBooleanFilterGroup::class,
699 'name' =>
'hidethud',
700 'showHide' =>
'showhidethud',
706 'showHide' =>
'showhidemos',
714 $this->changesListSpecialPage->registerFiltersFromDefinitions( $definition );
723 'name' =>
'gub-group',
724 'title' =>
'gub-group-title',
730 'label' =>
'bar-label',
731 'description' =>
'bar-description',
740 'label' =>
'foo-label',
741 'description' =>
'foo-description',
749 'fullCoverage' =>
true,
754 'name' =>
'des-group',
755 'title' =>
'des-group-title',
758 'fullCoverage' =>
true,
762 'label' =>
'grault-label',
763 'description' =>
'grault-description',
771 'label' =>
'garply-label',
772 'description' =>
'garply-description',
792 'grault-description',
794 'garply-description',
797 $this->changesListSpecialPage->getStructuredFilterJsData(),
805 [
'hidebots', [
'hidebots' =>
true ] ],
807 [
'bots', [
'hidebots' =>
false ] ],
809 [
'hideminor', [
'hideminor' =>
true ] ],
811 [
'minor', [
'hideminor' =>
false ] ],
813 [
'hidemajor', [
'hidemajor' =>
true ] ],
815 [
'hideliu', [
'hideliu' =>
true ] ],
817 [
'hidepatrolled', [
'hidepatrolled' =>
true ] ],
819 [
'hideunpatrolled', [
'hideunpatrolled' =>
true ] ],
821 [
'hideanons', [
'hideanons' =>
true ] ],
823 [
'hidemyself', [
'hidemyself' =>
true ] ],
825 [
'hidebyothers', [
'hidebyothers' =>
true ] ],
827 [
'hidehumans', [
'hidehumans' =>
true ] ],
829 [
'hidepageedits', [
'hidepageedits' =>
true ] ],
831 [
'pagedits', [
'hidepageedits' =>
false ] ],
833 [
'hidenewpages', [
'hidenewpages' =>
true ] ],
835 [
'hidecategorization', [
'hidecategorization' =>
true ] ],
837 [
'hidelog', [
'hidelog' =>
true ] ],
840 'userExpLevel=learner;experienced',
842 'userExpLevel' =>
'learner;experienced'
848 'bots,hideliu,hidemyself',
852 'hidemyself' =>
true,
857 'minor,hideanons,categorization',
859 'hideminor' =>
false,
861 'hidecategorization' =>
false,
866 'hidehumans,bots,hidecategorization',
868 'hidehumans' =>
true,
870 'hidecategorization' =>
true,
875 'hidemyself,userExpLevel=newcomer;learner,hideminor',
877 'hidemyself' =>
true,
879 'userExpLevel' =>
'newcomer;learner',
889 "expectedConflicts" =>
false,
894 "userExpLevel" =>
"newcomer",
896 "expectedConflicts" =>
false,
901 "userExpLevel" =>
"learner",
903 "expectedConflicts" =>
false,
908 "hidenewpages" =>
true,
909 "hidepageedits" =>
true,
910 "hidecategorization" =>
false,
912 "hideWikidata" =>
true,
914 "expectedConflicts" =>
true,
919 "hidenewpages" =>
false,
920 "hidepageedits" =>
true,
921 "hidecategorization" =>
false,
923 "hideWikidata" =>
true,
925 "expectedConflicts" =>
true,
930 "hidenewpages" =>
false,
931 "hidepageedits" =>
false,
932 "hidecategorization" =>
true,
934 "hideWikidata" =>
true,
936 "expectedConflicts" =>
false,
941 "hidenewpages" =>
true,
942 "hidepageedits" =>
true,
943 "hidecategorization" =>
false,
945 "hideWikidata" =>
true,
947 "expectedConflicts" =>
false,
958 $this->changesListSpecialPage->setContext(
$context );
962 $this->changesListSpecialPage->areFiltersInConflict()
969 [
'hideanons' => 1,
'hideliu' => 1,
'hidebots' => 1 ],
971 [
'hideliu' => 1,
'hidebots' => 1, ],
975 [
'hideanons' => 1,
'hideliu' => 1,
'hidebots' => 0 ],
977 [
'hidebots' => 0,
'hidehumans' => 1 ],
981 [
'hidemyself' => 1,
'hidebyothers' => 1 ],
986 [
'hidebots' => 1,
'hidehumans' => 1 ],
991 [
'hidepatrolled' => 1,
'hideunpatrolled' => 1 ],
996 [
'hideminor' => 1,
'hidemajor' => 1 ],
1002 [
'hidepageedits' => 1,
'hidenewpages' => 1,
'hidecategorization' => 1,
'hidelog' => 1, ],
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Abstract base class for shared logic when testing ChangesListSpecialPage and subclasses.
const TYPE
Type marker, used by JavaScript.
Test class for ChangesListSpecialPage class.
testRcHidepatrolledDisabledFilter()
testRcHidepatrolledFilter()
testFilterUserExpLevelRegisteredUnregistered()
testFilterUserExpLevelUnregistrered()
testFilterUserExpLevelAll()
validateOptionsProvider()
testRcHideunpatrolledDisabledFilter()
testRcHidebyothersFilter()
createUsers( $specs, $now)
testGetStructuredFilterJsData()
testFilterUserExpLevelAllExperienceLevels()
testRcNsFilterMultipleAssociated()
fetchUsers( $filters, $now)
testRcNsFilterMultipleInvert()
testRcHideunpatrolledFilter()
static normalizeCondition( $conds)
provideGetFilterConflicts()
testGetFilterConflicts( $parameters, $expectedConflicts)
provideGetFilterConflicts
static filterOutRcTimestampCondition( $var)
return false if condition begin with 'rc_timestamp '
testFilterUserExpLevelRegistrered()
buildQuery( $requestOptions=null, $user=null)
testGetFilterGroupDefinitionFromLegacyCustomFilters()
testFilterUserExpLevelRegistreredOrLearner()
testRcNsFilterInversion()
testFilterUserExpLevelRegisteredUnregisteredLearner()
testRcNsFilterMultipleAssociatedInvert()
testFilterUserExpLevelUnregistreredOrExperienced()
assertConditions( $expected, $requestOptions=null, $message='', $user=null)
helper to test SpecialRecentchanges::buildQuery()
const TYPE
Type marker, used by JavaScript.
const NONE
Signifies that no options in the group are selected, meaning the group has no effect.
WebRequest clone which takes values from a provided array.
Group all the pieces relevant to the context of a request into one instance.
this hook is for auditing only RecentChangesLinked and Watchlist RecentChangesLinked and Watchlist Do not use this to implement individual filters if they are compatible with the ChangesListFilter and ChangesListFilterGroup structure use sub classes of those in conjunction with the ChangesListSpecialPageStructuredFilters hook This hook can be used to implement filters that do not implement that or custom behavior that is not an individual filter e g Watchlist & $tables
do that in ParserLimitReportFormat instead use this to modify the parameters of the image all existing parser cache entries will be invalid To avoid you ll need to handle that somehow(e.g. with the RejectParserCacheValue hook) because MediaWiki won 't do it for you. & $defaults also a ContextSource after deleting those rows but within the same transaction you ll probably need to make sure the header is varied on and they can depend only on the ResourceLoaderContext $context
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses just before the function returns a value If you return true
processing should stop and the error should be shown to the user * false