Merge "HtmlFormatter::filterContent() should always return an array"
[lhc/web/wiklou.git] / tests / phpunit / includes / UserTest.php
1 <?php
2
3 define( 'NS_UNITTEST', 5600 );
4 define( 'NS_UNITTEST_TALK', 5601 );
5
6 /**
7 * @group Database
8 */
9 class UserTest extends MediaWikiTestCase {
10 /**
11 * @var User
12 */
13 protected $user;
14
15 protected function setUp() {
16 parent::setUp();
17
18 $this->setMwGlobals( array(
19 'wgGroupPermissions' => array(),
20 'wgRevokePermissions' => array(),
21 ) );
22
23 $this->setUpPermissionGlobals();
24
25 $this->user = new User;
26 $this->user->addGroup( 'unittesters' );
27 }
28
29 private function setUpPermissionGlobals() {
30 global $wgGroupPermissions, $wgRevokePermissions;
31
32 # Data for regular $wgGroupPermissions test
33 $wgGroupPermissions['unittesters'] = array(
34 'test' => true,
35 'runtest' => true,
36 'writetest' => false,
37 'nukeworld' => false,
38 );
39 $wgGroupPermissions['testwriters'] = array(
40 'test' => true,
41 'writetest' => true,
42 'modifytest' => true,
43 );
44
45 # Data for regular $wgRevokePermissions test
46 $wgRevokePermissions['formertesters'] = array(
47 'runtest' => true,
48 );
49
50 # For the options test
51 $wgGroupPermissions['*'] = array(
52 'editmyoptions' => true,
53 );
54 }
55
56 /**
57 * @covers User::getGroupPermissions
58 */
59 public function testGroupPermissions() {
60 $rights = User::getGroupPermissions( array( 'unittesters' ) );
61 $this->assertContains( 'runtest', $rights );
62 $this->assertNotContains( 'writetest', $rights );
63 $this->assertNotContains( 'modifytest', $rights );
64 $this->assertNotContains( 'nukeworld', $rights );
65
66 $rights = User::getGroupPermissions( array( 'unittesters', 'testwriters' ) );
67 $this->assertContains( 'runtest', $rights );
68 $this->assertContains( 'writetest', $rights );
69 $this->assertContains( 'modifytest', $rights );
70 $this->assertNotContains( 'nukeworld', $rights );
71 }
72
73 /**
74 * @covers User::getGroupPermissions
75 */
76 public function testRevokePermissions() {
77 $rights = User::getGroupPermissions( array( 'unittesters', 'formertesters' ) );
78 $this->assertNotContains( 'runtest', $rights );
79 $this->assertNotContains( 'writetest', $rights );
80 $this->assertNotContains( 'modifytest', $rights );
81 $this->assertNotContains( 'nukeworld', $rights );
82 }
83
84 /**
85 * @covers User::getRights
86 */
87 public function testUserPermissions() {
88 $rights = $this->user->getRights();
89 $this->assertContains( 'runtest', $rights );
90 $this->assertNotContains( 'writetest', $rights );
91 $this->assertNotContains( 'modifytest', $rights );
92 $this->assertNotContains( 'nukeworld', $rights );
93 }
94
95 /**
96 * @dataProvider provideGetGroupsWithPermission
97 * @covers User::getGroupsWithPermission
98 */
99 public function testGetGroupsWithPermission( $expected, $right ) {
100 $result = User::getGroupsWithPermission( $right );
101 sort( $result );
102 sort( $expected );
103
104 $this->assertEquals( $expected, $result, "Groups with permission $right" );
105 }
106
107 public static function provideGetGroupsWithPermission() {
108 return array(
109 array(
110 array( 'unittesters', 'testwriters' ),
111 'test'
112 ),
113 array(
114 array( 'unittesters' ),
115 'runtest'
116 ),
117 array(
118 array( 'testwriters' ),
119 'writetest'
120 ),
121 array(
122 array( 'testwriters' ),
123 'modifytest'
124 ),
125 );
126 }
127
128 /**
129 * @dataProvider provideUserNames
130 * @covers User::isValidUserName
131 */
132 public function testIsValidUserName( $username, $result, $message ) {
133 $this->assertEquals( $this->user->isValidUserName( $username ), $result, $message );
134 }
135
136 public static function provideUserNames() {
137 return array(
138 array( '', false, 'Empty string' ),
139 array( ' ', false, 'Blank space' ),
140 array( 'abcd', false, 'Starts with small letter' ),
141 array( 'Ab/cd', false, 'Contains slash' ),
142 array( 'Ab cd', true, 'Whitespace' ),
143 array( '192.168.1.1', false, 'IP' ),
144 array( 'User:Abcd', false, 'Reserved Namespace' ),
145 array( '12abcd232', true, 'Starts with Numbers' ),
146 array( '?abcd', true, 'Start with ? mark' ),
147 array( '#abcd', false, 'Start with #' ),
148 array( 'Abcdകഖഗഘ', true, ' Mixed scripts' ),
149 array( 'ജോസ്‌തോമസ്', false, 'ZWNJ- Format control character' ),
150 array( 'Ab cd', false, ' Ideographic space' ),
151 );
152 }
153
154 /**
155 * Test, if for all rights a right- message exist,
156 * which is used on Special:ListGroupRights as help text
157 * Extensions and core
158 */
159 public function testAllRightsWithMessage() {
160 //Getting all user rights, for core: User::$mCoreRights, for extensions: $wgAvailableRights
161 $allRights = User::getAllRights();
162 $allMessageKeys = Language::getMessageKeysFor( 'en' );
163
164 $rightsWithMessage = array();
165 foreach ( $allMessageKeys as $message ) {
166 // === 0: must be at beginning of string (position 0)
167 if ( strpos( $message, 'right-' ) === 0 ) {
168 $rightsWithMessage[] = substr( $message, strlen( 'right-' ) );
169 }
170 }
171
172 sort( $allRights );
173 sort( $rightsWithMessage );
174
175 $this->assertEquals(
176 $allRights,
177 $rightsWithMessage,
178 'Each user rights (core/extensions) has a corresponding right- message.'
179 );
180 }
181
182 /**
183 * Test User::editCount
184 * @group medium
185 * @covers User::getEditCount
186 */
187 public function testEditCount() {
188 $user = User::newFromName( 'UnitTestUser' );
189 $user->loadDefaults();
190 $user->addToDatabase();
191
192 // let the user have a few (3) edits
193 $page = WikiPage::factory( Title::newFromText( 'Help:UserTest_EditCount' ) );
194 for ( $i = 0; $i < 3; $i++ ) {
195 $page->doEdit( (string)$i, 'test', 0, false, $user );
196 }
197
198 $user->clearInstanceCache();
199 $this->assertEquals(
200 3,
201 $user->getEditCount(),
202 'After three edits, the user edit count should be 3'
203 );
204
205 // increase the edit count and clear the cache
206 $user->incEditCount();
207
208 $user->clearInstanceCache();
209 $this->assertEquals(
210 4,
211 $user->getEditCount(),
212 'After increasing the edit count manually, the user edit count should be 4'
213 );
214 }
215
216 /**
217 * Test changing user options.
218 * @covers User::setOption
219 * @covers User::getOption
220 */
221 public function testOptions() {
222 $user = User::newFromName( 'UnitTestUser' );
223 $user->addToDatabase();
224
225 $user->setOption( 'someoption', 'test' );
226 $user->setOption( 'cols', 200 );
227 $user->saveSettings();
228
229 $user = User::newFromName( 'UnitTestUser' );
230 $this->assertEquals( 'test', $user->getOption( 'someoption' ) );
231 $this->assertEquals( 200, $user->getOption( 'cols' ) );
232 }
233
234 /**
235 * Bug 37963
236 * Make sure defaults are loaded when setOption is called.
237 * @covers User::loadOptions
238 */
239 public function testAnonOptions() {
240 global $wgDefaultUserOptions;
241 $this->user->setOption( 'someoption', 'test' );
242 $this->assertEquals( $wgDefaultUserOptions['cols'], $this->user->getOption( 'cols' ) );
243 $this->assertEquals( 'test', $this->user->getOption( 'someoption' ) );
244 }
245
246 /**
247 * Test password expiration.
248 * @covers User::getPasswordExpired()
249 */
250 public function testPasswordExpire() {
251 global $wgPasswordExpireGrace;
252 $wgTemp = $wgPasswordExpireGrace;
253 $wgPasswordExpireGrace = 3600 * 24 * 7; // 7 days
254
255 $user = User::newFromName( 'UnitTestUser' );
256 $user->loadDefaults();
257 $this->assertEquals( false, $user->getPasswordExpired() );
258
259 $ts = time() - ( 3600 * 24 * 1 ); // 1 day ago
260 $user->expirePassword( $ts );
261 $this->assertEquals( 'soft', $user->getPasswordExpired() );
262
263 $ts = time() - ( 3600 * 24 * 10 ); // 10 days ago
264 $user->expirePassword( $ts );
265 $this->assertEquals( 'hard', $user->getPasswordExpired() );
266
267 $wgPasswordExpireGrace = $wgTemp;
268 }
269
270 /**
271 * Test password validity checks. There are 3 checks in core,
272 * - ensure the password meets the minimal length
273 * - ensure the password is not the same as the username
274 * - ensure the username/password combo isn't forbidden
275 * @covers User::checkPasswordValidity()
276 * @covers User::getPasswordValidity()
277 * @covers User::isValidPassword()
278 */
279 public function testCheckPasswordValidity() {
280 $this->setMwGlobals( 'wgMinimalPasswordLength', 6 );
281 $user = User::newFromName( 'Useruser' );
282 // Sanity
283 $this->assertTrue( $user->isValidPassword( 'Password1234' ) );
284
285 // Minimum length
286 $this->assertFalse( $user->isValidPassword( 'a' ) );
287 $this->assertFalse( $user->checkPasswordValidity( 'a' )->isGood() );
288 $this->assertEquals( 'passwordtooshort', $user->getPasswordValidity( 'a' ) );
289
290 // Matches username
291 $this->assertFalse( $user->checkPasswordValidity( 'Useruser' )->isGood() );
292 $this->assertEquals( 'password-name-match', $user->getPasswordValidity( 'Useruser' ) );
293
294 // On the forbidden list
295 $this->assertFalse( $user->checkPasswordValidity( 'Passpass' )->isGood() );
296 $this->assertEquals( 'password-login-forbidden', $user->getPasswordValidity( 'Passpass' ) );
297 }
298 }