Make SpecialBlankPageTest independend from the language
[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 provideProcessFormErrors
396 * @covers ::processForm()
397 */
398 public function testProcessFormErrors( $data, $expected, $config = [] ) {
399 $defaultConfig = [
400 'wgEnablePartialBlocks' => true,
401 'wgBlockAllowsUTEdit' => true,
402 ];
403
404 $this->setMwGlobals( array_merge( $defaultConfig, $config ) );
405
406 $defaultData = [
407 'Target' => '1.2.3.4',
408 'Expiry' => 'infinity',
409 'Reason' => [ 'bad reason' ],
410 'Confirm' => false,
411 'PageRestrictions' => '',
412 'NamespaceRestrictions' => '',
413 ];
414
415 $context = RequestContext::getMain();
416 $page = $this->newSpecialPage();
417 $result = $page->processForm( array_merge( $defaultData, $data ), $context );
418
419 $this->assertEquals( $result[0], $expected );
420 }
421
422 public function provideProcessFormErrors() {
423 return [
424 'Invalid expiry' => [
425 [
426 'Expiry' => 'invalid',
427 ],
428 'ipb_expiry_invalid',
429 ],
430 'Expiry is in the past' => [
431 [
432 'Expiry' => 'yesterday',
433 ],
434 'ipb_expiry_old',
435 ],
436 'HideUser with wrong permissions' => [
437 [
438 'HideUser' => 1,
439 ],
440 'badaccess-group0',
441 ],
442 'Bad ip address' => [
443 [
444 'Target' => '1.2.3.4/1234',
445 ],
446 'badipaddress',
447 ],
448 'Edit user talk page invalid with no restrictions' => [
449 [
450 'EditingRestriction' => 'partial',
451 'DisableUTEdit' => 1,
452 ],
453 'ipb-prevent-user-talk-edit',
454 ],
455 'Edit user talk page invalid with namespace restriction != NS_USER_TALK ' => [
456 [
457 'EditingRestriction' => 'partial',
458 'DisableUTEdit' => 1,
459 'NamespaceRestrictions' => NS_USER
460 ],
461 'ipb-prevent-user-talk-edit',
462 ],
463 ];
464 }
465
466 /**
467 * @dataProvider provideCheckUnblockSelf
468 * @covers ::checkUnblockSelf
469 */
470 public function testCheckUnblockSelf(
471 $blockedUser,
472 $blockPerformer,
473 $adjustPerformer,
474 $adjustTarget,
475 $expectedResult,
476 $reason
477 ) {
478 $this->setMwGlobals( [
479 'wgBlockDisablesLogin' => false,
480 ] );
481 $this->setGroupPermissions( 'sysop', 'unblockself', true );
482 $this->setGroupPermissions( 'user', 'block', true );
483 // Getting errors about creating users in db in provider.
484 // Need to use mutable to ensure different named testusers.
485 $users = [
486 'u1' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
487 'u2' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
488 'u3' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
489 'u4' => TestUserRegistry::getMutableTestUser( __CLASS__, 'sysop' )->getUser(),
490 'nonsysop' => $this->getTestUser()->getUser()
491 ];
492 foreach ( [ 'blockedUser', 'blockPerformer', 'adjustPerformer', 'adjustTarget' ] as $var ) {
493 $$var = $users[$$var];
494 }
495
496 $block = new DatabaseBlock( [
497 'address' => $blockedUser->getName(),
498 'user' => $blockedUser->getId(),
499 'by' => $blockPerformer->getId(),
500 'expiry' => 'infinity',
501 'sitewide' => 1,
502 'enableAutoblock' => true,
503 ] );
504
505 $block->insert();
506
507 $this->assertSame(
508 SpecialBlock::checkUnblockSelf( $adjustTarget, $adjustPerformer ),
509 $expectedResult,
510 $reason
511 );
512 }
513
514 public function provideCheckUnblockSelf() {
515 // 'blockedUser', 'blockPerformer', 'adjustPerformer', 'adjustTarget'
516 return [
517 [ 'u1', 'u2', 'u3', 'u4', true, 'Unrelated users' ],
518 [ 'u1', 'u2', 'u1', 'u4', 'ipbblocked', 'Block unrelated while blocked' ],
519 [ 'u1', 'u2', 'u1', 'u1', true, 'Has unblockself' ],
520 [ 'nonsysop', 'u2', 'nonsysop', 'nonsysop', 'ipbnounblockself', 'no unblockself' ],
521 [ 'nonsysop', 'nonsysop', 'nonsysop', 'nonsysop', true, 'no unblockself but can de-selfblock' ],
522 [ 'u1', 'u2', 'u1', 'u2', true, 'Can block user who blocked' ],
523 ];
524 }
525
526 protected function insertBlock() {
527 $badActor = $this->getTestUser()->getUser();
528 $sysop = $this->getTestSysop()->getUser();
529
530 $block = new DatabaseBlock( [
531 'address' => $badActor->getName(),
532 'user' => $badActor->getId(),
533 'by' => $sysop->getId(),
534 'expiry' => 'infinity',
535 'sitewide' => 1,
536 'enableAutoblock' => true,
537 ] );
538
539 $block->insert();
540
541 return $block;
542 }
543
544 protected function resetTables() {
545 $this->db->delete( 'ipblocks', '*', __METHOD__ );
546 $this->db->delete( 'ipblocks_restrictions', '*', __METHOD__ );
547 }
548
549 /**
550 * Get a BlockRestrictionStore instance
551 *
552 * @return BlockRestrictionStore
553 */
554 private function getBlockRestrictionStore() : BlockRestrictionStore {
555 $loadBalancer = $this->getMockBuilder( LoadBalancer::class )
556 ->disableOriginalConstructor()
557 ->getMock();
558
559 return new BlockRestrictionStore( $loadBalancer );
560 }
561 }