Merge "Support custom offsets from SearchResultSet"
[lhc/web/wiklou.git] / tests / phpunit / includes / specialpage / ChangesListSpecialPageTest.php
index b536c22..4070bc0 100644 (file)
@@ -15,30 +15,30 @@ use Wikimedia\TestingAccessWrapper;
  * @covers ChangesListSpecialPage
  */
 class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase {
-       protected function setUp() {
-               parent::setUp();
-
-               # setup the rc object
-               $this->changesListSpecialPage = $this->getPage();
-       }
-
        protected function getPage() {
-               return TestingAccessWrapper::newFromObject(
-                       $this->getMockForAbstractClass(
-                               'ChangesListSpecialPage',
+               $mock = $this->getMockBuilder( ChangesListSpecialPage::class )
+                       ->setConstructorArgs(
                                [
                                        'ChangesListSpecialPage',
                                        ''
                                ]
                        )
+                       ->setMethods( [ 'getPageTitle' ] )
+                       ->getMockForAbstractClass();
+
+               $mock->method( 'getPageTitle' )->willReturn(
+                       Title::makeTitle( NS_SPECIAL, 'ChangesListSpecialPage' )
+               );
+
+               $mock = TestingAccessWrapper::newFromObject(
+                       $mock
                );
+
+               return $mock;
        }
 
-       /** helper to test SpecialRecentchanges::buildMainQueryConds() */
-       private function assertConditions(
-               $expected,
+       private function buildQuery(
                $requestOptions = null,
-               $message = '',
                $user = null
        ) {
                $context = new RequestContext;
@@ -48,6 +48,7 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                }
 
                $this->changesListSpecialPage->setContext( $context );
+               $this->changesListSpecialPage->filterGroups = [];
                $formOptions = $this->changesListSpecialPage->setup( null );
 
                #  Filter out rc_timestamp conditions which depends on the test runtime
@@ -77,6 +78,18 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                        'ChangesListSpecialPageTest::filterOutRcTimestampCondition'
                );
 
+               return $queryConditions;
+       }
+
+       /** helper to test SpecialRecentchanges::buildQuery() */
+       private function assertConditions(
+               $expected,
+               $requestOptions = null,
+               $message = '',
+               $user = null
+       ) {
+               $queryConditions = $this->buildQuery( $requestOptions, $user );
+
                $this->assertEquals(
                        self::normalizeCondition( $expected ),
                        self::normalizeCondition( $queryConditions ),
@@ -109,7 +122,7 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                        [
                                'namespace' => NS_MAIN,
                        ],
-                       "rc conditions with no options (aka default setting)"
+                       "rc conditions with one namespace"
                );
        }
 
@@ -126,50 +139,56 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                );
        }
 
-       /**
-        * T4429
-        * @dataProvider provideNamespacesAssociations
-        */
-       public function testRcNsFilterAssociation( $ns1, $ns2 ) {
+       public function testRcNsFilterMultiple() {
+               $this->assertConditions(
+                       [ # expected
+                               "rc_namespace IN ('1','2','3')",
+                       ],
+                       [
+                               'namespace' => '1;2;3',
+                       ],
+                       "rc conditions with multiple namespaces"
+               );
+       }
+
+       public function testRcNsFilterMultipleAssociated() {
                $this->assertConditions(
                        [ # expected
-                               "(rc_namespace = '$ns1' OR rc_namespace = '$ns2')",
+                               "rc_namespace IN ('0','1','4','5','6','7')",
                        ],
                        [
-                               'namespace' => $ns1,
+                               'namespace' => '1;4;7',
                                'associated' => 1,
                        ],
-                       "rc conditions with namespace inverted"
+                       "rc conditions with multiple namespaces and associated"
                );
        }
 
-       /**
-        * T4429
-        * @dataProvider provideNamespacesAssociations
-        */
-       public function testRcNsFilterAssociationWithInversion( $ns1, $ns2 ) {
+       public function testRcNsFilterMultipleAssociatedInvert() {
                $this->assertConditions(
                        [ # expected
-                               "(rc_namespace != '$ns1' AND rc_namespace != '$ns2')",
+                               "rc_namespace NOT IN ('2','3','8','9')",
                        ],
                        [
-                               'namespace' => $ns1,
+                               'namespace' => '2;3;9',
                                'associated' => 1,
-                               'invert' => 1,
+                               'invert' => 1
                        ],
-                       "rc conditions with namespace inverted"
+                       "rc conditions with multiple namespaces, associated and inverted"
                );
        }
 
-       /**
-        * Provides associated namespaces to test recent changes
-        * namespaces association filtering.
-        */
-       public static function provideNamespacesAssociations() {
-               return [ # (NS => Associated_NS)
-                       [ NS_MAIN, NS_TALK ],
-                       [ NS_TALK, NS_MAIN ],
-               ];
+       public function testRcNsFilterMultipleInvert() {
+               $this->assertConditions(
+                       [ # expected
+                               "rc_namespace NOT IN ('1','2','3')",
+                       ],
+                       [
+                               'namespace' => '1;2;3',
+                               'invert' => 1,
+                       ],
+                       "rc conditions with multiple namespaces inverted"
+               );
        }
 
        public function testRcHidemyselfFilter() {
@@ -224,22 +243,6 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                );
        }
 
-       public function testRcHidemyselfHidebyothersFilter() {
-               $user = $this->getTestUser()->getUser();
-               $this->assertConditions(
-                       [ # expected
-                               "rc_user_text != '{$user->getName()}'",
-                               "rc_user_text = '{$user->getName()}'",
-                       ],
-                       [
-                               'hidemyself' => 1,
-                               'hidebyothers' => 1,
-                       ],
-                       "rc conditions: hidemyself=1 hidebyothers=1 (logged in)",
-                       $user
-               );
-       }
-
        public function testRcHidepageedits() {
                $this->assertConditions(
                        [ # expected
@@ -366,36 +369,119 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                );
        }
 
-       public function testRcHidepatrolledHideunpatrolledFilter() {
-               $user = $this->getTestSysop()->getUser();
+       public function testHideCategorization() {
                $this->assertConditions(
-                       [ # expected
-                               "rc_patrolled = 0",
-                               "rc_patrolled = 1",
+                       [
+                               # expected
+                               "rc_type != '6'"
                        ],
                        [
-                               'hidepatrolled' => 1,
-                               'hideunpatrolled' => 1,
+                               'hidecategorization' => 1
                        ],
-                       "rc conditions: hidepatrolled=1 hideunpatrolled=1",
-                       $user
+                       "rc conditions: hidecategorization=1"
                );
        }
 
-       public function testHideCategorization() {
+       public function testFilterUserExpLevelAll() {
                $this->assertConditions(
                        [
                                # expected
-                               "rc_type != '6'"
                        ],
                        [
-                               'hidecategorization' => 1
+                               'userExpLevel' => 'registered;unregistered;newcomer;learner;experienced',
                        ],
-                       "rc conditions: hidecategorization=1"
+                       "rc conditions: userExpLevel=registered;unregistered;newcomer;learner;experienced"
+               );
+       }
+
+       public function testFilterUserExpLevelRegisteredUnregistered() {
+               $this->assertConditions(
+                       [
+                               # expected
+                       ],
+                       [
+                               'userExpLevel' => 'registered;unregistered',
+                       ],
+                       "rc conditions: userExpLevel=registered;unregistered"
+               );
+       }
+
+       public function testFilterUserExpLevelRegisteredUnregisteredLearner() {
+               $this->assertConditions(
+                       [
+                               # expected
+                       ],
+                       [
+                               'userExpLevel' => 'registered;unregistered;learner',
+                       ],
+                       "rc conditions: userExpLevel=registered;unregistered;learner"
+               );
+       }
+
+       public function testFilterUserExpLevelAllExperienceLevels() {
+               $this->assertConditions(
+                       [
+                               # expected
+                               'rc_user != 0',
+                       ],
+                       [
+                               'userExpLevel' => 'newcomer;learner;experienced',
+                       ],
+                       "rc conditions: userExpLevel=newcomer;learner;experienced"
+               );
+       }
+
+       public function testFilterUserExpLevelRegistrered() {
+               $this->assertConditions(
+                       [
+                               # expected
+                               'rc_user != 0',
+                       ],
+                       [
+                               'userExpLevel' => 'registered',
+                       ],
+                       "rc conditions: userExpLevel=registered"
+               );
+       }
+
+       public function testFilterUserExpLevelUnregistrered() {
+               $this->assertConditions(
+                       [
+                               # expected
+                               'rc_user' => 0,
+                       ],
+                       [
+                               'userExpLevel' => 'unregistered',
+                       ],
+                       "rc conditions: userExpLevel=unregistered"
+               );
+       }
+
+       public function testFilterUserExpLevelRegistreredOrLearner() {
+               $this->assertConditions(
+                       [
+                               # expected
+                               'rc_user != 0',
+                       ],
+                       [
+                               'userExpLevel' => 'registered;learner',
+                       ],
+                       "rc conditions: userExpLevel=registered;learner"
+               );
+       }
+
+       public function testFilterUserExpLevelUnregistreredOrExperienced() {
+               $conds = $this->buildQuery( [ 'userExpLevel' => 'unregistered;experienced' ] );
+
+               $this->assertRegExp(
+                       '/\(rc_user = 0\) OR \(\(user_editcount >= 500\) AND \(user_registration <= \'\d+\'\)\)/',
+                       reset( $conds ),
+                       "rc conditions: userExpLevel=unregistered;experienced"
                );
        }
 
        public function testFilterUserExpLevel() {
+               $now = time();
                $this->setMwGlobals( [
                        'wgLearnerEdits' => 10,
                        'wgLearnerMemberSince' => 4,
@@ -412,12 +498,12 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                        'Learner3' => [ 'edits' => 460, 'days' => 33 ],
                        'Learner4' => [ 'edits' => 525, 'days' => 28 ],
                        'Experienced1' => [ 'edits' => 538, 'days' => 33 ],
-               ] );
+               ], $now );
 
                // newcomers only
                $this->assertArrayEquals(
                        [ 'Newcomer1', 'Newcomer2', 'Newcomer3' ],
-                       $this->fetchUsers( [ 'newcomer' ] )
+                       $this->fetchUsers( [ 'newcomer' ], $now )
                );
 
                // newcomers and learner
@@ -426,7 +512,7 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                                'Newcomer1', 'Newcomer2', 'Newcomer3',
                                'Learner1', 'Learner2', 'Learner3', 'Learner4',
                        ],
-                       $this->fetchUsers( [ 'newcomer', 'learner' ] )
+                       $this->fetchUsers( [ 'newcomer', 'learner' ], $now )
                );
 
                // newcomers and more learner
@@ -435,19 +521,19 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                                'Newcomer1', 'Newcomer2', 'Newcomer3',
                                'Experienced1',
                        ],
-                       $this->fetchUsers( [ 'newcomer', 'experienced' ] )
+                       $this->fetchUsers( [ 'newcomer', 'experienced' ], $now )
                );
 
                // learner only
                $this->assertArrayEquals(
                        [ 'Learner1', 'Learner2', 'Learner3', 'Learner4' ],
-                       $this->fetchUsers( [ 'learner' ] )
+                       $this->fetchUsers( [ 'learner' ], $now )
                );
 
                // more experienced only
                $this->assertArrayEquals(
                        [ 'Experienced1' ],
-                       $this->fetchUsers( [ 'experienced' ] )
+                       $this->fetchUsers( [ 'experienced' ], $now )
                );
 
                // learner and more experienced
@@ -456,38 +542,26 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                                'Learner1', 'Learner2', 'Learner3', 'Learner4',
                                'Experienced1',
                        ],
-                       $this->fetchUsers( [ 'learner', 'experienced' ] ),
+                       $this->fetchUsers( [ 'learner', 'experienced' ], $now ),
                        'Learner and more experienced'
                );
-
-               // newcomers, learner, and more experienced
-               // TOOD: Fix test.  This needs to test that anons are excluded,
-               // and right now the join fails.
-               /* $this->assertArrayEquals( */
-               /*      [ */
-               /*              'Newcomer1', 'Newcomer2', 'Newcomer3', */
-               /*              'Learner1', 'Learner2', 'Learner3', 'Learner4', */
-               /*              'Experienced1', */
-               /*      ], */
-               /*      $this->fetchUsers( [ 'newcomer', 'learner', 'experienced' ] ) */
-               /* ); */
        }
 
-       private function createUsers( $specs ) {
+       private function createUsers( $specs, $now ) {
                $dbw = wfGetDB( DB_MASTER );
                foreach ( $specs as $name => $spec ) {
                        User::createNew(
                                $name,
                                [
                                        'editcount' => $spec['edits'],
-                                       'registration' => $dbw->timestamp( $this->daysAgo( $spec['days'] ) ),
+                                       'registration' => $dbw->timestamp( $this->daysAgo( $spec['days'], $now ) ),
                                        'email' => 'ut',
                                ]
                        );
                }
        }
 
-       private function fetchUsers( $filters ) {
+       private function fetchUsers( $filters, $now ) {
                $tables = [];
                $conds = [];
                $fields = [];
@@ -507,12 +581,13 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                                &$conds,
                                &$query_options,
                                &$join_conds,
-                               $filters
+                               $filters,
+                               $now
                        ]
                );
 
                $result = wfGetDB( DB_MASTER )->select(
-                       'user',
+                       $tables,
                        'user_name',
                        array_filter( $conds ) + [ 'user_email' => 'ut' ]
                );
@@ -525,9 +600,9 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                return $usernames;
        }
 
-       private function daysAgo( $days ) {
+       private function daysAgo( $days, $now ) {
                $secondsPerDay = 86400;
-               return time() - $days * $secondsPerDay;
+               return $now - $days * $secondsPerDay;
        }
 
        public function testGetFilterGroupDefinitionFromLegacyCustomFilters() {
@@ -568,6 +643,8 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
        }
 
        public function testGetStructuredFilterJsData() {
+               $this->changesListSpecialPage->filterGroups = [];
+
                $definition = [
                        [
                                'name' => 'gub-group',
@@ -816,7 +893,7 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                                        "hideliu" => true,
                                        "userExpLevel" => "newcomer",
                                ],
-                               "expectedConflicts" => true,
+                               "expectedConflicts" => false,
                        ],
                        [
                                "parameters" => [
@@ -885,4 +962,47 @@ class ChangesListSpecialPageTest extends AbstractChangesListSpecialPageTestCase
                        $this->changesListSpecialPage->areFiltersInConflict()
                );
        }
+
+       public function validateOptionsProvider() {
+               return [
+                       [
+                               [ 'hideanons' => 1, 'hideliu' => 1, 'hidebots' => 1 ],
+                               true,
+                               [ 'hideliu' => 1, 'hidebots' => 1, ],
+                       ],
+
+                       [
+                               [ 'hideanons' => 1, 'hideliu' => 1, 'hidebots' => 0 ],
+                               true,
+                               [ 'hidebots' => 0, 'hidehumans' => 1 ],
+                       ],
+
+                       [
+                               [ 'hidemyself' => 1, 'hidebyothers' => 1 ],
+                               true,
+                               [],
+                       ],
+                       [
+                               [ 'hidebots' => 1, 'hidehumans' => 1 ],
+                               true,
+                               [],
+                       ],
+                       [
+                               [ 'hidepatrolled' => 1, 'hideunpatrolled' => 1 ],
+                               true,
+                               [],
+                       ],
+                       [
+                               [ 'hideminor' => 1, 'hidemajor' => 1 ],
+                               true,
+                               [],
+                       ],
+                       [
+                               // changeType
+                               [ 'hidepageedits' => 1, 'hidenewpages' => 1, 'hidecategorization' => 1, 'hidelog' => 1, ],
+                               true,
+                               [],
+                       ],
+               ];
+       }
 }