Merge "maintenance: Script to rename titles for Unicode uppercasing changes"
[lhc/web/wiklou.git] / tests / phpunit / includes / actions / ActionTest.php
1 <?php
2
3 use MediaWiki\Block\DatabaseBlock;
4 use MediaWiki\Block\Restriction\PageRestriction;
5
6 /**
7 * @covers Action
8 *
9 * @group Action
10 * @group Database
11 *
12 * @license GPL-2.0-or-later
13 * @author Thiemo Kreuz
14 */
15 class ActionTest extends MediaWikiTestCase {
16
17 protected function setUp() {
18 parent::setUp();
19
20 $context = $this->getContext();
21 $this->setMwGlobals( 'wgActions', [
22 'null' => null,
23 'disabled' => false,
24 'view' => true,
25 'edit' => true,
26 'revisiondelete' => SpecialPageAction::class,
27 'dummy' => true,
28 'access' => 'ControlledAccessDummyAction',
29 'unblock' => 'RequiresUnblockDummyAction',
30 'string' => 'NamedDummyAction',
31 'declared' => 'NonExistingClassName',
32 'callable' => [ $this, 'dummyActionCallback' ],
33 'object' => new InstantiatedDummyAction( $context->getWikiPage(), $context ),
34 ] );
35 }
36
37 private function getPage() {
38 return WikiPage::factory( Title::makeTitle( 0, 'Title' ) );
39 }
40
41 private function getContext( $requestedAction = null ) {
42 $request = new FauxRequest( [ 'action' => $requestedAction ] );
43
44 $context = new DerivativeContext( RequestContext::getMain() );
45 $context->setRequest( $request );
46 $context->setWikiPage( $this->getPage() );
47
48 return $context;
49 }
50
51 public function actionProvider() {
52 return [
53 [ 'dummy', 'DummyAction' ],
54 [ 'string', 'NamedDummyAction' ],
55 [ 'callable', 'CalledDummyAction' ],
56 [ 'object', 'InstantiatedDummyAction' ],
57
58 // Capitalization is ignored
59 [ 'DUMMY', 'DummyAction' ],
60 [ 'STRING', 'NamedDummyAction' ],
61
62 // Null and non-existing values
63 [ 'null', null ],
64 [ 'undeclared', null ],
65 [ '', null ],
66 [ false, null ],
67 ];
68 }
69
70 /**
71 * @dataProvider actionProvider
72 * @param string $requestedAction
73 * @param string|null $expected
74 */
75 public function testActionExists( $requestedAction, $expected ) {
76 $exists = Action::exists( $requestedAction );
77
78 $this->assertSame( $expected !== null, $exists );
79 }
80
81 public function testActionExists_doesNotRequireInstantiation() {
82 // The method is not supposed to check if the action can be instantiated.
83 $exists = Action::exists( 'declared' );
84
85 $this->assertTrue( $exists );
86 }
87
88 /**
89 * @dataProvider actionProvider
90 * @param string $requestedAction
91 * @param string|null $expected
92 */
93 public function testGetActionName( $requestedAction, $expected ) {
94 $context = $this->getContext( $requestedAction );
95 $actionName = Action::getActionName( $context );
96
97 $this->assertEquals( $expected ?: 'nosuchaction', $actionName );
98 }
99
100 public function testGetActionName_editredlinkWorkaround() {
101 // See https://phabricator.wikimedia.org/T22966
102 $context = $this->getContext( 'editredlink' );
103 $actionName = Action::getActionName( $context );
104
105 $this->assertEquals( 'edit', $actionName );
106 }
107
108 public function testGetActionName_historysubmitWorkaround() {
109 // See https://phabricator.wikimedia.org/T22966
110 $context = $this->getContext( 'historysubmit' );
111 $actionName = Action::getActionName( $context );
112
113 $this->assertEquals( 'view', $actionName );
114 }
115
116 public function testGetActionName_revisiondeleteWorkaround() {
117 // See https://phabricator.wikimedia.org/T22966
118 $context = $this->getContext( 'historysubmit' );
119 $context->getRequest()->setVal( 'revisiondelete', true );
120 $actionName = Action::getActionName( $context );
121
122 $this->assertEquals( 'revisiondelete', $actionName );
123 }
124
125 public function testGetActionName_whenCanNotUseWikiPage_defaultsToView() {
126 $request = new FauxRequest( [ 'action' => 'edit' ] );
127 $context = new DerivativeContext( RequestContext::getMain() );
128 $context->setRequest( $request );
129 $actionName = Action::getActionName( $context );
130
131 $this->assertEquals( 'view', $actionName );
132 }
133
134 /**
135 * @dataProvider actionProvider
136 * @param string $requestedAction
137 * @param string|null $expected
138 */
139 public function testActionFactory( $requestedAction, $expected ) {
140 $context = $this->getContext();
141 $action = Action::factory( $requestedAction, $context->getWikiPage(), $context );
142
143 $this->assertType( $expected ?: 'null', $action );
144 }
145
146 public function testNull_doesNotExist() {
147 $exists = Action::exists( null );
148
149 $this->assertFalse( $exists );
150 }
151
152 public function testNull_defaultsToView() {
153 $context = $this->getContext( null );
154 $actionName = Action::getActionName( $context );
155
156 $this->assertEquals( 'view', $actionName );
157 }
158
159 public function testNull_canNotBeInstantiated() {
160 $page = $this->getPage();
161 $action = Action::factory( null, $page );
162
163 $this->assertNull( $action );
164 }
165
166 public function testDisabledAction_exists() {
167 $exists = Action::exists( 'disabled' );
168
169 $this->assertTrue( $exists );
170 }
171
172 public function testDisabledAction_isNotResolved() {
173 $context = $this->getContext( 'disabled' );
174 $actionName = Action::getActionName( $context );
175
176 $this->assertEquals( 'nosuchaction', $actionName );
177 }
178
179 public function testDisabledAction_factoryReturnsFalse() {
180 $page = $this->getPage();
181 $action = Action::factory( 'disabled', $page );
182
183 $this->assertFalse( $action );
184 }
185
186 public function dummyActionCallback() {
187 $context = $this->getContext();
188 return new CalledDummyAction( $context->getWikiPage(), $context );
189 }
190
191 public function testCanExecute() {
192 $user = $this->getTestUser()->getUser();
193 $this->overrideUserPermissions( $user, 'access' );
194 $action = Action::factory( 'access', $this->getPage(), $this->getContext() );
195 $this->assertNull( $action->canExecute( $user ) );
196 }
197
198 public function testCanExecuteNoRight() {
199 $user = $this->getTestUser()->getUser();
200 $this->overrideUserPermissions( $user, [] );
201 $action = Action::factory( 'access', $this->getPage(), $this->getContext() );
202
203 try {
204 $action->canExecute( $user );
205 } catch ( Exception $e ) {
206 $this->assertInstanceOf( PermissionsError::class, $e );
207 }
208 }
209
210 public function testCanExecuteRequiresUnblock() {
211 $user = $this->getTestUser()->getUser();
212 $this->overrideUserPermissions( $user, [] );
213
214 $page = $this->getExistingTestPage();
215 $action = Action::factory( 'unblock', $page, $this->getContext() );
216
217 $block = new DatabaseBlock( [
218 'address' => $user,
219 'by' => $this->getTestSysop()->getUser()->getId(),
220 'expiry' => 'infinity',
221 'sitewide' => false,
222 ] );
223 $block->setRestrictions( [
224 new PageRestriction( 0, $page->getTitle()->getArticleID() ),
225 ] );
226
227 $block->insert();
228
229 try {
230 $action->canExecute( $user );
231 } catch ( Exception $e ) {
232 $this->assertInstanceOf( UserBlockedError::class, $e );
233 }
234
235 $block->delete();
236 }
237
238 }
239
240 class DummyAction extends Action {
241
242 public function getName() {
243 return static::class;
244 }
245
246 public function show() {
247 }
248
249 public function execute() {
250 }
251
252 public function canExecute( User $user ) {
253 return $this->checkCanExecute( $user );
254 }
255 }
256
257 class NamedDummyAction extends DummyAction {
258 }
259
260 class CalledDummyAction extends DummyAction {
261 }
262
263 class InstantiatedDummyAction extends DummyAction {
264 }
265
266 class ControlledAccessDummyAction extends DummyAction {
267 public function getRestriction() {
268 return 'access';
269 }
270 }
271
272 class RequiresUnblockDummyAction extends DummyAction {
273 public function requiresUnblock() {
274 return true;
275 }
276 }