3 use MediaWiki\Block\DatabaseBlock
;
4 use MediaWiki\Block\Restriction\PageRestriction
;
12 * @license GPL-2.0-or-later
13 * @author Thiemo Kreuz
15 class ActionTest
extends MediaWikiTestCase
{
17 protected function setUp() {
20 $context = $this->getContext();
21 $this->setMwGlobals( 'wgActions', [
26 'revisiondelete' => SpecialPageAction
::class,
28 'access' => 'ControlledAccessDummyAction',
29 'unblock' => 'RequiresUnblockDummyAction',
30 'string' => 'NamedDummyAction',
31 'declared' => 'NonExistingClassName',
32 'callable' => [ $this, 'dummyActionCallback' ],
33 'object' => new InstantiatedDummyAction( $context->getWikiPage(), $context ),
37 private function getPage() {
38 return WikiPage
::factory( Title
::makeTitle( 0, 'Title' ) );
41 private function getContext( $requestedAction = null ) {
42 $request = new FauxRequest( [ 'action' => $requestedAction ] );
44 $context = new DerivativeContext( RequestContext
::getMain() );
45 $context->setRequest( $request );
46 $context->setWikiPage( $this->getPage() );
51 public function actionProvider() {
53 [ 'dummy', 'DummyAction' ],
54 [ 'string', 'NamedDummyAction' ],
55 [ 'callable', 'CalledDummyAction' ],
56 [ 'object', 'InstantiatedDummyAction' ],
58 // Capitalization is ignored
59 [ 'DUMMY', 'DummyAction' ],
60 [ 'STRING', 'NamedDummyAction' ],
62 // Null and non-existing values
64 [ 'undeclared', null ],
71 * @dataProvider actionProvider
72 * @param string $requestedAction
73 * @param string|null $expected
75 public function testActionExists( $requestedAction, $expected ) {
76 $exists = Action
::exists( $requestedAction );
78 $this->assertSame( $expected !== null, $exists );
81 public function testActionExists_doesNotRequireInstantiation() {
82 // The method is not supposed to check if the action can be instantiated.
83 $exists = Action
::exists( 'declared' );
85 $this->assertTrue( $exists );
89 * @dataProvider actionProvider
90 * @param string $requestedAction
91 * @param string|null $expected
93 public function testGetActionName( $requestedAction, $expected ) {
94 $context = $this->getContext( $requestedAction );
95 $actionName = Action
::getActionName( $context );
97 $this->assertEquals( $expected ?
: 'nosuchaction', $actionName );
100 public function testGetActionName_editredlinkWorkaround() {
101 // See https://phabricator.wikimedia.org/T22966
102 $context = $this->getContext( 'editredlink' );
103 $actionName = Action
::getActionName( $context );
105 $this->assertEquals( 'edit', $actionName );
108 public function testGetActionName_historysubmitWorkaround() {
109 // See https://phabricator.wikimedia.org/T22966
110 $context = $this->getContext( 'historysubmit' );
111 $actionName = Action
::getActionName( $context );
113 $this->assertEquals( 'view', $actionName );
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 );
122 $this->assertEquals( 'revisiondelete', $actionName );
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 );
131 $this->assertEquals( 'view', $actionName );
135 * @dataProvider actionProvider
136 * @param string $requestedAction
137 * @param string|null $expected
139 public function testActionFactory( $requestedAction, $expected ) {
140 $context = $this->getContext();
141 $action = Action
::factory( $requestedAction, $context->getWikiPage(), $context );
143 $this->assertType( $expected ?
: 'null', $action );
146 public function testNull_doesNotExist() {
147 $exists = Action
::exists( null );
149 $this->assertFalse( $exists );
152 public function testNull_defaultsToView() {
153 $context = $this->getContext( null );
154 $actionName = Action
::getActionName( $context );
156 $this->assertEquals( 'view', $actionName );
159 public function testNull_canNotBeInstantiated() {
160 $page = $this->getPage();
161 $action = Action
::factory( null, $page );
163 $this->assertNull( $action );
166 public function testDisabledAction_exists() {
167 $exists = Action
::exists( 'disabled' );
169 $this->assertTrue( $exists );
172 public function testDisabledAction_isNotResolved() {
173 $context = $this->getContext( 'disabled' );
174 $actionName = Action
::getActionName( $context );
176 $this->assertEquals( 'nosuchaction', $actionName );
179 public function testDisabledAction_factoryReturnsFalse() {
180 $page = $this->getPage();
181 $action = Action
::factory( 'disabled', $page );
183 $this->assertFalse( $action );
186 public function dummyActionCallback() {
187 $context = $this->getContext();
188 return new CalledDummyAction( $context->getWikiPage(), $context );
191 public function testCanExecute() {
192 $user = $this->getTestUser()->getUser();
193 $user->mRights
= [ 'access' ];
194 $action = Action
::factory( 'access', $this->getPage(), $this->getContext() );
195 $this->assertNull( $action->canExecute( $user ) );
198 public function testCanExecuteNoRight() {
199 $user = $this->getTestUser()->getUser();
201 $action = Action
::factory( 'access', $this->getPage(), $this->getContext() );
204 $action->canExecute( $user );
205 } catch ( Exception
$e ) {
206 $this->assertInstanceOf( PermissionsError
::class, $e );
210 public function testCanExecuteRequiresUnblock() {
211 $user = $this->getTestUser()->getUser();
214 $page = $this->getExistingTestPage();
215 $action = Action
::factory( 'unblock', $page, $this->getContext() );
217 $block = new DatabaseBlock( [
219 'by' => $this->getTestSysop()->getUser()->getId(),
220 'expiry' => 'infinity',
223 $block->setRestrictions( [
224 new PageRestriction( 0, $page->getTitle()->getArticleID() ),
230 $action->canExecute( $user );
231 } catch ( Exception
$e ) {
232 $this->assertInstanceOf( UserBlockedError
::class, $e );
240 class DummyAction
extends Action
{
242 public function getName() {
243 return static::class;
246 public function show() {
249 public function execute() {
252 public function canExecute( User
$user ) {
253 return $this->checkCanExecute( $user );
257 class NamedDummyAction
extends DummyAction
{
260 class CalledDummyAction
extends DummyAction
{
263 class InstantiatedDummyAction
extends DummyAction
{
266 class ControlledAccessDummyAction
extends DummyAction
{
267 public function getRestriction() {
272 class RequiresUnblockDummyAction
extends DummyAction
{
273 public function requiresUnblock() {