Merge "Add checkDependencies.php"
[lhc/web/wiklou.git] / tests / phpunit / includes / specials / SpecialBlockTest.php
1 <?php
2
3 use MediaWiki\Block\BlockRestrictionStore;
4 use MediaWiki\Block\DatabaseBlock;
5 use MediaWiki\Block\Restriction\PageRestriction;
6 use MediaWiki\Block\Restriction\NamespaceRestriction;
7 use Wikimedia\TestingAccessWrapper;
8 use Wikimedia\Rdbms\LoadBalancer;
9
10 /**
11 * @group Blocking
12 * @group Database
13 * @coversDefaultClass SpecialBlock
14 */
15 class SpecialBlockTest extends SpecialPageTestBase {
16 /**
17 * @inheritDoc
18 */
19 protected function newSpecialPage() {
20 return new SpecialBlock();
21 }
22
23 public function tearDown() {
24 parent::tearDown();
25 $this->resetTables();
26 }
27
28 /**
29 * @covers ::getFormFields()
30 */
31 public function testGetFormFields() {
32 $this->setMwGlobals( [
33 'wgEnablePartialBlocks' => false,
34 'wgBlockAllowsUTEdit' => true,
35 ] );
36 $page = $this->newSpecialPage();
37 $wrappedPage = TestingAccessWrapper::newFromObject( $page );
38 $fields = $wrappedPage->getFormFields();
39 $this->assertInternalType( 'array', $fields );
40 $this->assertArrayHasKey( 'Target', $fields );
41 $this->assertArrayHasKey( 'Expiry', $fields );
42 $this->assertArrayHasKey( 'Reason', $fields );
43 $this->assertArrayHasKey( 'CreateAccount', $fields );
44 $this->assertArrayHasKey( 'DisableUTEdit', $fields );
45 $this->assertArrayHasKey( 'AutoBlock', $fields );
46 $this->assertArrayHasKey( 'HardBlock', $fields );
47 $this->assertArrayHasKey( 'PreviousTarget', $fields );
48 $this->assertArrayHasKey( 'Confirm', $fields );
49
50 $this->assertArrayNotHasKey( 'EditingRestriction', $fields );
51 $this->assertArrayNotHasKey( 'PageRestrictions', $fields );
52 $this->assertArrayNotHasKey( 'NamespaceRestrictions', $fields );
53 }
54
55 /**
56 * @covers ::getFormFields()
57 */
58 public function testGetFormFieldsPartialBlocks() {
59 $this->setMwGlobals( [
60 'wgEnablePartialBlocks' => true,
61 ] );
62 $page = $this->newSpecialPage();
63 $wrappedPage = TestingAccessWrapper::newFromObject( $page );
64 $fields = $wrappedPage->getFormFields();
65
66 $this->assertArrayHasKey( 'EditingRestriction', $fields );
67 $this->assertArrayHasKey( 'PageRestrictions', $fields );
68 $this->assertArrayHasKey( 'NamespaceRestrictions', $fields );
69 }
70
71 /**
72 * @covers ::maybeAlterFormDefaults()
73 */
74 public function testMaybeAlterFormDefaults() {
75 $this->setMwGlobals( [
76 'wgEnablePartialBlocks' => false,
77 'wgBlockAllowsUTEdit' => true,
78 ] );
79
80 $block = $this->insertBlock();
81
82 // Refresh the block from the database.
83 $block = DatabaseBlock::newFromTarget( $block->getTarget() );
84
85 $page = $this->newSpecialPage();
86
87 $wrappedPage = TestingAccessWrapper::newFromObject( $page );
88 $wrappedPage->target = $block->getTarget();
89 $fields = $wrappedPage->getFormFields();
90
91 $this->assertSame( (string)$block->getTarget(), $fields['Target']['default'] );
92 $this->assertSame( $block->isHardblock(), $fields['HardBlock']['default'] );
93 $this->assertSame( $block->isCreateAccountBlocked(), $fields['CreateAccount']['default'] );
94 $this->assertSame( $block->isAutoblocking(), $fields['AutoBlock']['default'] );
95 $this->assertSame( !$block->isUsertalkEditAllowed(), $fields['DisableUTEdit']['default'] );
96 $this->assertSame( $block->getReason(), $fields['Reason']['default'] );
97 $this->assertSame( 'infinite', $fields['Expiry']['default'] );
98 }
99
100 /**
101 * @covers ::maybeAlterFormDefaults()
102 */
103 public function testMaybeAlterFormDefaultsPartial() {
104 $this->setMwGlobals( [
105 'wgEnablePartialBlocks' => true,
106 ] );
107
108 $badActor = $this->getTestUser()->getUser();
109 $sysop = $this->getTestSysop()->getUser();
110 $pageSaturn = $this->getExistingTestPage( 'Saturn' );
111 $pageMars = $this->getExistingTestPage( 'Mars' );
112
113 $block = new DatabaseBlock( [
114 'address' => $badActor->getName(),
115 'user' => $badActor->getId(),
116 'by' => $sysop->getId(),
117 'expiry' => 'infinity',
118 'sitewide' => 0,
119 'enableAutoblock' => true,
120 ] );
121
122 $block->setRestrictions( [
123 new PageRestriction( 0, $pageSaturn->getId() ),
124 new PageRestriction( 0, $pageMars->getId() ),
125 new NamespaceRestriction( 0, NS_TALK ),
126 // Deleted page.
127 new PageRestriction( 0, 999999 ),
128 ] );
129
130 $block->insert();
131
132 // Refresh the block from the database.
133 $block = DatabaseBlock::newFromTarget( $block->getTarget() );
134
135 $page = $this->newSpecialPage();
136
137 $wrappedPage = TestingAccessWrapper::newFromObject( $page );
138 $wrappedPage->target = $block->getTarget();
139 $fields = $wrappedPage->getFormFields();
140
141 $titles = [
142 $pageMars->getTitle()->getPrefixedText(),
143 $pageSaturn->getTitle()->getPrefixedText(),
144 ];
145
146 $this->assertSame( (string)$block->getTarget(), $fields['Target']['default'] );
147 $this->assertSame( 'partial', $fields['EditingRestriction']['default'] );
148 $this->assertSame( implode( "\n", $titles ), $fields['PageRestrictions']['default'] );
149 }
150
151 /**
152 * @covers ::processForm()
153 */
154 public function testProcessForm() {
155 $this->setMwGlobals( [
156 'wgEnablePartialBlocks' => false,
157 ] );
158 $badActor = $this->getTestUser()->getUser();
159 $context = RequestContext::getMain();
160
161 $page = $this->newSpecialPage();
162 $reason = 'test';
163 $expiry = 'infinity';
164 $data = [
165 'Target' => (string)$badActor,
166 'Expiry' => 'infinity',
167 'Reason' => [
168 $reason,
169 ],
170 'Confirm' => '1',
171 'CreateAccount' => '0',
172 'DisableUTEdit' => '0',
173 'DisableEmail' => '0',
174 'HardBlock' => '0',
175 'AutoBlock' => '1',
176 'HideUser' => '0',
177 'Watch' => '0',
178 ];
179 $result = $page->processForm( $data, $context );
180
181 $this->assertTrue( $result );
182
183 $block = DatabaseBlock::newFromTarget( $badActor );
184 $this->assertSame( $reason, $block->getReason() );
185 $this->assertSame( $expiry, $block->getExpiry() );
186 }
187
188 /**
189 * @covers ::processForm()
190 */
191 public function testProcessFormExisting() {
192 $this->setMwGlobals( [
193 'wgEnablePartialBlocks' => false,
194 ] );
195 $badActor = $this->getTestUser()->getUser();
196 $sysop = $this->getTestSysop()->getUser();
197 $context = RequestContext::getMain();
198
199 // Create a block that will be updated.
200 $block = new DatabaseBlock( [
201 'address' => $badActor->getName(),
202 'user' => $badActor->getId(),
203 'by' => $sysop->getId(),
204 'expiry' => 'infinity',
205 'sitewide' => 0,
206 'enableAutoblock' => false,
207 ] );
208 $block->insert();
209
210 $page = $this->newSpecialPage();
211 $reason = 'test';
212 $expiry = 'infinity';
213 $data = [
214 'Target' => (string)$badActor,
215 'Expiry' => 'infinity',
216 'Reason' => [
217 $reason,
218 ],
219 'Confirm' => '1',
220 'CreateAccount' => '0',
221 'DisableUTEdit' => '0',
222 'DisableEmail' => '0',
223 'HardBlock' => '0',
224 'AutoBlock' => '1',
225 'HideUser' => '0',
226 'Watch' => '0',
227 ];
228 $result = $page->processForm( $data, $context );
229
230 $this->assertTrue( $result );
231
232 $block = DatabaseBlock::newFromTarget( $badActor );
233 $this->assertSame( $reason, $block->getReason() );
234 $this->assertSame( $expiry, $block->getExpiry() );
235 $this->assertSame( '1', $block->isAutoblocking() );
236 }
237
238 /**
239 * @covers ::processForm()
240 */
241 public function testProcessFormRestrictions() {
242 $this->setMwGlobals( [
243 'wgEnablePartialBlocks' => true,
244 ] );
245 $badActor = $this->getTestUser()->getUser();
246 $context = RequestContext::getMain();
247
248 $pageSaturn = $this->getExistingTestPage( 'Saturn' );
249 $pageMars = $this->getExistingTestPage( 'Mars' );
250
251 $titles = [
252 $pageSaturn->getTitle()->getText(),
253 $pageMars->getTitle()->getText(),
254 ];
255
256 $page = $this->newSpecialPage();
257 $reason = 'test';
258 $expiry = 'infinity';
259 $data = [
260 'Target' => (string)$badActor,
261 'Expiry' => 'infinity',
262 'Reason' => [
263 $reason,
264 ],
265 'Confirm' => '1',
266 'CreateAccount' => '0',
267 'DisableUTEdit' => '0',
268 'DisableEmail' => '0',
269 'HardBlock' => '0',
270 'AutoBlock' => '1',
271 'HideUser' => '0',
272 'Watch' => '0',
273 'EditingRestriction' => 'partial',
274 'PageRestrictions' => implode( "\n", $titles ),
275 'NamespaceRestrictions' => '',
276 ];
277 $result = $page->processForm( $data, $context );
278
279 $this->assertTrue( $result );
280
281 $block = DatabaseBlock::newFromTarget( $badActor );
282 $this->assertSame( $reason, $block->getReason() );
283 $this->assertSame( $expiry, $block->getExpiry() );
284 $this->assertCount( 2, $block->getRestrictions() );
285 $this->assertTrue( $this->getBlockRestrictionStore()->equals( $block->getRestrictions(), [
286 new PageRestriction( $block->getId(), $pageMars->getId() ),
287 new PageRestriction( $block->getId(), $pageSaturn->getId() ),
288 ] ) );
289 }
290
291 /**
292 * @covers ::processForm()
293 */
294 public function testProcessFormRestrictionsChange() {
295 $this->setMwGlobals( [
296 'wgEnablePartialBlocks' => true,
297 ] );
298 $badActor = $this->getTestUser()->getUser();
299 $context = RequestContext::getMain();
300
301 $pageSaturn = $this->getExistingTestPage( 'Saturn' );
302 $pageMars = $this->getExistingTestPage( 'Mars' );
303
304 $titles = [
305 $pageSaturn->getTitle()->getText(),
306 $pageMars->getTitle()->getText(),
307 ];
308
309 // Create a partial block.
310 $page = $this->newSpecialPage();
311 $reason = 'test';
312 $expiry = 'infinity';
313 $data = [
314 'Target' => (string)$badActor,
315 'Expiry' => 'infinity',
316 'Reason' => [
317 $reason,
318 ],
319 'Confirm' => '1',
320 'CreateAccount' => '0',
321 'DisableUTEdit' => '0',
322 'DisableEmail' => '0',
323 'HardBlock' => '0',
324 'AutoBlock' => '1',
325 'HideUser' => '0',
326 'Watch' => '0',
327 'EditingRestriction' => 'partial',
328 'PageRestrictions' => implode( "\n", $titles ),
329 'NamespaceRestrictions' => '',
330 ];
331 $result = $page->processForm( $data, $context );
332
333 $this->assertTrue( $result );
334
335 $block = DatabaseBlock::newFromTarget( $badActor );
336 $this->assertSame( $reason, $block->getReason() );
337 $this->assertSame( $expiry, $block->getExpiry() );
338 $this->assertFalse( $block->isSitewide() );
339 $this->assertCount( 2, $block->getRestrictions() );
340 $this->assertTrue( $this->getBlockRestrictionStore()->equals( $block->getRestrictions(), [
341 new PageRestriction( $block->getId(), $pageMars->getId() ),
342 new PageRestriction( $block->getId(), $pageSaturn->getId() ),
343 ] ) );
344
345 // Remove a page from the partial block.
346 $data['PageRestrictions'] = $pageMars->getTitle()->getText();
347 $result = $page->processForm( $data, $context );
348
349 $this->assertTrue( $result );
350
351 $block = DatabaseBlock::newFromTarget( $badActor );
352 $this->assertSame( $reason, $block->getReason() );
353 $this->assertSame( $expiry, $block->getExpiry() );
354 $this->assertFalse( $block->isSitewide() );
355 $this->assertCount( 1, $block->getRestrictions() );
356 $this->assertTrue( $this->getBlockRestrictionStore()->equals( $block->getRestrictions(), [
357 new PageRestriction( $block->getId(), $pageMars->getId() ),
358 ] ) );
359
360 // Remove the last page from the block.
361 $data['PageRestrictions'] = '';
362 $result = $page->processForm( $data, $context );
363
364 $this->assertTrue( $result );
365
366 $block = DatabaseBlock::newFromTarget( $badActor );
367 $this->assertSame( $reason, $block->getReason() );
368 $this->assertSame( $expiry, $block->getExpiry() );
369 $this->assertFalse( $block->isSitewide() );
370 $this->assertCount( 0, $block->getRestrictions() );
371
372 // Change to sitewide.
373 $data['EditingRestriction'] = 'sitewide';
374 $result = $page->processForm( $data, $context );
375
376 $this->assertTrue( $result );
377
378 $block = DatabaseBlock::newFromTarget( $badActor );
379 $this->assertSame( $reason, $block->getReason() );
380 $this->assertSame( $expiry, $block->getExpiry() );
381 $this->assertTrue( $block->isSitewide() );
382 $this->assertCount( 0, $block->getRestrictions() );
383
384 // Ensure that there are no restrictions where the blockId is 0.
385 $count = $this->db->selectRowCount(
386 'ipblocks_restrictions',
387 '*',
388 [ 'ir_ipb_id' => 0 ],
389 __METHOD__
390 );
391 $this->assertSame( 0, $count );
392 }
393
394 /**
395 * @dataProvider provideCheckUnblockSelf
396 * @covers ::checkUnblockSelf
397 */
398 public function testCheckUnblockSelf(
399 $blockedUser,
400 $blockPerformer,
401 $adjustPerformer,
402 $adjustTarget,
403 $expectedResult,
404 $reason
405 ) {
406 $this->setMwGlobals( [
407 'wgBlockDisablesLogin' => false,
408 ] );
409 $this->setGroupPermissions( 'sysop', 'unblockself', true );
410 $this->setGroupPermissions( 'user', 'block', true );
411 // Getting errors about creating users in db in provider.
412 // Need to use mutable to ensure different named testusers.
413 $users = [
414 'u1' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
415 'u2' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
416 'u3' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
417 'u4' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
418 'nonsysop' => $this->getTestUser()->getUser()
419 ];
420 foreach ( [ 'blockedUser', 'blockPerformer', 'adjustPerformer', 'adjustTarget' ] as $var ) {
421 $$var = $users[$$var];
422 }
423
424 $block = new DatabaseBlock( [
425 'address' => $blockedUser->getName(),
426 'user' => $blockedUser->getId(),
427 'by' => $blockPerformer->getId(),
428 'expiry' => 'infinity',
429 'sitewide' => 1,
430 'enableAutoblock' => true,
431 ] );
432
433 $block->insert();
434
435 $this->assertSame(
436 SpecialBlock::checkUnblockSelf( $adjustTarget, $adjustPerformer ),
437 $expectedResult,
438 $reason
439 );
440 }
441
442 public function provideCheckUnblockSelf() {
443 // 'blockedUser', 'blockPerformer', 'adjustPerformer', 'adjustTarget'
444 return [
445 [ 'u1', 'u2', 'u3', 'u4', true, 'Unrelated users' ],
446 [ 'u1', 'u2', 'u1', 'u4', 'ipbblocked', 'Block unrelated while blocked' ],
447 [ 'u1', 'u2', 'u1', 'u1', true, 'Has unblockself' ],
448 [ 'nonsysop', 'u2', 'nonsysop', 'nonsysop', 'ipbnounblockself', 'no unblockself' ],
449 [ 'nonsysop', 'nonsysop', 'nonsysop', 'nonsysop', true, 'no unblockself but can de-selfblock' ],
450 [ 'u1', 'u2', 'u1', 'u2', true, 'Can block user who blocked' ],
451 ];
452 }
453
454 protected function insertBlock() {
455 $badActor = $this->getTestUser()->getUser();
456 $sysop = $this->getTestSysop()->getUser();
457
458 $block = new DatabaseBlock( [
459 'address' => $badActor->getName(),
460 'user' => $badActor->getId(),
461 'by' => $sysop->getId(),
462 'expiry' => 'infinity',
463 'sitewide' => 1,
464 'enableAutoblock' => true,
465 ] );
466
467 $block->insert();
468
469 return $block;
470 }
471
472 protected function resetTables() {
473 $this->db->delete( 'ipblocks', '*', __METHOD__ );
474 $this->db->delete( 'ipblocks_restrictions', '*', __METHOD__ );
475 }
476
477 /**
478 * Get a BlockRestrictionStore instance
479 *
480 * @return BlockRestrictionStore
481 */
482 private function getBlockRestrictionStore() : BlockRestrictionStore {
483 $loadBalancer = $this->getMockBuilder( LoadBalancer::class )
484 ->disableOriginalConstructor()
485 ->getMock();
486
487 return new BlockRestrictionStore( $loadBalancer );
488 }
489 }