Test that classes use all their ServiceOptions
[lhc/web/wiklou.git] / tests / phpunit / includes / title / NamespaceInfoTest.php
1 <?php
2 /**
3 * @author Antoine Musso
4 * @copyright Copyright © 2011, Antoine Musso
5 * @file
6 */
7
8 use MediaWiki\Config\ServiceOptions;
9 use MediaWiki\Linker\LinkTarget;
10
11 class NamespaceInfoTest extends MediaWikiTestCase {
12 use TestAllServiceOptionsUsed;
13
14 /**********************************************************************************************
15 * Shared code
16 * %{
17 */
18 private $scopedCallback;
19
20 public function setUp() {
21 parent::setUp();
22
23 // Boo, there's still some global state in the class :(
24 global $wgHooks;
25 $hooks = $wgHooks;
26 unset( $hooks['CanonicalNamespaces'] );
27 $this->setMwGlobals( 'wgHooks', $hooks );
28
29 $this->scopedCallback =
30 ExtensionRegistry::getInstance()->setAttributeForTest( 'ExtensionNamespaces', [] );
31 }
32
33 public function tearDown() {
34 $this->scopedCallback = null;
35
36 parent::tearDown();
37 }
38
39 /**
40 * TODO Make this a const once HHVM support is dropped (T192166)
41 */
42 private static $defaultOptions = [
43 'AllowImageMoving' => true,
44 'CanonicalNamespaceNames' => [
45 NS_TALK => 'Talk',
46 NS_USER => 'User',
47 NS_USER_TALK => 'User_talk',
48 NS_SPECIAL => 'Special',
49 NS_MEDIA => 'Media',
50 ],
51 'CapitalLinkOverrides' => [],
52 'CapitalLinks' => true,
53 'ContentNamespaces' => [ NS_MAIN ],
54 'ExtraNamespaces' => [],
55 'ExtraSignatureNamespaces' => [],
56 'NamespaceContentModels' => [],
57 'NamespaceProtection' => [],
58 'NamespacesWithSubpages' => [
59 NS_TALK => true,
60 NS_USER => true,
61 NS_USER_TALK => true,
62 ],
63 'NonincludableNamespaces' => [],
64 'RestrictionLevels' => [ '', 'autoconfirmed', 'sysop' ],
65 ];
66
67 private function newObj( array $options = [] ) : NamespaceInfo {
68 return new NamespaceInfo( new LoggedServiceOptions(
69 self::$serviceOptionsAccessLog,
70 NamespaceInfo::$constructorOptions,
71 $options, self::$defaultOptions
72 ) );
73 }
74
75 // %} End shared code
76
77 /**********************************************************************************************
78 * Basic methods
79 * %{
80 */
81
82 /**
83 * @covers NamespaceInfo::__construct
84 * @dataProvider provideConstructor
85 * @param ServiceOptions $options
86 * @param string|null $expectedExceptionText
87 */
88 public function testConstructor( ServiceOptions $options, $expectedExceptionText = null ) {
89 if ( $expectedExceptionText !== null ) {
90 $this->setExpectedException( \Wikimedia\Assert\PreconditionException::class,
91 $expectedExceptionText );
92 }
93 new NamespaceInfo( $options );
94 $this->assertTrue( true );
95 }
96
97 public function provideConstructor() {
98 return [
99 [ new ServiceOptions( NamespaceInfo::$constructorOptions, self::$defaultOptions ) ],
100 [ new ServiceOptions( [], [] ), 'Required options missing: ' ],
101 [ new ServiceOptions(
102 array_merge( NamespaceInfo::$constructorOptions, [ 'invalid' ] ),
103 self::$defaultOptions,
104 [ 'invalid' => '' ]
105 ), 'Unsupported options passed: invalid' ],
106 ];
107 }
108
109 /**
110 * @dataProvider provideIsMovable
111 * @covers NamespaceInfo::isMovable
112 *
113 * @param bool $expected
114 * @param int $ns
115 * @param bool $allowImageMoving
116 */
117 public function testIsMovable( $expected, $ns, $allowImageMoving = true ) {
118 $obj = $this->newObj( [ 'AllowImageMoving' => $allowImageMoving ] );
119 $this->assertSame( $expected, $obj->isMovable( $ns ) );
120 }
121
122 public function provideIsMovable() {
123 return [
124 'Main' => [ true, NS_MAIN ],
125 'Talk' => [ true, NS_TALK ],
126 'Special' => [ false, NS_SPECIAL ],
127 'Nonexistent even namespace' => [ true, 1234 ],
128 'Nonexistent odd namespace' => [ true, 12345 ],
129
130 'Media with image moving' => [ false, NS_MEDIA, true ],
131 'Media with no image moving' => [ false, NS_MEDIA, false ],
132 'File with image moving' => [ true, NS_FILE, true ],
133 'File with no image moving' => [ false, NS_FILE, false ],
134 ];
135 }
136
137 /**
138 * @param int $ns
139 * @param bool $expected
140 * @dataProvider provideIsSubject
141 * @covers NamespaceInfo::isSubject
142 */
143 public function testIsSubject( $ns, $expected ) {
144 $this->assertSame( $expected, $this->newObj()->isSubject( $ns ) );
145 }
146
147 /**
148 * @param int $ns
149 * @param bool $expected
150 * @dataProvider provideIsSubject
151 * @covers NamespaceInfo::isTalk
152 */
153 public function testIsTalk( $ns, $expected ) {
154 $this->assertSame( !$expected, $this->newObj()->isTalk( $ns ) );
155 }
156
157 public function provideIsSubject() {
158 return [
159 // Special namespaces
160 [ NS_MEDIA, true ],
161 [ NS_SPECIAL, true ],
162
163 // Subject pages
164 [ NS_MAIN, true ],
165 [ NS_USER, true ],
166 [ 100, true ],
167
168 // Talk pages
169 [ NS_TALK, false ],
170 [ NS_USER_TALK, false ],
171 [ 101, false ],
172 ];
173 }
174
175 /**
176 * @covers NamespaceInfo::exists
177 * @dataProvider provideExists
178 * @param int $ns
179 * @param bool $expected
180 */
181 public function testExists( $ns, $expected ) {
182 $this->assertSame( $expected, $this->newObj()->exists( $ns ) );
183 }
184
185 public function provideExists() {
186 return [
187 'Main' => [ NS_MAIN, true ],
188 'Talk' => [ NS_TALK, true ],
189 'Media' => [ NS_MEDIA, true ],
190 'Special' => [ NS_SPECIAL, true ],
191 'Nonexistent' => [ 12345, false ],
192 'Negative nonexistent' => [ -12345, false ],
193 ];
194 }
195
196 /**
197 * Note if we add a namespace registration system with keys like 'MAIN'
198 * we should add tests here for equivalence on things like 'MAIN' == 0
199 * and 'MAIN' == NS_MAIN.
200 * @covers NamespaceInfo::equals
201 */
202 public function testEquals() {
203 $obj = $this->newObj();
204 $this->assertTrue( $obj->equals( NS_MAIN, NS_MAIN ) );
205 $this->assertTrue( $obj->equals( NS_MAIN, 0 ) ); // In case we make NS_MAIN 'MAIN'
206 $this->assertTrue( $obj->equals( NS_USER, NS_USER ) );
207 $this->assertTrue( $obj->equals( NS_USER, 2 ) );
208 $this->assertTrue( $obj->equals( NS_USER_TALK, NS_USER_TALK ) );
209 $this->assertTrue( $obj->equals( NS_SPECIAL, NS_SPECIAL ) );
210 $this->assertFalse( $obj->equals( NS_MAIN, NS_TALK ) );
211 $this->assertFalse( $obj->equals( NS_USER, NS_USER_TALK ) );
212 $this->assertFalse( $obj->equals( NS_PROJECT, NS_TEMPLATE ) );
213 }
214
215 /**
216 * @param int $ns1
217 * @param int $ns2
218 * @param bool $expected
219 * @dataProvider provideSubjectEquals
220 * @covers NamespaceInfo::subjectEquals
221 */
222 public function testSubjectEquals( $ns1, $ns2, $expected ) {
223 $this->assertSame( $expected, $this->newObj()->subjectEquals( $ns1, $ns2 ) );
224 }
225
226 public function provideSubjectEquals() {
227 return [
228 [ NS_MAIN, NS_MAIN, true ],
229 // In case we make NS_MAIN 'MAIN'
230 [ NS_MAIN, 0, true ],
231 [ NS_USER, NS_USER, true ],
232 [ NS_USER, 2, true ],
233 [ NS_USER_TALK, NS_USER_TALK, true ],
234 [ NS_SPECIAL, NS_SPECIAL, true ],
235 [ NS_MAIN, NS_TALK, true ],
236 [ NS_USER, NS_USER_TALK, true ],
237
238 [ NS_PROJECT, NS_TEMPLATE, false ],
239 [ NS_SPECIAL, NS_MAIN, false ],
240 [ NS_MEDIA, NS_SPECIAL, false ],
241 [ NS_SPECIAL, NS_MEDIA, false ],
242 ];
243 }
244
245 /**
246 * @dataProvider provideHasTalkNamespace
247 * @covers NamespaceInfo::hasTalkNamespace
248 *
249 * @param int $ns
250 * @param bool $expected
251 */
252 public function testHasTalkNamespace( $ns, $expected ) {
253 $this->assertSame( $expected, $this->newObj()->hasTalkNamespace( $ns ) );
254 }
255
256 public function provideHasTalkNamespace() {
257 return [
258 [ NS_MEDIA, false ],
259 [ NS_SPECIAL, false ],
260
261 [ NS_MAIN, true ],
262 [ NS_TALK, true ],
263 [ NS_USER, true ],
264 [ NS_USER_TALK, true ],
265
266 [ 100, true ],
267 [ 101, true ],
268 ];
269 }
270
271 /**
272 * @param int $ns
273 * @param bool $expected
274 * @param array $contentNamespaces
275 * @covers NamespaceInfo::isContent
276 * @dataProvider provideIsContent
277 */
278 public function testIsContent( $ns, $expected, $contentNamespaces = [ NS_MAIN ] ) {
279 $obj = $this->newObj( [ 'ContentNamespaces' => $contentNamespaces ] );
280 $this->assertSame( $expected, $obj->isContent( $ns ) );
281 }
282
283 public function provideIsContent() {
284 return [
285 [ NS_MAIN, true ],
286 [ NS_MEDIA, false ],
287 [ NS_SPECIAL, false ],
288 [ NS_TALK, false ],
289 [ NS_USER, false ],
290 [ NS_CATEGORY, false ],
291 [ 100, false ],
292 [ 100, true, [ NS_MAIN, 100, 252 ] ],
293 [ 252, true, [ NS_MAIN, 100, 252 ] ],
294 [ NS_MAIN, true, [ NS_MAIN, 100, 252 ] ],
295 // NS_MAIN is always content
296 [ NS_MAIN, true, [] ],
297 ];
298 }
299
300 /**
301 * @dataProvider provideWantSignatures
302 * @covers NamespaceInfo::wantSignatures
303 *
304 * @param int $index
305 * @param bool $expected
306 */
307 public function testWantSignatures( $index, $expected ) {
308 $this->assertSame( $expected, $this->newObj()->wantSignatures( $index ) );
309 }
310
311 public function provideWantSignatures() {
312 return [
313 'Main' => [ NS_MAIN, false ],
314 'Talk' => [ NS_TALK, true ],
315 'User' => [ NS_USER, false ],
316 'User talk' => [ NS_USER_TALK, true ],
317 'Special' => [ NS_SPECIAL, false ],
318 'Media' => [ NS_MEDIA, false ],
319 'Nonexistent talk' => [ 12345, true ],
320 'Nonexistent subject' => [ 123456, false ],
321 'Nonexistent negative odd' => [ -12345, false ],
322 ];
323 }
324
325 /**
326 * @dataProvider provideWantSignatures_ExtraSignatureNamespaces
327 * @covers NamespaceInfo::wantSignatures
328 *
329 * @param int $index
330 * @param int $expected
331 */
332 public function testWantSignatures_ExtraSignatureNamespaces( $index, $expected ) {
333 $obj = $this->newObj( [ 'ExtraSignatureNamespaces' =>
334 [ NS_MAIN, NS_USER, NS_SPECIAL, NS_MEDIA, 123456, -12345 ] ] );
335 $this->assertSame( $expected, $obj->wantSignatures( $index ) );
336 }
337
338 public function provideWantSignatures_ExtraSignatureNamespaces() {
339 $ret = array_map(
340 function ( $arr ) {
341 // We've added all these as extra signature namespaces, so expect true
342 return [ $arr[0], true ];
343 },
344 self::provideWantSignatures()
345 );
346
347 // Add one more that's false
348 $ret['Another nonexistent subject'] = [ 12345678, false ];
349 return $ret;
350 }
351
352 /**
353 * @param int $ns
354 * @param bool $expected
355 * @covers NamespaceInfo::isWatchable
356 * @dataProvider provideIsWatchable
357 */
358 public function testIsWatchable( $ns, $expected ) {
359 $this->assertSame( $expected, $this->newObj()->isWatchable( $ns ) );
360 }
361
362 public function provideIsWatchable() {
363 return [
364 // Specials namespaces are not watchable
365 [ NS_MEDIA, false ],
366 [ NS_SPECIAL, false ],
367
368 // Core defined namespaces are watchables
369 [ NS_MAIN, true ],
370 [ NS_TALK, true ],
371
372 // Additional, user defined namespaces are watchables
373 [ 100, true ],
374 [ 101, true ],
375 ];
376 }
377
378 /**
379 * @param int $ns
380 * @param int $expected
381 * @param array|null $namespacesWithSubpages To pass to constructor
382 * @covers NamespaceInfo::hasSubpages
383 * @dataProvider provideHasSubpages
384 */
385 public function testHasSubpages( $ns, $expected, array $namespacesWithSubpages = null ) {
386 $obj = $this->newObj( $namespacesWithSubpages
387 ? [ 'NamespacesWithSubpages' => $namespacesWithSubpages ]
388 : [] );
389 $this->assertSame( $expected, $obj->hasSubpages( $ns ) );
390 }
391
392 public function provideHasSubpages() {
393 return [
394 // Special namespaces:
395 [ NS_MEDIA, false ],
396 [ NS_SPECIAL, false ],
397
398 // Namespaces without subpages
399 [ NS_MAIN, false ],
400 [ NS_MAIN, true, [ NS_MAIN => true ] ],
401 [ NS_MAIN, false, [ NS_MAIN => false ] ],
402
403 // Some namespaces with subpages
404 [ NS_TALK, true ],
405 [ NS_USER, true ],
406 [ NS_USER_TALK, true ],
407 ];
408 }
409
410 /**
411 * @param mixed $contentNamespaces To pass to constructor
412 * @param array $expected
413 * @dataProvider provideGetContentNamespaces
414 * @covers NamespaceInfo::getContentNamespaces
415 */
416 public function testGetContentNamespaces( $contentNamespaces, array $expected ) {
417 $obj = $this->newObj( [ 'ContentNamespaces' => $contentNamespaces ] );
418 $this->assertSame( $expected, $obj->getContentNamespaces() );
419 }
420
421 public function provideGetContentNamespaces() {
422 return [
423 // Non-array
424 [ '', [ NS_MAIN ] ],
425 [ false, [ NS_MAIN ] ],
426 [ null, [ NS_MAIN ] ],
427 [ 5, [ NS_MAIN ] ],
428
429 // Empty array
430 [ [], [ NS_MAIN ] ],
431
432 // NS_MAIN is forced to be content even if unwanted
433 [ [ NS_USER, NS_CATEGORY ], [ NS_MAIN, NS_USER, NS_CATEGORY ] ],
434
435 // In other cases, return as-is
436 [ [ NS_MAIN ], [ NS_MAIN ] ],
437 [ [ NS_MAIN, NS_USER, NS_CATEGORY ], [ NS_MAIN, NS_USER, NS_CATEGORY ] ],
438 ];
439 }
440
441 /**
442 * @covers NamespaceInfo::getSubjectNamespaces
443 */
444 public function testGetSubjectNamespaces() {
445 $subjectsNS = $this->newObj()->getSubjectNamespaces();
446 $this->assertContains( NS_MAIN, $subjectsNS,
447 "Talk namespaces should have NS_MAIN" );
448 $this->assertNotContains( NS_TALK, $subjectsNS,
449 "Talk namespaces should have NS_TALK" );
450
451 $this->assertNotContains( NS_MEDIA, $subjectsNS,
452 "Talk namespaces should not have NS_MEDIA" );
453 $this->assertNotContains( NS_SPECIAL, $subjectsNS,
454 "Talk namespaces should not have NS_SPECIAL" );
455 }
456
457 /**
458 * @covers NamespaceInfo::getTalkNamespaces
459 */
460 public function testGetTalkNamespaces() {
461 $talkNS = $this->newObj()->getTalkNamespaces();
462 $this->assertContains( NS_TALK, $talkNS,
463 "Subject namespaces should have NS_TALK" );
464 $this->assertNotContains( NS_MAIN, $talkNS,
465 "Subject namespaces should not have NS_MAIN" );
466
467 $this->assertNotContains( NS_MEDIA, $talkNS,
468 "Subject namespaces should not have NS_MEDIA" );
469 $this->assertNotContains( NS_SPECIAL, $talkNS,
470 "Subject namespaces should not have NS_SPECIAL" );
471 }
472
473 /**
474 * @param int $ns
475 * @param bool $expected
476 * @param bool $capitalLinks To pass to constructor
477 * @param array $capitalLinkOverrides To pass to constructor
478 * @dataProvider provideIsCapitalized
479 * @covers NamespaceInfo::isCapitalized
480 */
481 public function testIsCapitalized(
482 $ns, $expected, $capitalLinks = true, array $capitalLinkOverrides = []
483 ) {
484 $obj = $this->newObj( [
485 'CapitalLinks' => $capitalLinks,
486 'CapitalLinkOverrides' => $capitalLinkOverrides,
487 ] );
488 $this->assertSame( $expected, $obj->isCapitalized( $ns ) );
489 }
490
491 public function provideIsCapitalized() {
492 return [
493 // Test default settings
494 [ NS_PROJECT, true ],
495 [ NS_PROJECT_TALK, true ],
496 [ NS_MEDIA, true ],
497 [ NS_FILE, true ],
498
499 // Always capitalized no matter what
500 [ NS_SPECIAL, true, false ],
501 [ NS_USER, true, false ],
502 [ NS_MEDIAWIKI, true, false ],
503
504 // Even with an override too
505 [ NS_SPECIAL, true, false, [ NS_SPECIAL => false ] ],
506 [ NS_USER, true, false, [ NS_USER => false ] ],
507 [ NS_MEDIAWIKI, true, false, [ NS_MEDIAWIKI => false ] ],
508
509 // Overrides work for other namespaces
510 [ NS_PROJECT, false, true, [ NS_PROJECT => false ] ],
511 [ NS_PROJECT, true, false, [ NS_PROJECT => true ] ],
512
513 // NS_MEDIA is treated like NS_FILE, and ignores NS_MEDIA overrides
514 [ NS_MEDIA, false, true, [ NS_FILE => false, NS_MEDIA => true ] ],
515 [ NS_MEDIA, true, false, [ NS_FILE => true, NS_MEDIA => false ] ],
516 [ NS_FILE, false, true, [ NS_FILE => false, NS_MEDIA => true ] ],
517 [ NS_FILE, true, false, [ NS_FILE => true, NS_MEDIA => false ] ],
518 ];
519 }
520
521 /**
522 * @covers NamespaceInfo::hasGenderDistinction
523 */
524 public function testHasGenderDistinction() {
525 $obj = $this->newObj();
526
527 // Namespaces with gender distinctions
528 $this->assertTrue( $obj->hasGenderDistinction( NS_USER ) );
529 $this->assertTrue( $obj->hasGenderDistinction( NS_USER_TALK ) );
530
531 // Other ones, "genderless"
532 $this->assertFalse( $obj->hasGenderDistinction( NS_MEDIA ) );
533 $this->assertFalse( $obj->hasGenderDistinction( NS_SPECIAL ) );
534 $this->assertFalse( $obj->hasGenderDistinction( NS_MAIN ) );
535 $this->assertFalse( $obj->hasGenderDistinction( NS_TALK ) );
536 }
537
538 /**
539 * @covers NamespaceInfo::isNonincludable
540 */
541 public function testIsNonincludable() {
542 $obj = $this->newObj( [ 'NonincludableNamespaces' => [ NS_USER ] ] );
543 $this->assertTrue( $obj->isNonincludable( NS_USER ) );
544 $this->assertFalse( $obj->isNonincludable( NS_TEMPLATE ) );
545 }
546
547 /**
548 * @dataProvider provideGetNamespaceContentModel
549 * @covers NamespaceInfo::getNamespaceContentModel
550 *
551 * @param int $ns
552 * @param string $expected
553 */
554 public function testGetNamespaceContentModel( $ns, $expected ) {
555 $obj = $this->newObj( [ 'NamespaceContentModels' =>
556 [ NS_USER => CONTENT_MODEL_WIKITEXT, 123 => CONTENT_MODEL_JSON, 1234 => 'abcdef' ],
557 ] );
558 $this->assertSame( $expected, $obj->getNamespaceContentModel( $ns ) );
559 }
560
561 public function provideGetNamespaceContentModel() {
562 return [
563 [ NS_MAIN, null ],
564 [ NS_TALK, null ],
565 [ NS_USER, CONTENT_MODEL_WIKITEXT ],
566 [ NS_USER_TALK, null ],
567 [ NS_SPECIAL, null ],
568 [ 122, null ],
569 [ 123, CONTENT_MODEL_JSON ],
570 [ 1234, 'abcdef' ],
571 [ 1235, null ],
572 ];
573 }
574
575 /**
576 * @dataProvider provideGetCategoryLinkType
577 * @covers NamespaceInfo::getCategoryLinkType
578 *
579 * @param int $ns
580 * @param string $expected
581 */
582 public function testGetCategoryLinkType( $ns, $expected ) {
583 $this->assertSame( $expected, $this->newObj()->getCategoryLinkType( $ns ) );
584 }
585
586 public function provideGetCategoryLinkType() {
587 return [
588 [ NS_MAIN, 'page' ],
589 [ NS_TALK, 'page' ],
590 [ NS_USER, 'page' ],
591 [ NS_USER_TALK, 'page' ],
592
593 [ NS_FILE, 'file' ],
594 [ NS_FILE_TALK, 'page' ],
595
596 [ NS_CATEGORY, 'subcat' ],
597 [ NS_CATEGORY_TALK, 'page' ],
598
599 [ 100, 'page' ],
600 [ 101, 'page' ],
601 ];
602 }
603
604 // %} End basic methods
605
606 /**********************************************************************************************
607 * getSubject/Talk/Associated
608 * %{
609 */
610
611 /**
612 * @dataProvider provideSubjectTalk
613 * @covers NamespaceInfo::getSubject
614 * @covers NamespaceInfo::getSubjectPage
615 * @covers NamespaceInfo::isMethodValidFor
616 * @covers Title::getSubjectPage
617 *
618 * @param int $subject
619 * @param int $talk
620 */
621 public function testGetSubject( $subject, $talk ) {
622 $obj = $this->newObj();
623 $this->assertSame( $subject, $obj->getSubject( $subject ) );
624 $this->assertSame( $subject, $obj->getSubject( $talk ) );
625
626 $subjectTitleVal = new TitleValue( $subject, 'A' );
627 $talkTitleVal = new TitleValue( $talk, 'A' );
628 // Object will be the same one passed in if it's a subject, different but equal object if
629 // it's talk
630 $this->assertSame( $subjectTitleVal, $obj->getSubjectPage( $subjectTitleVal ) );
631 $this->assertEquals( $subjectTitleVal, $obj->getSubjectPage( $talkTitleVal ) );
632
633 $subjectTitle = Title::makeTitle( $subject, 'A' );
634 $talkTitle = Title::makeTitle( $talk, 'A' );
635 $this->assertSame( $subjectTitle, $subjectTitle->getSubjectPage() );
636 $this->assertEquals( $subjectTitle, $talkTitle->getSubjectPage() );
637 }
638
639 /**
640 * @dataProvider provideSpecialNamespaces
641 * @covers NamespaceInfo::getSubject
642 * @covers NamespaceInfo::getSubjectPage
643 *
644 * @param int $ns
645 */
646 public function testGetSubject_special( $ns ) {
647 $obj = $this->newObj();
648 $this->assertSame( $ns, $obj->getSubject( $ns ) );
649
650 $title = new TitleValue( $ns, 'A' );
651 $this->assertSame( $title, $obj->getSubjectPage( $title ) );
652 }
653
654 /**
655 * @dataProvider provideSubjectTalk
656 * @covers NamespaceInfo::getTalk
657 * @covers NamespaceInfo::getTalkPage
658 * @covers NamespaceInfo::isMethodValidFor
659 * @covers Title::getTalkPage
660 *
661 * @param int $subject
662 * @param int $talk
663 */
664 public function testGetTalk( $subject, $talk ) {
665 $obj = $this->newObj();
666 $this->assertSame( $talk, $obj->getTalk( $subject ) );
667 $this->assertSame( $talk, $obj->getTalk( $talk ) );
668
669 $subjectTitleVal = new TitleValue( $subject, 'A' );
670 $talkTitleVal = new TitleValue( $talk, 'A' );
671 // Object will be the same one passed in if it's a talk, different but equal object if it's
672 // subject
673 $this->assertEquals( $talkTitleVal, $obj->getTalkPage( $subjectTitleVal ) );
674 $this->assertSame( $talkTitleVal, $obj->getTalkPage( $talkTitleVal ) );
675
676 $subjectTitle = Title::makeTitle( $subject, 'A' );
677 $talkTitle = Title::makeTitle( $talk, 'A' );
678 $this->assertEquals( $talkTitle, $subjectTitle->getTalkPage() );
679 $this->assertSame( $talkTitle, $talkTitle->getTalkPage() );
680 }
681
682 /**
683 * @dataProvider provideSpecialNamespaces
684 * @covers NamespaceInfo::getTalk
685 * @covers NamespaceInfo::isMethodValidFor
686 *
687 * @param int $ns
688 */
689 public function testGetTalk_special( $ns ) {
690 $this->setExpectedException( MWException::class,
691 "NamespaceInfo::getTalk does not make any sense for given namespace $ns" );
692 $this->newObj()->getTalk( $ns );
693 }
694
695 /**
696 * @dataProvider provideSpecialNamespaces
697 * @covers NamespaceInfo::getAssociated
698 * @covers NamespaceInfo::isMethodValidFor
699 *
700 * @param int $ns
701 */
702 public function testGetAssociated_special( $ns ) {
703 $this->setExpectedException(
704 MWException::class,
705 "NamespaceInfo::getAssociated does not make any sense for given namespace $ns"
706 );
707 $this->newObj()->getAssociated( $ns );
708 }
709
710 public static function provideCanHaveTalkPage() {
711 return [
712 [ new TitleValue( NS_MAIN, 'Test' ), true ],
713 [ new TitleValue( NS_TALK, 'Test' ), true ],
714 [ new TitleValue( NS_USER, 'Test' ), true ],
715 [ new TitleValue( NS_SPECIAL, 'Test' ), false ],
716 [ new TitleValue( NS_MEDIA, 'Test' ), false ],
717 [ new TitleValue( NS_MAIN, '', 'Kittens' ), false ],
718 [ new TitleValue( NS_MAIN, 'Kittens', '', 'acme' ), false ],
719 ];
720 }
721
722 /**
723 * @dataProvider provideCanHaveTalkPage
724 * @covers NamespaceInfo::canHaveTalkPage
725 */
726 public function testCanHaveTalkPage( LinkTarget $t, $expected ) {
727 $actual = $this->newObj()->canHaveTalkPage( $t );
728 $this->assertEquals( $expected, $actual, $t->getDBkey() );
729 }
730
731 public static function provideGetTalkPage_good() {
732 return [
733 [ new TitleValue( NS_MAIN, 'Test' ), new TitleValue( NS_TALK, 'Test' ) ],
734 [ new TitleValue( NS_TALK, 'Test' ), new TitleValue( NS_TALK, 'Test' ) ],
735 [ new TitleValue( NS_USER, 'Test' ), new TitleValue( NS_USER_TALK, 'Test' ) ],
736 ];
737 }
738
739 /**
740 * @dataProvider provideGetTalkPage_good
741 * @covers NamespaceInfo::getTalk
742 * @covers NamespaceInfo::getTalkPage
743 * @covers NamespaceInfo::isMethodValidFor
744 */
745 public function testGetTalkPage_good( LinkTarget $t, LinkTarget $expected ) {
746 $actual = $this->newObj()->getTalkPage( $t );
747 $this->assertEquals( $expected, $actual, $t->getDBkey() );
748 }
749
750 public static function provideGetTalkPage_bad() {
751 return [
752 [ new TitleValue( NS_SPECIAL, 'Test' ) ],
753 [ new TitleValue( NS_MEDIA, 'Test' ) ],
754 [ new TitleValue( NS_MAIN, '', 'Kittens' ) ],
755 [ new TitleValue( NS_MAIN, 'Kittens', '', 'acme' ) ],
756 ];
757 }
758
759 /**
760 * @dataProvider provideGetTalkPage_bad
761 * @covers NamespaceInfo::getTalk
762 * @covers NamespaceInfo::getTalkPage
763 * @covers NamespaceInfo::isMethodValidFor
764 */
765 public function testGetTalkPage_bad( LinkTarget $t ) {
766 $this->setExpectedException( MWException::class );
767 $this->newObj()->getTalkPage( $t );
768 }
769
770 /**
771 * @dataProvider provideGetTalkPage_bad
772 * @covers NamespaceInfo::getAssociated
773 * @covers NamespaceInfo::getAssociatedPage
774 * @covers NamespaceInfo::isMethodValidFor
775 */
776 public function testGetAssociatedPage_bad( LinkTarget $t ) {
777 $this->setExpectedException( MWException::class );
778 $this->newObj()->getAssociatedPage( $t );
779 }
780
781 /**
782 * @dataProvider provideSubjectTalk
783 * @covers NamespaceInfo::getAssociated
784 * @covers NamespaceInfo::getAssociatedPage
785 * @covers Title::getOtherPage
786 *
787 * @param int $subject
788 * @param int $talk
789 */
790 public function testGetAssociated( $subject, $talk ) {
791 $obj = $this->newObj();
792 $this->assertSame( $talk, $obj->getAssociated( $subject ) );
793 $this->assertSame( $subject, $obj->getAssociated( $talk ) );
794
795 $subjectTitle = new TitleValue( $subject, 'A' );
796 $talkTitle = new TitleValue( $talk, 'A' );
797 // Object will not be the same
798 $this->assertEquals( $talkTitle, $obj->getAssociatedPage( $subjectTitle ) );
799 $this->assertEquals( $subjectTitle, $obj->getAssociatedPage( $talkTitle ) );
800
801 $subjectTitle = Title::makeTitle( $subject, 'A' );
802 $talkTitle = Title::makeTitle( $talk, 'A' );
803 $this->assertEquals( $talkTitle, $subjectTitle->getOtherPage() );
804 $this->assertEquals( $subjectTitle, $talkTitle->getOtherPage() );
805 }
806
807 public static function provideSubjectTalk() {
808 return [
809 // Format: [ subject, talk ]
810 'Main/talk' => [ NS_MAIN, NS_TALK ],
811 'User/user talk' => [ NS_USER, NS_USER_TALK ],
812 'Unknown namespaces also supported' => [ 106, 107 ],
813 ];
814 }
815
816 public static function provideSpecialNamespaces() {
817 return [
818 'Special' => [ NS_SPECIAL ],
819 'Media' => [ NS_MEDIA ],
820 'Unknown negative index' => [ -613 ],
821 ];
822 }
823
824 // %} End getSubject/Talk/Associated
825
826 /**********************************************************************************************
827 * Canonical namespaces
828 * %{
829 */
830
831 // Default canonical namespaces
832 // %{
833 private function getDefaultNamespaces() {
834 return [ NS_MAIN => '' ] + self::$defaultOptions['CanonicalNamespaceNames'];
835 }
836
837 /**
838 * @covers NamespaceInfo::getCanonicalNamespaces
839 */
840 public function testGetCanonicalNamespaces() {
841 $this->assertSame(
842 $this->getDefaultNamespaces(),
843 $this->newObj()->getCanonicalNamespaces()
844 );
845 }
846
847 /**
848 * @dataProvider provideGetCanonicalName
849 * @covers NamespaceInfo::getCanonicalName
850 *
851 * @param int $index
852 * @param string|bool $expected
853 */
854 public function testGetCanonicalName( $index, $expected ) {
855 $this->assertSame( $expected, $this->newObj()->getCanonicalName( $index ) );
856 }
857
858 public function provideGetCanonicalName() {
859 return [
860 'Main' => [ NS_MAIN, '' ],
861 'Talk' => [ NS_TALK, 'Talk' ],
862 'With underscore not space' => [ NS_USER_TALK, 'User_talk' ],
863 'Special' => [ NS_SPECIAL, 'Special' ],
864 'Nonexistent' => [ 12345, false ],
865 'Nonexistent negative' => [ -12345, false ],
866 ];
867 }
868
869 /**
870 * @dataProvider provideGetCanonicalIndex
871 * @covers NamespaceInfo::getCanonicalIndex
872 *
873 * @param string $name
874 * @param int|null $expected
875 */
876 public function testGetCanonicalIndex( $name, $expected ) {
877 $this->assertSame( $expected, $this->newObj()->getCanonicalIndex( $name ) );
878 }
879
880 public function provideGetCanonicalIndex() {
881 return [
882 'Main' => [ '', NS_MAIN ],
883 'Talk' => [ 'talk', NS_TALK ],
884 'Not lowercase' => [ 'Talk', null ],
885 'With underscore' => [ 'user_talk', NS_USER_TALK ],
886 'Space is not recognized for underscore' => [ 'user talk', null ],
887 '0' => [ '0', null ],
888 ];
889 }
890
891 /**
892 * @covers NamespaceInfo::getValidNamespaces
893 */
894 public function testGetValidNamespaces() {
895 $this->assertSame(
896 [ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK ],
897 $this->newObj()->getValidNamespaces()
898 );
899 }
900
901 // %} End default canonical namespaces
902
903 // No canonical namespace names
904 // %{
905
906 /**
907 * @covers NamespaceInfo::getCanonicalNamespaces
908 */
909 public function testGetCanonicalNamespaces_NoCanonicalNamespaceNames() {
910 $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
911
912 $this->assertSame( [ NS_MAIN => '' ], $obj->getCanonicalNamespaces() );
913 }
914
915 /**
916 * @covers NamespaceInfo::getCanonicalName
917 */
918 public function testGetCanonicalName_NoCanonicalNamespaceNames() {
919 $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
920
921 $this->assertSame( '', $obj->getCanonicalName( NS_MAIN ) );
922 $this->assertFalse( $obj->getCanonicalName( NS_TALK ) );
923 }
924
925 /**
926 * @covers NamespaceInfo::getCanonicalIndex
927 */
928 public function testGetCanonicalIndex_NoCanonicalNamespaceNames() {
929 $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
930
931 $this->assertSame( NS_MAIN, $obj->getCanonicalIndex( '' ) );
932 $this->assertNull( $obj->getCanonicalIndex( 'talk' ) );
933 }
934
935 /**
936 * @covers NamespaceInfo::getValidNamespaces
937 */
938 public function testGetValidNamespaces_NoCanonicalNamespaceNames() {
939 $obj = $this->newObj( [ 'CanonicalNamespaceNames' => [] ] );
940
941 $this->assertSame( [ NS_MAIN ], $obj->getValidNamespaces() );
942 }
943
944 // %} End no canonical namespace names
945
946 // Test extension namespaces
947 // %{
948 private function setupExtensionNamespaces() {
949 $this->scopedCallback = null;
950 $this->scopedCallback = ExtensionRegistry::getInstance()->setAttributeForTest(
951 'ExtensionNamespaces',
952 [ NS_MAIN => 'No effect', NS_TALK => 'No effect', 12345 => 'Extended' ]
953 );
954 }
955
956 /**
957 * @covers NamespaceInfo::getCanonicalNamespaces
958 */
959 public function testGetCanonicalNamespaces_ExtensionNamespaces() {
960 $this->setupExtensionNamespaces();
961
962 $this->assertSame(
963 $this->getDefaultNamespaces() + [ 12345 => 'Extended' ],
964 $this->newObj()->getCanonicalNamespaces()
965 );
966 }
967
968 /**
969 * @covers NamespaceInfo::getCanonicalName
970 */
971 public function testGetCanonicalName_ExtensionNamespaces() {
972 $this->setupExtensionNamespaces();
973 $obj = $this->newObj();
974
975 $this->assertSame( '', $obj->getCanonicalName( NS_MAIN ) );
976 $this->assertSame( 'Talk', $obj->getCanonicalName( NS_TALK ) );
977 $this->assertSame( 'Extended', $obj->getCanonicalName( 12345 ) );
978 }
979
980 /**
981 * @covers NamespaceInfo::getCanonicalIndex
982 */
983 public function testGetCanonicalIndex_ExtensionNamespaces() {
984 $this->setupExtensionNamespaces();
985 $obj = $this->newObj();
986
987 $this->assertSame( NS_MAIN, $obj->getCanonicalIndex( '' ) );
988 $this->assertSame( NS_TALK, $obj->getCanonicalIndex( 'talk' ) );
989 $this->assertSame( 12345, $obj->getCanonicalIndex( 'extended' ) );
990 }
991
992 /**
993 * @covers NamespaceInfo::getValidNamespaces
994 */
995 public function testGetValidNamespaces_ExtensionNamespaces() {
996 $this->setupExtensionNamespaces();
997
998 $this->assertSame(
999 [ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK, 12345 ],
1000 $this->newObj()->getValidNamespaces()
1001 );
1002 }
1003
1004 // %} End extension namespaces
1005
1006 // Hook namespaces
1007 // %{
1008
1009 /**
1010 * @return array Expected canonical namespaces
1011 */
1012 private function setupHookNamespaces() {
1013 $callback =
1014 function ( &$canonicalNamespaces ) {
1015 $canonicalNamespaces[NS_MAIN] = 'Main';
1016 unset( $canonicalNamespaces[NS_MEDIA] );
1017 $canonicalNamespaces[123456] = 'Hooked';
1018 };
1019 $this->setTemporaryHook( 'CanonicalNamespaces', $callback );
1020 $expected = $this->getDefaultNamespaces();
1021 ( $callback )( $expected );
1022 return $expected;
1023 }
1024
1025 /**
1026 * @covers NamespaceInfo::getCanonicalNamespaces
1027 */
1028 public function testGetCanonicalNamespaces_HookNamespaces() {
1029 $expected = $this->setupHookNamespaces();
1030
1031 $this->assertSame( $expected, $this->newObj()->getCanonicalNamespaces() );
1032 }
1033
1034 /**
1035 * @covers NamespaceInfo::getCanonicalName
1036 */
1037 public function testGetCanonicalName_HookNamespaces() {
1038 $this->setupHookNamespaces();
1039 $obj = $this->newObj();
1040
1041 $this->assertSame( 'Main', $obj->getCanonicalName( NS_MAIN ) );
1042 $this->assertFalse( $obj->getCanonicalName( NS_MEDIA ) );
1043 $this->assertSame( 'Hooked', $obj->getCanonicalName( 123456 ) );
1044 }
1045
1046 /**
1047 * @covers NamespaceInfo::getCanonicalIndex
1048 */
1049 public function testGetCanonicalIndex_HookNamespaces() {
1050 $this->setupHookNamespaces();
1051 $obj = $this->newObj();
1052
1053 $this->assertSame( NS_MAIN, $obj->getCanonicalIndex( 'main' ) );
1054 $this->assertNull( $obj->getCanonicalIndex( 'media' ) );
1055 $this->assertSame( 123456, $obj->getCanonicalIndex( 'hooked' ) );
1056 }
1057
1058 /**
1059 * @covers NamespaceInfo::getValidNamespaces
1060 */
1061 public function testGetValidNamespaces_HookNamespaces() {
1062 $this->setupHookNamespaces();
1063
1064 $this->assertSame(
1065 [ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK, 123456 ],
1066 $this->newObj()->getValidNamespaces()
1067 );
1068 }
1069
1070 // %} End hook namespaces
1071
1072 // Extra namespaces
1073 // %{
1074
1075 /**
1076 * @return NamespaceInfo
1077 */
1078 private function setupExtraNamespaces() {
1079 return $this->newObj( [ 'ExtraNamespaces' =>
1080 [ NS_MAIN => 'No effect', NS_TALK => 'No effect', 1234567 => 'Extra' ]
1081 ] );
1082 }
1083
1084 /**
1085 * @covers NamespaceInfo::getCanonicalNamespaces
1086 */
1087 public function testGetCanonicalNamespaces_ExtraNamespaces() {
1088 $this->assertSame(
1089 $this->getDefaultNamespaces() + [ 1234567 => 'Extra' ],
1090 $this->setupExtraNamespaces()->getCanonicalNamespaces()
1091 );
1092 }
1093
1094 /**
1095 * @covers NamespaceInfo::getCanonicalName
1096 */
1097 public function testGetCanonicalName_ExtraNamespaces() {
1098 $obj = $this->setupExtraNamespaces();
1099
1100 $this->assertSame( '', $obj->getCanonicalName( NS_MAIN ) );
1101 $this->assertSame( 'Talk', $obj->getCanonicalName( NS_TALK ) );
1102 $this->assertSame( 'Extra', $obj->getCanonicalName( 1234567 ) );
1103 }
1104
1105 /**
1106 * @covers NamespaceInfo::getCanonicalIndex
1107 */
1108 public function testGetCanonicalIndex_ExtraNamespaces() {
1109 $obj = $this->setupExtraNamespaces();
1110
1111 $this->assertNull( $obj->getCanonicalIndex( 'no effect' ) );
1112 $this->assertNull( $obj->getCanonicalIndex( 'no_effect' ) );
1113 $this->assertSame( 1234567, $obj->getCanonicalIndex( 'extra' ) );
1114 }
1115
1116 /**
1117 * @covers NamespaceInfo::getValidNamespaces
1118 */
1119 public function testGetValidNamespaces_ExtraNamespaces() {
1120 $this->assertSame(
1121 [ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK, 1234567 ],
1122 $this->setupExtraNamespaces()->getValidNamespaces()
1123 );
1124 }
1125
1126 // %} End extra namespaces
1127
1128 // Canonical namespace caching
1129 // %{
1130
1131 /**
1132 * @covers NamespaceInfo::getCanonicalNamespaces
1133 */
1134 public function testGetCanonicalNamespaces_caching() {
1135 $obj = $this->newObj();
1136
1137 // This should cache the values
1138 $obj->getCanonicalNamespaces();
1139
1140 // Now try to alter them through nefarious means
1141 $this->setupExtensionNamespaces();
1142 $this->setupHookNamespaces();
1143
1144 // Should have no effect
1145 $this->assertSame( $this->getDefaultNamespaces(), $obj->getCanonicalNamespaces() );
1146 }
1147
1148 /**
1149 * @covers NamespaceInfo::getCanonicalName
1150 */
1151 public function testGetCanonicalName_caching() {
1152 $obj = $this->newObj();
1153
1154 // This should cache the values
1155 $obj->getCanonicalName( NS_MAIN );
1156
1157 // Now try to alter them through nefarious means
1158 $this->setupExtensionNamespaces();
1159 $this->setupHookNamespaces();
1160
1161 // Should have no effect
1162 $this->assertSame( '', $obj->getCanonicalName( NS_MAIN ) );
1163 $this->assertSame( 'Media', $obj->getCanonicalName( NS_MEDIA ) );
1164 $this->assertFalse( $obj->getCanonicalName( 12345 ) );
1165 $this->assertFalse( $obj->getCanonicalName( 123456 ) );
1166 }
1167
1168 /**
1169 * @covers NamespaceInfo::getCanonicalIndex
1170 */
1171 public function testGetCanonicalIndex_caching() {
1172 $obj = $this->newObj();
1173
1174 // This should cache the values
1175 $obj->getCanonicalIndex( '' );
1176
1177 // Now try to alter them through nefarious means
1178 $this->setupExtensionNamespaces();
1179 $this->setupHookNamespaces();
1180
1181 // Should have no effect
1182 $this->assertSame( NS_MAIN, $obj->getCanonicalIndex( '' ) );
1183 $this->assertSame( NS_MEDIA, $obj->getCanonicalIndex( 'media' ) );
1184 $this->assertNull( $obj->getCanonicalIndex( 'extended' ) );
1185 $this->assertNull( $obj->getCanonicalIndex( 'hooked' ) );
1186 }
1187
1188 /**
1189 * @covers NamespaceInfo::getValidNamespaces
1190 */
1191 public function testGetValidNamespaces_caching() {
1192 $obj = $this->newObj();
1193
1194 // This should cache the values
1195 $obj->getValidNamespaces();
1196
1197 // Now try to alter through nefarious means
1198 $this->setupExtensionNamespaces();
1199 $this->setupHookNamespaces();
1200
1201 // Should have no effect
1202 $this->assertSame(
1203 [ NS_MAIN, NS_TALK, NS_USER, NS_USER_TALK ],
1204 $obj->getValidNamespaces()
1205 );
1206 }
1207
1208 // %} End canonical namespace caching
1209
1210 // Miscellaneous
1211 // %{
1212
1213 /**
1214 * @dataProvider provideGetValidNamespaces_misc
1215 * @covers NamespaceInfo::getValidNamespaces
1216 *
1217 * @param array $namespaces List of namespace indices to return from getCanonicalNamespaces()
1218 * (list is overwritten by a hook, so NS_MAIN doesn't have to be present)
1219 * @param array $expected
1220 */
1221 public function testGetValidNamespaces_misc( array $namespaces, array $expected ) {
1222 // Each namespace's name is just its index
1223 $this->setTemporaryHook( 'CanonicalNamespaces',
1224 function ( &$canonicalNamespaces ) use ( $namespaces ) {
1225 $canonicalNamespaces = array_combine( $namespaces, $namespaces );
1226 }
1227 );
1228 $this->assertSame( $expected, $this->newObj()->getValidNamespaces() );
1229 }
1230
1231 public function provideGetValidNamespaces_misc() {
1232 return [
1233 'Out of order (T109137)' => [ [ 1, 0 ], [ 0, 1 ] ],
1234 'Alphabetical order' => [ [ 10, 2 ], [ 2, 10 ] ],
1235 'Negative' => [ [ -1000, -500, -2, 0 ], [ 0 ] ],
1236 ];
1237 }
1238
1239 // %} End miscellaneous
1240 // %} End canonical namespaces
1241
1242 /**********************************************************************************************
1243 * Restriction levels
1244 * %{
1245 */
1246
1247 /**
1248 * This mock user can only have isAllowed() called on it.
1249 *
1250 * @param array $groups Groups for the mock user to have
1251 * @return User
1252 */
1253 private function getMockUser( array $groups = [] ) : User {
1254 $groups[] = '*';
1255
1256 $mock = $this->createMock( User::class );
1257 $mock->method( 'isAllowed' )->will( $this->returnCallback(
1258 function ( $action ) use ( $groups ) {
1259 global $wgGroupPermissions, $wgRevokePermissions;
1260 if ( $action == '' ) {
1261 return true;
1262 }
1263 foreach ( $wgRevokePermissions as $group => $rights ) {
1264 if ( !in_array( $group, $groups ) ) {
1265 continue;
1266 }
1267 if ( isset( $rights[$action] ) && $rights[$action] ) {
1268 return false;
1269 }
1270 }
1271 foreach ( $wgGroupPermissions as $group => $rights ) {
1272 if ( !in_array( $group, $groups ) ) {
1273 continue;
1274 }
1275 if ( isset( $rights[$action] ) && $rights[$action] ) {
1276 return true;
1277 }
1278 }
1279 return false;
1280 }
1281 ) );
1282 $mock->expects( $this->never() )->method( $this->anythingBut( 'isAllowed' ) );
1283 return $mock;
1284 }
1285
1286 /**
1287 * @dataProvider provideGetRestrictionLevels
1288 * @covers NamespaceInfo::getRestrictionLevels
1289 *
1290 * @param array $expected
1291 * @param int $ns
1292 * @param User|null $user
1293 */
1294 public function testGetRestrictionLevels( array $expected, $ns, User $user = null ) {
1295 $this->setMwGlobals( [
1296 'wgGroupPermissions' => [
1297 '*' => [ 'edit' => true ],
1298 'autoconfirmed' => [ 'editsemiprotected' => true ],
1299 'sysop' => [
1300 'editsemiprotected' => true,
1301 'editprotected' => true,
1302 ],
1303 'privileged' => [ 'privileged' => true ],
1304 ],
1305 'wgRevokePermissions' => [
1306 'noeditsemiprotected' => [ 'editsemiprotected' => true ],
1307 ],
1308 ] );
1309 $obj = $this->newObj( [
1310 'NamespaceProtection' => [
1311 NS_MAIN => 'autoconfirmed',
1312 NS_USER => 'sysop',
1313 101 => [ 'editsemiprotected', 'privileged' ],
1314 ],
1315 ] );
1316 $this->assertSame( $expected, $obj->getRestrictionLevels( $ns, $user ) );
1317 }
1318
1319 public function provideGetRestrictionLevels() {
1320 return [
1321 'No namespace restriction' => [ [ '', 'autoconfirmed', 'sysop' ], NS_TALK ],
1322 'Restricted to autoconfirmed' => [ [ '', 'sysop' ], NS_MAIN ],
1323 'Restricted to sysop' => [ [ '' ], NS_USER ],
1324 'Restricted to someone in two groups' => [ [ '', 'sysop' ], 101 ],
1325 'No special permissions' => [ [ '' ], NS_TALK, $this->getMockUser() ],
1326 'autoconfirmed' => [
1327 [ '', 'autoconfirmed' ],
1328 NS_TALK,
1329 $this->getMockUser( [ 'autoconfirmed' ] )
1330 ],
1331 'autoconfirmed revoked' => [
1332 [ '' ],
1333 NS_TALK,
1334 $this->getMockUser( [ 'autoconfirmed', 'noeditsemiprotected' ] )
1335 ],
1336 'sysop' => [
1337 [ '', 'autoconfirmed', 'sysop' ],
1338 NS_TALK,
1339 $this->getMockUser( [ 'sysop' ] )
1340 ],
1341 'sysop with autoconfirmed revoked (a bit silly)' => [
1342 [ '', 'sysop' ],
1343 NS_TALK,
1344 $this->getMockUser( [ 'sysop', 'noeditsemiprotected' ] )
1345 ],
1346 ];
1347 }
1348
1349 // %} End restriction levels
1350
1351 /**
1352 * @coversNothing
1353 */
1354 public function testAllServiceOptionsUsed() {
1355 $this->assertAllServiceOptionsUsed();
1356 }
1357 }
1358
1359 /**
1360 * For really cool vim folding this needs to be at the end:
1361 * vim: foldmarker=%{,%} foldmethod=marker
1362 */