Localisation updates from https://translatewiki.net.
[mediawiki.git] / tests / phpunit / includes / actions / ActionTest.php
blobd6a7008b95537e3cc1122dc5c0c2b657676a5f2e
1 <?php
3 use MediaWiki\Block\DatabaseBlock;
4 use MediaWiki\Context\DerivativeContext;
5 use MediaWiki\Context\IContextSource;
6 use MediaWiki\Context\RequestContext;
7 use MediaWiki\DAO\WikiAwareEntity;
8 use MediaWiki\MainConfigNames;
9 use MediaWiki\Permissions\PermissionManager;
10 use MediaWiki\Request\FauxRequest;
11 use MediaWiki\Title\Title;
12 use MediaWiki\User\User;
14 /**
15 * @covers \Action
17 * @group Action
18 * @group Database
20 * @license GPL-2.0-or-later
21 * @author Thiemo Kreuz
23 class ActionTest extends MediaWikiIntegrationTestCase {
25 protected function setUp(): void {
26 parent::setUp();
28 $context = $this->getContext();
29 $this->overrideConfigValue(
30 MainConfigNames::Actions,
32 'null' => null,
33 'disabled' => false,
34 'view' => true,
35 'edit' => true,
36 'dummy' => true,
37 'access' => 'ControlledAccessDummyAction',
38 'unblock' => 'RequiresUnblockDummyAction',
39 'string' => 'NamedDummyAction',
40 'declared' => 'NonExistingClassName',
41 'callable' => [ $this, 'dummyActionCallback' ],
42 'object' => new InstantiatedDummyAction(
43 $this->getArticle(),
44 $context
50 /**
51 * @param string $requestedAction
52 * @param WikiPage|null $wikiPage
53 * @return Action|bool|null
55 private function getAction(
56 string $requestedAction,
57 ?WikiPage $wikiPage = null
58 ) {
59 $context = $this->getContext( $requestedAction );
61 return Action::factory(
62 $requestedAction,
63 $this->getArticle( $wikiPage, $context ),
64 $context
68 /**
69 * @param WikiPage|null $wikiPage
70 * @param IContextSource|null $context
71 * @return Article
73 private function getArticle(
74 ?WikiPage $wikiPage = null,
75 ?IContextSource $context = null
76 ): Article {
77 $context ??= $this->getContext();
78 if ( $wikiPage !== null ) {
79 $context->setWikiPage( $wikiPage );
80 $context->setTitle( $wikiPage->getTitle() );
81 } else {
82 $wikiPage = $this->getPage();
85 return Article::newFromWikiPage( $wikiPage, $context );
88 private function getPage(): WikiPage {
89 $title = Title::makeTitle( 0, 'Title' );
90 return $this->getServiceContainer()->getWikiPageFactory()->newFromTitle( $title );
93 /**
94 * @param string|null $requestedAction
95 * @return IContextSource
97 private function getContext(
98 ?string $requestedAction = null
99 ): IContextSource {
100 $request = new FauxRequest( [ 'action' => $requestedAction ] );
102 $context = new DerivativeContext( RequestContext::getMain() );
103 $context->setRequest( $request );
104 $context->setWikiPage( $this->getPage() );
106 return $context;
109 public static function provideActions() {
110 return [
111 [ 'dummy', 'DummyAction' ],
112 [ 'string', 'NamedDummyAction' ],
113 [ 'callable', 'CalledDummyAction' ],
114 [ 'object', 'InstantiatedDummyAction' ],
116 // Capitalization is ignored
117 [ 'DUMMY', 'DummyAction' ],
118 [ 'STRING', 'NamedDummyAction' ],
120 // non-existing values
121 [ 'null', null ],
122 [ 'undeclared', null ],
123 [ '', null ],
125 // disabled action exists but cannot be created
126 [ 'disabled', false ],
130 public static function provideGetActionName() {
131 return [
132 'dummy' => [ 'dummy', 'DummyAction' ],
133 'string' => [ 'string', 'NamedDummyAction' ],
134 'callable' => [ 'callable', 'CalledDummyAction' ],
135 'object' => [ 'object', 'InstantiatedDummyAction' ],
137 // Capitalization is ignored
138 'dummy (caps)' => [ 'DUMMY', 'DummyAction' ],
139 'string (caps)' => [ 'STRING', 'NamedDummyAction' ],
141 // non-existing values
142 'null (string)' => [ 'null', 'nosuchaction' ],
143 'undeclared' => [ 'undeclared', 'nosuchaction' ],
144 'empty' => [ '', 'nosuchaction' ],
146 // impossible
147 'null (value)' => [ null, 'view' ],
148 'false' => [ false, 'nosuchaction' ],
150 // Compatibility with old URLs
151 'editredlink' => [ 'editredlink', 'edit' ],
152 'historysubmit' => [ 'historysubmit', 'view' ],
154 'disabled not resolvable' => [ 'disabled', 'nosuchaction' ],
159 * @dataProvider provideGetActionName
160 * @param string $requestedAction
161 * @param string $expected
163 public function testGetActionName( $requestedAction, $expected ) {
164 $actionName = Action::getActionName(
165 $this->getContext( $requestedAction )
167 $this->assertEquals( $expected, $actionName );
170 public function testGetActionName_whenCanNotUseWikiPage_defaultsToView() {
171 $request = new FauxRequest( [ 'action' => 'edit' ] );
172 $context = new DerivativeContext( RequestContext::getMain() );
173 $context->setRequest( $request );
174 $actionName = Action::getActionName( $context );
176 $this->assertEquals( 'view', $actionName );
180 * @covers \Action::factory
182 * @dataProvider provideActions
183 * @param string $requestedAction
184 * @param string|false|null $expected
186 public function testActionFactory( string $requestedAction, $expected ) {
187 $action = $this->getAction( $requestedAction );
189 if ( is_string( $expected ) ) {
190 $this->assertInstanceOf( $expected, $action );
191 } else {
192 $this->assertSame( $expected, $action );
196 public function dummyActionCallback() {
197 $article = $this->getArticle();
198 return new CalledDummyAction(
199 $article,
200 $article->getContext()
204 public function testCanExecute() {
205 $user = $this->getTestUser()->getUser();
206 $this->overrideUserPermissions( $user, 'access' );
207 $action = $this->getAction( 'access' );
208 $this->assertNull( $action->canExecute( $user ) );
211 public function testCanExecuteNoRight() {
212 $user = $this->getTestUser()->getUser();
213 $this->overrideUserPermissions( $user, [] );
214 $action = $this->getAction( 'access' );
215 $this->expectException( PermissionsError::class );
216 $action->canExecute( $user );
219 public function testCanExecuteRequiresUnblock() {
220 $page = $this->getExistingTestPage();
221 $action = $this->getAction( 'unblock', $page );
223 $user = $this->createMock( User::class );
225 $user->method( 'getWikiId' )->willReturn( WikiAwareEntity::LOCAL );
227 $block = new DatabaseBlock( [
228 'address' => $user,
229 'by' => $this->getTestSysop()->getUser(),
230 'expiry' => 'infinity',
231 'sitewide' => false,
232 ] );
234 $user->expects( $this->once() )
235 ->method( 'getBlock' )
236 ->willReturn( $block );
238 $permissionManager = $this->createMock( PermissionManager::class );
239 $permissionManager->method( 'isBlockedFrom' )->willReturn( true );
240 $this->setService( 'PermissionManager', $permissionManager );
242 $this->expectException( UserBlockedError::class );
243 $action->canExecute( $user );
248 class DummyAction extends Action {
250 public function getName() {
251 return static::class;
254 public function show() {
257 public function execute() {
260 public function canExecute( User $user ) {
261 $this->checkCanExecute( $user );
265 class NamedDummyAction extends DummyAction {
268 class CalledDummyAction extends DummyAction {
271 class InstantiatedDummyAction extends DummyAction {
274 class ControlledAccessDummyAction extends DummyAction {
275 public function getRestriction() {
276 return 'access';
280 class RequiresUnblockDummyAction extends DummyAction {
281 public function requiresUnblock() {
282 return true;