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