wiki.techinc.nl/tests/phpunit/includes/api/ApiChangeContentModelTest.php
libraryupgrader 5357695270 build: Updating dependencies
composer:
* mediawiki/mediawiki-codesniffer: 36.0.0 → 37.0.0
  The following sniffs now pass and were enabled:
  * Generic.ControlStructures.InlineControlStructure
  * MediaWiki.PHPUnit.AssertCount.NotUsed

npm:
* svgo: 2.3.0 → 2.3.1
  * https://npmjs.com/advisories/1754 (CVE-2021-33587)

Change-Id: I2a9bbee2fecbf7259876d335f565ece4b3622426
2021-07-22 03:36:05 +00:00

332 lines
8.7 KiB
PHP

<?php
use MediaWiki\Tests\Unit\Permissions\MockAuthorityTrait;
/**
* Tests for editing page content model via api
*
* @group API
* @group Database
* @group medium
*
* @covers ApiChangeContentModel
* @author DannyS712
*/
class ApiChangeContentModelTest extends ApiTestCase {
use MockAuthorityTrait;
protected function setUp(): void {
parent::setUp();
$this->tablesUsed = array_merge(
$this->tablesUsed,
[ 'change_tag', 'change_tag_def', 'logging' ]
);
$this->getExistingTestPage( 'ExistingPage' );
$this->setMwGlobals( [
'wgExtraNamespaces' => [
12312 => 'Dummy',
12313 => 'Dummy_talk',
],
'wgNamespaceContentModels' => [
12312 => 'testing',
],
] );
$this->mergeMwGlobalArrayValue( 'wgContentHandlers', [
'testing' => 'DummyContentHandlerForTesting',
] );
}
public function testTitleMustExist() {
$name = __METHOD__;
$this->assertFalse(
Title::newFromText( $name )->exists(),
'Sanity check that title does not exist already'
);
$this->setExpectedApiException( 'apierror-changecontentmodel-missingtitle' );
$this->doApiRequestWithToken( [
'action' => 'changecontentmodel',
'title' => $name,
'model' => 'text'
] );
}
/**
* Test user needs `editcontentmodel` rights
*/
public function testRightsNeeded() {
$this->setExpectedApiException( [
'apierror-permissiondenied',
wfMessage( 'action-editcontentmodel' )
] );
$this->doApiRequestWithToken( [
'action' => 'changecontentmodel',
'title' => 'ExistingPage',
'model' => 'text'
],
null,
$this->mockAnonAuthorityWithoutPermissions( [ 'editcontentmodel' ] ) );
}
/**
* Test that the content model needs to change
*/
public function testChangeNeeded() {
$this->assertSame(
'wikitext',
Title::newFromText( 'ExistingPage' )->getContentModel(),
'Sanity check: `ExistingPage` should be wikitext'
);
$this->setExpectedApiException( 'apierror-nochanges' );
$this->doApiRequestWithToken( [
'action' => 'changecontentmodel',
'title' => 'ExistingPage',
'model' => 'wikitext'
] );
}
/**
* Test that the content needs to be valid for the requested model
*/
public function testInvalidContent() {
$wikipage = $this->getExistingTestPage( 'PageWithTextThatIsNotValidJSON' );
$invalidJSON = 'Foo\nBar\nEaster egg\nT22281';
$wikipage->doUserEditContent(
ContentHandler::makeContent( $invalidJSON, $wikipage->getTitle() ),
$this->getTestSysop()->getUser(),
'EditSummaryForThisTest',
EDIT_UPDATE | EDIT_SUPPRESS_RC
);
$this->assertSame(
'wikitext',
$wikipage->getTitle()->getContentModel(),
'Sanity check: `PageWithTextThatIsNotValidJSON` should be wikitext at first'
);
$this->setExpectedApiException( 'invalid-content-data' );
$this->doApiRequestWithToken( [
'action' => 'changecontentmodel',
'title' => 'PageWithTextThatIsNotValidJSON',
'model' => 'json'
],
null,
$this->mockAnonAuthorityWithPermissions( [ 'edit', 'editcontentmodel', 'writeapi' ] )
);
}
/**
* Test the EditFilterMergedContent hook can be intercepted
*
* @dataProvider provideTestEditFilterMergedContent
* @param string|bool $customMessage Hook message, or false
* @param string $expectedMessage expected fatal
*/
public function testEditFilterMergedContent( $customMessage, $expectedMessage ) {
$title = Title::newFromText( 'ExistingPage' );
$this->assertSame(
'wikitext',
$title->getContentModel( Title::READ_LATEST ),
'Sanity check: `ExistingPage` should be wikitext'
);
$this->setTemporaryHook( 'EditFilterMergedContent',
static function ( $unused1, $unused2, Status $status ) use ( $customMessage ) {
if ( $customMessage !== false ) {
$status->fatal( $customMessage );
}
return false;
}
);
$exception = new ApiUsageException(
null,
Status::newFatal( $expectedMessage )
);
$this->expectException( ApiUsageException::class );
$this->expectExceptionMessage( $exception->getMessage() );
$this->doApiRequestWithToken( [
'action' => 'changecontentmodel',
'title' => 'ExistingPage',
'model' => 'text'
],
null,
$this->mockAnonAuthorityWithPermissions( [ 'edit', 'editcontentmodel', 'writeapi' ] )
);
}
public function provideTestEditFilterMergedContent() {
return [
[ 'DannyS712 objects to this change!', 'DannyS712 objects to this change!' ],
[ false, 'hookaborted' ]
];
}
/**
* Test the ContentModelCanBeUsedOn hook can be intercepted
*/
public function testContentModelCanBeUsedOn() {
$title = Title::newFromText( 'ExistingPage' );
$this->assertSame(
'wikitext',
$title->getContentModel( Title::READ_LATEST ),
'Sanity check: `ExistingPage` should be wikitext'
);
$this->setTemporaryHook( 'ContentModelCanBeUsedOn',
static function ( $unused1, $unused2, &$ok ) {
$ok = false;
return false;
}
);
$this->setExpectedApiException( [
'apierror-changecontentmodel-cannotbeused',
wfMessage( 'content-model-text' ),
'ExistingPage'
] );
$this->doApiRequestWithToken( [
'action' => 'changecontentmodel',
'title' => 'ExistingPage',
'model' => 'text'
],
null,
$this->mockAnonAuthorityWithPermissions( [ 'edit', 'editcontentmodel', 'writeapi' ] )
);
}
/**
* Test that content handler must support direct editing
*/
public function testNoDirectEditing() {
$title = Title::newFromText( 'Dummy:NoDirectEditing' );
$dummyContent = ContentHandler::getForModelID( 'testing' )->makeEmptyContent();
WikiPage::factory( $title )->doUserEditContent(
$dummyContent,
$this->getTestSysop()->getUser(),
'EditSummaryForThisTest',
EDIT_NEW | EDIT_SUPPRESS_RC
);
$this->assertSame(
'testing',
$title->getContentModel( Title::READ_LATEST ),
'Dummy:NoDirectEditing should start with the `testing` content model'
);
$this->setExpectedApiException( [
'apierror-changecontentmodel-nodirectediting',
ContentHandler::getLocalizedName( 'testing' )
] );
$this->doApiRequestWithToken( [
'action' => 'changecontentmodel',
'title' => 'Dummy:NoDirectEditing',
'model' => 'wikitext'
],
null,
$this->mockAnonAuthorityWithPermissions( [ 'edit', 'editcontentmodel', 'writeapi' ] )
);
}
public function testCannotApplyTags() {
ChangeTags::defineTag( 'api edit content model tag' );
$this->setExpectedApiException( 'tags-apply-no-permission' );
$this->doApiRequestWithToken( [
'action' => 'changecontentmodel',
'title' => 'ExistingPage',
'model' => 'text',
'tags' => 'api edit content model tag',
],
null,
$this->mockAnonAuthorityWithoutPermissions( [ 'applychangetags' ] ) );
}
/**
* Test that it works
*/
public function testEverythingWorks() {
$title = Title::newFromText( 'ExistingPage' );
$performer = $this->mockAnonAuthorityWithPermissions(
[ 'edit', 'editcontentmodel', 'writeapi', 'applychangetags' ]
);
$this->assertSame(
'wikitext',
$title->getContentModel( Title::READ_LATEST ),
'Sanity check: `ExistingPage` should be wikitext'
);
ChangeTags::defineTag( 'api edit content model tag' );
$data = $this->doApiRequestWithToken( [
'action' => 'changecontentmodel',
'title' => 'ExistingPage',
'model' => 'text',
'tags' => 'api edit content model tag',
], null, $performer );
$this->assertSame(
'text',
$title->getContentModel( Title::READ_LATEST ),
'API can successfully change the content model'
);
$data = $data[0]['changecontentmodel'];
$this->assertSame( 'Success', $data['result'], 'API reports successful change' );
$firstLogId = (int)$data['logid'];
$firstRevId = (int)$data['revid'];
$this->assertGreaterThan( 0, $firstLogId, 'Plausible log id generated' );
$this->assertGreaterThan( 0, $firstRevId, 'Plausible rev id generated' );
$data = $this->doApiRequestWithToken( [
'action' => 'changecontentmodel',
'title' => 'ExistingPage',
'model' => 'wikitext',
'tags' => 'api edit content model tag',
], null, $performer );
$this->assertSame(
'wikitext',
$title->getContentModel( Title::READ_LATEST ),
'API can also change the content model back'
);
$data = $data[0]['changecontentmodel'];
$this->assertSame( 'Success', $data['result'], 'API reports successful change back' );
$this->assertGreaterThan(
$firstLogId,
(int)$data['logid'],
'Second log entry should come after the first'
);
$this->assertGreaterThan(
$firstRevId,
(int)$data['revid'],
'Second revision should come after the first'
);
$dbw = wfGetDB( DB_PRIMARY );
$this->assertSame(
'4',
$dbw->selectField(
[ 'change_tag_def' ],
'ctd_count',
[ 'ctd_name' => 'api edit content model tag' ],
__METHOD__
),
'There should be four uses of the `api edit content model tag` tag, '
. 'two for the two revisions and two for the two log entries'
);
}
}