Added release notes for 'ContentHandler::runLegacyHooks' removal
[mediawiki.git] / tests / phpunit / includes / specials / SpecialRecentchangesTest.php
blobab92aeeb3f45a5c7edf453e4e67ccc41726a2dfa
1 <?php
2 /**
3 * Test class for SpecialRecentchanges class
5 * Copyright © 2011, Antoine Musso
7 * @author Antoine Musso
8 * @group Database
10 * @covers SpecialRecentChanges
12 class SpecialRecentchangesTest extends MediaWikiTestCase {
14 protected function setUp() {
15 parent::setUp();
16 $this->setMwGlobals( 'wgRCWatchCategoryMembership', true );
19 /**
20 * @var SpecialRecentChanges
22 protected $rc;
24 /** helper to test SpecialRecentchanges::buildMainQueryConds() */
25 private function assertConditions(
26 $expected,
27 $requestOptions = null,
28 $message = '',
29 $user = null
30 ) {
31 $context = new RequestContext;
32 $context->setRequest( new FauxRequest( $requestOptions ) );
33 if ( $user ) {
34 $context->setUser( $user );
37 # setup the rc object
38 $this->rc = new SpecialRecentChanges();
39 $this->rc->setContext( $context );
40 $formOptions = $this->rc->setup( null );
42 #  Filter out rc_timestamp conditions which depends on the test runtime
43 # This condition is not needed as of march 2, 2011 -- hashar
44 # @todo FIXME: Find a way to generate the correct rc_timestamp
45 $queryConditions = array_filter(
46 $this->rc->buildMainQueryConds( $formOptions ),
47 'SpecialRecentchangesTest::filterOutRcTimestampCondition'
50 $this->assertEquals(
51 self::normalizeCondition( $expected ),
52 self::normalizeCondition( $queryConditions ),
53 $message
57 private static function normalizeCondition( $conds ) {
58 $normalized = array_map(
59 function ( $k, $v ) {
60 return is_numeric( $k ) ? $v : "$k = $v";
62 array_keys( $conds ),
63 $conds
65 sort( $normalized );
66 return $normalized;
69 /** return false if condition begin with 'rc_timestamp ' */
70 private static function filterOutRcTimestampCondition( $var ) {
71 return ( false === strpos( $var, 'rc_timestamp ' ) );
74 public function testRcNsFilter() {
75 $this->assertConditions(
76 [ # expected
77 'rc_bot' => 0,
78 "rc_type != '6'",
79 "rc_namespace = '0'",
82 'namespace' => NS_MAIN,
84 "rc conditions with no options (aka default setting)"
88 public function testRcNsFilterInversion() {
89 $this->assertConditions(
90 [ # expected
91 'rc_bot' => 0,
92 "rc_type != '6'",
93 "rc_namespace != '0'",
96 'namespace' => NS_MAIN,
97 'invert' => 1,
99 "rc conditions with namespace inverted"
104 * @bug 2429
105 * @dataProvider provideNamespacesAssociations
107 public function testRcNsFilterAssociation( $ns1, $ns2 ) {
108 $this->assertConditions(
109 [ # expected
110 'rc_bot' => 0,
111 "rc_type != '6'",
112 "(rc_namespace = '$ns1' OR rc_namespace = '$ns2')",
115 'namespace' => $ns1,
116 'associated' => 1,
118 "rc conditions with namespace inverted"
123 * @bug 2429
124 * @dataProvider provideNamespacesAssociations
126 public function testRcNsFilterAssociationWithInversion( $ns1, $ns2 ) {
127 $this->assertConditions(
128 [ # expected
129 'rc_bot' => 0,
130 "rc_type != '6'",
131 "(rc_namespace != '$ns1' AND rc_namespace != '$ns2')",
134 'namespace' => $ns1,
135 'associated' => 1,
136 'invert' => 1,
138 "rc conditions with namespace inverted"
143 * Provides associated namespaces to test recent changes
144 * namespaces association filtering.
146 public static function provideNamespacesAssociations() {
147 return [ # (NS => Associated_NS)
148 [ NS_MAIN, NS_TALK ],
149 [ NS_TALK, NS_MAIN ],
153 public function testRcHidemyselfFilter() {
154 $user = $this->getTestUser()->getUser();
155 $this->assertConditions(
156 [ # expected
157 'rc_bot' => 0,
158 "rc_user != '{$user->getId()}'",
159 "rc_type != '6'",
162 'hidemyself' => 1,
164 "rc conditions: hidemyself=1 (logged in)",
165 $user
168 $user = User::newFromName( '10.11.12.13', false );
169 $this->assertConditions(
170 [ # expected
171 'rc_bot' => 0,
172 "rc_user_text != '10.11.12.13'",
173 "rc_type != '6'",
176 'hidemyself' => 1,
178 "rc conditions: hidemyself=1 (anon)",
179 $user
183 public function testRcHidebyothersFilter() {
184 $user = $this->getTestUser()->getUser();
185 $this->assertConditions(
186 [ # expected
187 'rc_bot' => 0,
188 "rc_user = '{$user->getId()}'",
189 "rc_type != '6'",
192 'hidebyothers' => 1,
194 "rc conditions: hidebyothers=1 (logged in)",
195 $user
198 $user = User::newFromName( '10.11.12.13', false );
199 $this->assertConditions(
200 [ # expected
201 'rc_bot' => 0,
202 "rc_user_text = '10.11.12.13'",
203 "rc_type != '6'",
206 'hidebyothers' => 1,
208 "rc conditions: hidebyothers=1 (anon)",
209 $user
213 public function testRcHidemyselfHidebyothersFilter() {
214 $user = $this->getTestUser()->getUser();
215 $this->assertConditions(
216 [ # expected
217 'rc_bot' => 0,
218 "rc_user != '{$user->getId()}'",
219 "rc_user = '{$user->getId()}'",
220 "rc_type != '6'",
223 'hidemyself' => 1,
224 'hidebyothers' => 1,
226 "rc conditions: hidemyself=1 hidebyothers=1 (logged in)",
227 $user
231 public function testRcHidepageedits() {
232 $this->assertConditions(
233 [ # expected
234 'rc_bot' => 0,
235 "rc_type != '6'",
236 "rc_type != '0'",
239 'hidepageedits' => 1,
241 "rc conditions: hidepageedits=1"
245 public function testRcHidenewpages() {
246 $this->assertConditions(
247 [ # expected
248 'rc_bot' => 0,
249 "rc_type != '6'",
250 "rc_type != '1'",
253 'hidenewpages' => 1,
255 "rc conditions: hidenewpages=1"
259 public function testRcHidelog() {
260 $this->assertConditions(
261 [ # expected
262 'rc_bot' => 0,
263 "rc_type != '6'",
264 "rc_type != '3'",
267 'hidelog' => 1,
269 "rc conditions: hidelog=1"
273 public function testRcHidehumans() {
274 $this->assertConditions(
275 [ # expected
276 'rc_bot' => 1,
277 "rc_type != '6'",
280 'hidebots' => 0,
281 'hidehumans' => 1,
283 "rc conditions: hidebots=0 hidehumans=1"
287 public function testRcHidepatrolledDisabledFilter() {
288 $user = $this->getTestUser()->getUser();
289 $this->assertConditions(
290 [ # expected
291 'rc_bot' => 0,
292 "rc_type != '6'",
295 'hidepatrolled' => 1,
297 "rc conditions: hidepatrolled=1 (user not allowed)",
298 $user
302 public function testRcHideunpatrolledDisabledFilter() {
303 $user = $this->getTestUser()->getUser();
304 $this->assertConditions(
305 [ # expected
306 'rc_bot' => 0,
307 "rc_type != '6'",
310 'hideunpatrolled' => 1,
312 "rc conditions: hideunpatrolled=1 (user not allowed)",
313 $user
316 public function testRcHidepatrolledFilter() {
317 $user = $this->getTestSysop()->getUser();
318 $this->assertConditions(
319 [ # expected
320 'rc_bot' => 0,
321 "rc_patrolled = 0",
322 "rc_type != '6'",
325 'hidepatrolled' => 1,
327 "rc conditions: hidepatrolled=1",
328 $user
332 public function testRcHideunpatrolledFilter() {
333 $user = $this->getTestSysop()->getUser();
334 $this->assertConditions(
335 [ # expected
336 'rc_bot' => 0,
337 "rc_patrolled = 1",
338 "rc_type != '6'",
341 'hideunpatrolled' => 1,
343 "rc conditions: hideunpatrolled=1",
344 $user
348 public function testRcHideminorFilter() {
349 $this->assertConditions(
350 [ # expected
351 'rc_bot' => 0,
352 "rc_minor = 0",
353 "rc_type != '6'",
356 'hideminor' => 1,
358 "rc conditions: hideminor=1"
362 public function testRcHidemajorFilter() {
363 $this->assertConditions(
364 [ # expected
365 'rc_bot' => 0,
366 "rc_minor = 1",
367 "rc_type != '6'",
370 'hidemajor' => 1,
372 "rc conditions: hidemajor=1"
376 // This is probably going to change when we do auto-fix of
377 // filters combinations that don't make sense but for now
378 // it's the behavior therefore it's the test.
379 public function testRcHidepatrolledHideunpatrolledFilter() {
380 $user = $this->getTestSysop()->getUser();
381 $this->assertConditions(
382 [ # expected
383 'rc_bot' => 0,
384 "rc_patrolled = 0",
385 "rc_patrolled = 1",
386 "rc_type != '6'",
389 'hidepatrolled' => 1,
390 'hideunpatrolled' => 1,
392 "rc conditions: hidepatrolled=1 hideunpatrolled=1",
393 $user
397 public function testFilterUserExpLevel() {
398 $this->setMwGlobals( [
399 'wgLearnerEdits' => 10,
400 'wgLearnerMemberSince' => 4,
401 'wgExperiencedUserEdits' => 500,
402 'wgExperiencedUserMemberSince' => 30,
403 ] );
405 $this->createUsers( [
406 'Newcomer1' => [ 'edits' => 2, 'days' => 2 ],
407 'Newcomer2' => [ 'edits' => 12, 'days' => 3 ],
408 'Newcomer3' => [ 'edits' => 8, 'days' => 5 ],
409 'Learner1' => [ 'edits' => 15, 'days' => 10 ],
410 'Learner2' => [ 'edits' => 450, 'days' => 20 ],
411 'Learner3' => [ 'edits' => 460, 'days' => 33 ],
412 'Learner4' => [ 'edits' => 525, 'days' => 28 ],
413 'Experienced1' => [ 'edits' => 538, 'days' => 33 ],
414 ] );
416 // newcomers only
417 $this->assertArrayEquals(
418 [ 'Newcomer1', 'Newcomer2', 'Newcomer3' ],
419 $this->fetchUsers( [ 'userExpLevel' => 'newcomer' ] )
422 // newcomers and learner
423 $this->assertArrayEquals(
425 'Newcomer1', 'Newcomer2', 'Newcomer3',
426 'Learner1', 'Learner2', 'Learner3', 'Learner4',
428 $this->fetchUsers( [ 'userExpLevel' => 'newcomer,learner' ] )
431 // newcomers and more learner
432 $this->assertArrayEquals(
434 'Newcomer1', 'Newcomer2', 'Newcomer3',
435 'Experienced1',
437 $this->fetchUsers( [ 'userExpLevel' => 'newcomer,experienced' ] )
440 // learner only
441 $this->assertArrayEquals(
442 [ 'Learner1', 'Learner2', 'Learner3', 'Learner4' ],
443 $this->fetchUsers( [ 'userExpLevel' => 'learner' ] )
446 // more experienced only
447 $this->assertArrayEquals(
448 [ 'Experienced1' ],
449 $this->fetchUsers( [ 'userExpLevel' => 'experienced' ] )
452 // learner and more experienced
453 $this->assertArrayEquals(
455 'Learner1', 'Learner2', 'Learner3', 'Learner4',
456 'Experienced1',
458 $this->fetchUsers( [ 'userExpLevel' => 'learner,experienced' ] )
461 // newcomers, learner, and more experienced
462 $this->assertArrayEquals(
464 'Newcomer1', 'Newcomer2', 'Newcomer3',
465 'Learner1', 'Learner2', 'Learner3', 'Learner4',
466 'Experienced1',
468 $this->fetchUsers( [ 'userExpLevel' => 'newcomer,learner,experienced' ] )
471 // 'all'
472 $this->assertArrayEquals(
474 'Newcomer1', 'Newcomer2', 'Newcomer3',
475 'Learner1', 'Learner2', 'Learner3', 'Learner4',
476 'Experienced1',
478 $this->fetchUsers( [ 'userExpLevel' => 'all' ] )
482 private function createUsers( $specs ) {
483 $dbw = wfGetDB( DB_MASTER );
484 foreach ( $specs as $name => $spec ) {
485 User::createNew(
486 $name,
488 'editcount' => $spec['edits'],
489 'registration' => $dbw->timestamp( $this->daysAgo( $spec['days'] ) ),
490 'email' => 'ut',
496 private function fetchUsers( $filters ) {
497 $specialRC = new SpecialRecentChanges();
499 $tables = [];
500 $conds = [];
501 $join_conds = [];
503 $specialRC->filterOnUserExperienceLevel(
504 $tables,
505 $conds,
506 $join_conds,
507 $filters
510 $result = wfGetDB( DB_MASTER )->select(
511 'user',
512 'user_name',
513 array_filter( $conds ) + [ 'user_email' => 'ut' ]
516 $usernames = [];
517 foreach ( $result as $row ) {
518 $usernames[] = $row->user_name;
521 return $usernames;
524 private function daysAgo( $days ) {
525 $secondsPerDay = 86400;
526 return time() - $days * $secondsPerDay;