*/
$wgUseTagFilter = true;
+/**
+ * List of core tags to enable. Available tags are:
+ * - 'mw-contentmodelchange': Edit changes content model of a page
+ * - 'mw-new-redirect': Edit makes new redirect page (new page or by changing content page)
+ * - 'mw-removed-redirect': Edit changes an existing redirect into a non-redirect
+ * - 'mw-changed-redirect-target': Edit changes redirect target
+ * - 'mw-blank': Edit completely blanks the page
+ * - 'mw-replace': Edit removes more than 90% of the content
+ * - 'mw-rollback': Edit is a rollback, made through the rollback link or rollback API
+ *
+ * @var array
+ * @since 1.31
+ */
+$wgSoftwareTags = [
+ 'mw-contentmodelchange' => true,
+ 'mw-new-redirect' => true,
+ 'mw-removed-redirect' => true,
+ 'mw-changed-redirect-target' => true,
+ 'mw-blank' => true,
+ 'mw-replace' => true,
+ 'mw-rollback' => true
+];
+
/**
* If set to an integer, pages that are watched by this many users or more
* will not require the unwatchedpages permission to view the number of
*/
const MAX_DELETE_USES = 5000;
+ private static $definedSoftwareTags = [
+ 'mw-contentmodelchange',
+ 'mw-new-redirect',
+ 'mw-removed-redirect',
+ 'mw-changed-redirect-target',
+ 'mw-blank',
+ 'mw-replace',
+ 'mw-rollback'
+ ];
+
/**
- * @var string[]
+ * Loads defined core tags, checks for invalid types (if not array),
+ * and filters for supported and enabled (if $all is false) tags only.
+ *
+ * @param bool $all If true, return all valid defined tags. Otherwise, return only enabled ones.
+ * @return array Array of all defined/enabled tags.
*/
- private static $coreTags = [ 'mw-contentmodelchange' ];
+ public static function getSoftwareTags( $all = false ) {
+ global $wgSoftwareTags;
+ $softwareTags = [];
+
+ if ( !is_array( $wgSoftwareTags ) ) {
+ wfWarn( 'wgSoftwareTags should be associative array of enabled tags.
+ Please refer to documentation for the list of tags you can enable' );
+ return $softwareTags;
+ }
+
+ $availableSoftwareTags = !$all ?
+ array_keys( array_filter( $wgSoftwareTags ) ) :
+ array_keys( $wgSoftwareTags );
+
+ $softwareTags = array_intersect(
+ $availableSoftwareTags,
+ self::$definedSoftwareTags
+ );
+
+ return $softwareTags;
+ }
/**
* Creates HTML for the given tags
*/
public static function listSoftwareActivatedTags() {
// core active tags
- $tags = self::$coreTags;
+ $tags = self::getSoftwareTags();
if ( !Hooks::isRegistered( 'ChangeTagsListActive' ) ) {
return $tags;
}
*/
public static function listSoftwareDefinedTags() {
// core defined tags
- $tags = self::$coreTags;
+ $tags = self::getSoftwareTags( true );
if ( !Hooks::isRegistered( 'ListDefinedTags' ) ) {
return $tags;
}
return false;
}
+ /**
+ * Return type of change if one exists for the given edit.
+ *
+ * @since 1.31
+ *
+ * @param Content|null $oldContent The previous text of the page.
+ * @param Content|null $newContent The submitted text of the page.
+ * @param int $flags Bit mask: a bit mask of flags submitted for the edit.
+ *
+ * @return string|null String key representing type of change, or null.
+ */
+ private function getChangeType(
+ Content $oldContent = null,
+ Content $newContent = null,
+ $flags = 0
+ ) {
+ $oldTarget = $oldContent !== null ? $oldContent->getRedirectTarget() : null;
+ $newTarget = $newContent !== null ? $newContent->getRedirectTarget() : null;
+
+ // We check for the type of change in the given edit, and return string key accordingly
+
+ // Blanking of a page
+ if ( $oldContent && $oldContent->getSize() > 0 &&
+ $newContent && $newContent->getSize() === 0
+ ) {
+ return 'blank';
+ }
+
+ // Redirects
+ if ( $newTarget ) {
+ if ( !$oldTarget ) {
+ // New redirect page (by creating new page or by changing content page)
+ return 'new-redirect';
+ } elseif ( !$newTarget->equals( $oldTarget ) ||
+ $oldTarget->getFragment() !== $newTarget->getFragment()
+ ) {
+ // Redirect target changed
+ return 'changed-redirect-target';
+ }
+ } elseif ( $oldTarget ) {
+ // Changing an existing redirect into a non-redirect
+ return 'removed-redirect';
+ }
+
+ // New page created
+ if ( $flags & EDIT_NEW && $newContent && $newContent->getSize() > 0 ) {
+ return 'newpage';
+ }
+
+ // New blank page
+ if ( $flags & EDIT_NEW && $newContent && $newContent->getSize() === 0 ) {
+ return 'newblank';
+ }
+
+ // Removing more than 90% of the page
+ if ( $oldContent && $newContent && $oldContent->getSize() > 10 * $newContent->getSize() ) {
+ return 'replace';
+ }
+
+ // Content model changed
+ if ( $oldContent && $newContent && $oldContent->getModel() !== $newContent->getModel() ) {
+ return 'contentmodelchange';
+ }
+
+ return null;
+ }
+
/**
* Return an applicable auto-summary if one exists for the given edit.
*
* @since 1.21
*
- * @param Content $oldContent The previous text of the page.
- * @param Content $newContent The submitted text of the page.
+ * @param Content|null $oldContent The previous text of the page.
+ * @param Content|null $newContent The submitted text of the page.
* @param int $flags Bit mask: a bit mask of flags submitted for the edit.
*
* @return string An appropriate auto-summary, or an empty string.
*/
- public function getAutosummary( Content $oldContent = null, Content $newContent = null,
- $flags ) {
- // Decide what kind of auto-summary is needed.
-
- // Redirect auto-summaries
-
- /**
- * @var $ot Title
- * @var $rt Title
- */
+ public function getAutosummary(
+ Content $oldContent = null,
+ Content $newContent = null,
+ $flags = 0
+ ) {
+ $changeType = $this->getChangeType( $oldContent, $newContent, $flags );
- $ot = !is_null( $oldContent ) ? $oldContent->getRedirectTarget() : null;
- $rt = !is_null( $newContent ) ? $newContent->getRedirectTarget() : null;
+ // There's no applicable auto-summary for our case, so our auto-summary is empty.
+ if ( !$changeType ) {
+ return '';
+ }
- if ( is_object( $rt ) ) {
- if ( !is_object( $ot )
- || !$rt->equals( $ot )
- || $ot->getFragment() != $rt->getFragment()
- ) {
+ // Decide what kind of auto-summary is needed.
+ switch ( $changeType ) {
+ case 'new-redirect':
+ $newTarget = $newContent->getRedirectTarget();
$truncatedtext = $newContent->getTextForSummary(
250
- strlen( wfMessage( 'autoredircomment' )->inContentLanguage()->text() )
- - strlen( $rt->getFullText() ) );
+ - strlen( $newTarget->getFullText() )
+ );
- return wfMessage( 'autoredircomment', $rt->getFullText() )
+ return wfMessage( 'autoredircomment', $newTarget->getFullText() )
->rawParams( $truncatedtext )->inContentLanguage()->text();
- }
- }
+ case 'changed-redirect-target':
+ $oldTarget = $oldContent->getRedirectTarget();
+ $newTarget = $newContent->getRedirectTarget();
- // New page auto-summaries
- if ( $flags & EDIT_NEW && $newContent->getSize() > 0 ) {
- // If they're making a new article, give its text, truncated, in
- // the summary.
+ $truncatedtext = $newContent->getTextForSummary(
+ 250
+ - strlen( wfMessage( 'autosumm-changed-redirect-target' )
+ ->inContentLanguage()->text() )
+ - strlen( $oldTarget->getFullText() )
+ - strlen( $newTarget->getFullText() )
+ );
+
+ return wfMessage( 'autosumm-changed-redirect-target',
+ $oldTarget->getFullText(),
+ $newTarget->getFullText() )
+ ->rawParams( $truncatedtext )->inContentLanguage()->text();
+ case 'removed-redirect':
+ $oldTarget = $oldContent->getRedirectTarget();
+ $truncatedtext = $newContent->getTextForSummary(
+ 250
+ - strlen( wfMessage( 'autosumm-removed-redirect' )
+ ->inContentLanguage()->text() )
+ - strlen( $oldTarget->getFullText() ) );
- $truncatedtext = $newContent->getTextForSummary(
- 200 - strlen( wfMessage( 'autosumm-new' )->inContentLanguage()->text() ) );
+ return wfMessage( 'autosumm-removed-redirect', $oldTarget->getFullText() )
+ ->rawParams( $truncatedtext )->inContentLanguage()->text();
+ case 'newpage':
+ // If they're making a new article, give its text, truncated, in the summary.
+ $truncatedtext = $newContent->getTextForSummary(
+ 200 - strlen( wfMessage( 'autosumm-new' )->inContentLanguage()->text() ) );
- return wfMessage( 'autosumm-new' )->rawParams( $truncatedtext )
- ->inContentLanguage()->text();
+ return wfMessage( 'autosumm-new' )->rawParams( $truncatedtext )
+ ->inContentLanguage()->text();
+ case 'blank':
+ return wfMessage( 'autosumm-blank' )->inContentLanguage()->text();
+ case 'replace':
+ $truncatedtext = $newContent->getTextForSummary(
+ 200 - strlen( wfMessage( 'autosumm-replace' )->inContentLanguage()->text() ) );
+
+ return wfMessage( 'autosumm-replace' )->rawParams( $truncatedtext )
+ ->inContentLanguage()->text();
+ case 'newblank':
+ return wfMessage( 'autosumm-newblank' )->inContentLanguage()->text();
+ default:
+ return '';
}
+ }
- // Blanking auto-summaries
- if ( !empty( $oldContent ) && $oldContent->getSize() > 0 && $newContent->getSize() == 0 ) {
- return wfMessage( 'autosumm-blank' )->inContentLanguage()->text();
- } elseif ( !empty( $oldContent )
- && $oldContent->getSize() > 10 * $newContent->getSize()
- && $newContent->getSize() < 500
- ) {
- // Removing more than 90% of the article
-
- $truncatedtext = $newContent->getTextForSummary(
- 200 - strlen( wfMessage( 'autosumm-replace' )->inContentLanguage()->text() ) );
+ /**
+ * Return an applicable tag if one exists for the given edit or return null.
+ *
+ * @since 1.31
+ *
+ * @param Content|null $oldContent The previous text of the page.
+ * @param Content|null $newContent The submitted text of the page.
+ * @param int $flags Bit mask: a bit mask of flags submitted for the edit.
+ *
+ * @return string|null An appropriate tag, or null.
+ */
+ public function getChangeTag(
+ Content $oldContent = null,
+ Content $newContent = null,
+ $flags = 0
+ ) {
+ $changeType = $this->getChangeType( $oldContent, $newContent, $flags );
- return wfMessage( 'autosumm-replace' )->rawParams( $truncatedtext )
- ->inContentLanguage()->text();
+ // There's no applicable tag for this change.
+ if ( !$changeType ) {
+ return null;
}
- // New blank article auto-summary
- if ( $flags & EDIT_NEW && $newContent->isEmpty() ) {
- return wfMessage( 'autosumm-newblank' )->inContentLanguage()->text();
+ // Core tags use the same keys as ones returned from $this->getChangeType()
+ // but prefixed with pseudo namespace 'mw-', so we add the prefix before checking
+ // if this type of change should be tagged
+ $tag = 'mw-' . $changeType;
+
+ // Not all change types are tagged, so we check against the list of defined tags.
+ if ( in_array( $tag, ChangeTags::getSoftwareTags() ) ) {
+ return $tag;
}
- // If we reach this point, there's no applicable auto-summary for our
- // case, so our auto-summary is empty.
- return '';
+ return null;
}
/**
$old_revision = $this->getRevision(); // current revision
$old_content = $this->getContent( Revision::RAW ); // current revision's content
- if ( $old_content && $old_content->getModel() !== $content->getModel() ) {
- $tags[] = 'mw-contentmodelchange';
+ $handler = $content->getContentHandler();
+ $tag = $handler->getChangeTag( $old_content, $content, $flags );
+ // If there is no applicable tag, null is returned, so we need to check
+ if ( $tag ) {
+ $tags[] = $tag;
}
- // Provide autosummaries if one is not provided and autosummaries are enabled
+ // Provide autosummaries if summary is not provided and autosummaries are enabled
if ( $wgUseAutomaticEditSummaries && ( $flags & EDIT_AUTOSUMMARY ) && $summary == '' ) {
- $handler = $content->getContentHandler();
$summary = $handler->getAutosummary( $old_content, $content, $flags );
}
$targetContent = $target->getContent();
$changingContentModel = $targetContent->getModel() !== $current->getContentModel();
+ if ( in_array( 'mw-rollback', ChangeTags::getSoftwareTags() ) ) {
+ $tags[] = 'mw-rollback';
+ }
+
// Actually store the edit
$status = $this->doEditContent(
$targetContent,
'summary' => $summary,
'current' => $current,
'target' => $target,
- 'newid' => $revId
+ 'newid' => $revId,
+ 'tags' => $tags
];
return [];
"autosumm-blank": "Blanked the page",
"autosumm-replace": "Replaced content with \"$1\"",
"autoredircomment": "Redirected page to [[$1]]",
+ "autosumm-removed-redirect": "Removed redirect to [[$1]]",
+ "autosumm-changed-redirect-target": "Changed redirect target from [[$1]] to [[$2]]",
"autosumm-new": "Created page with \"$1\"",
"autosumm-newblank": "Created blank page",
"autoblock_whitelist": "",
"tag-list-wrapper": "([[Special:Tags|{{PLURAL:$1|Tag|Tags}}]]: $2)",
"tag-mw-contentmodelchange": "content model change",
"tag-mw-contentmodelchange-description": "Edits that [https://www.mediawiki.org/wiki/Special:MyLanguage/Help:ChangeContentModel change the content model] of a page",
+ "tag-mw-new-redirect": "New redirect",
+ "tag-mw-new-redirect-description": "Edits that create a new redirect or change a page to a redirect",
+ "tag-mw-removed-redirect": "Removed redirect",
+ "tag-mw-removed-redirect-description": "Edits that change an existing redirect to a non-redirect",
+ "tag-mw-changed-redirect-target": "Redirect target changed",
+ "tag-mw-changed-redirect-target-description": "Edits that change the target of a redirect",
+ "tag-mw-blank": "Blanking",
+ "tag-mw-blank-description": "Edits that blank a page",
+ "tag-mw-replace": "Replaced",
+ "tag-mw-replace-description": "Edits that remove more than 90% of the content of a page",
+ "tag-mw-rollback": "Rollback",
+ "tag-mw-rollback-description": "Edits that roll back previous edits using the rollback link",
"tags-title": "Tags",
"tags-intro": "This page lists the tags that the software may mark an edit with, and their meaning.",
"tags-tag": "Tag name",
"autosumm-blank": "The auto summary when blanking the whole page. This is not the same as deleting the page.",
"autosumm-replace": "The auto summary when a user removes a lot of characters in the page.\n\nParameters:\n* $1 - truncated text",
"autoredircomment": "The auto summary when making a redirect. Parameters:\n* $1 - the page where it redirects to\n* $2 - (Optional) the first X number of characters of the redirect ($2 is usually only used when end users customize the message)\n{{Identical|Redirect}}",
+ "autosumm-removed-redirect": "The auto summary when making a redirect. Parameters:\n* $1 - the page where it redirects to\n* $2 - (Optional) the first X number of characters of the redirect ($2 is usually only used when end users customize the message)\n{{Identical|Redirect}}",
+ "autosumm-changed-redirect-target": "The auto summary when making a redirect. Parameters:\n* $1 - the page where it redirects to\n* $2 - (Optional) the first X number of characters of the redirect ($2 is usually only used when end users customize the message)\n{{Identical|Redirect}}",
"autosumm-new": "The auto summary when creating a new page. $1 are the first X number of characters of the new page.",
"autosumm-newblank": "The automatic edit summary when creating a blank page. This is not the same as blanking a page.",
"autoblock_whitelist": "{{notranslate}}",
"tag-list-wrapper": "Wrapper for the list of tags shown on recent changes, watchlists, history pages and diffs.\n\nParameters:\n* $1 - number of distinct tags for given edit\n* $2 - comma-separated list of tags for given edit",
"tag-mw-contentmodelchange": "Change tag for edits that change the content model of a page",
"tag-mw-contentmodelchange-description": "Description for \"content model change\" change tag",
+ "tag-mw-new-redirect": "Change tag for edits that make the page a redirect (either redirect creation or editing an existing page)",
+ "tag-mw-new-redirect-description": "Description for \"New redirect\" change tag",
+ "tag-mw-removed-redirect": "Change tag for edits that change an existing redirect into a non-redirect",
+ "tag-mw-removed-redirect-description": "Description for \"Removed redirect\" change tag",
+ "tag-mw-changed-redirect-target": "Change tag for edits that change the target of a redirect",
+ "tag-mw-changed-redirect-target-description": "Description for \"Redirect target changed\" change tag",
+ "tag-mw-blank": "Change tag for edits that blank a page with existing content",
+ "tag-mw-blank-description": "Description for \"blank\" change tag",
+ "tag-mw-replace": "Change tag for edits removing more than 90% of the content of a page",
+ "tag-mw-replace-description": "Description for \"replace\" change tag",
+ "tag-mw-rollback": "Change tag for rolling back an edit",
+ "tag-mw-rollback-description": "Description for \"rollback\" change tag",
"tags-title": "The title of [[Special:Tags]].\n{{Identical|Tag}}",
"tags-intro": "Explanation on top of [[Special:Tags]]. For more information on tags see [[mw:Manual:Tags|MediaWiki]].",
"tags-tag": "Caption of a column in [[Special:Tags]]. For more information on tags see [[mw:Manual:Tags|MediaWiki]].",
*/
class ChangeTagsTest extends MediaWikiTestCase {
- // TODO only modifyDisplayQuery is tested, nothing else is
+ // TODO only modifyDisplayQuery and getSoftwareTags are tested, nothing else is
/** @dataProvider provideModifyDisplayQuery */
public function testModifyDisplayQuery( $origQuery, $filter_tag, $useTags, $modifiedQuery ) {
];
}
+ public static function dataGetSoftwareTags() {
+ return [
+ [
+ [
+ 'mw-contentModelChange' => true,
+ 'mw-redirect' => true,
+ 'mw-rollback' => true,
+ 'mw-blank' => true,
+ 'mw-replace' => true
+ ],
+ [
+ 'mw-rollback',
+ 'mw-replace',
+ 'mw-blank'
+ ]
+ ],
+
+ [
+ [
+ 'mw-contentmodelchanged' => true,
+ 'mw-replace' => true,
+ 'mw-new-redirects' => true,
+ 'mw-changed-redirect-target' => true,
+ 'mw-rolback' => true,
+ 'mw-blanking' => false
+ ],
+ [
+ 'mw-replace',
+ 'mw-changed-redirect-target'
+ ]
+ ],
+
+ [
+ [
+ null,
+ false,
+ 'Lorem ipsum',
+ 'mw-translation'
+ ],
+ []
+ ],
+
+ [
+ [],
+ []
+ ]
+ ];
+ }
+
+ /**
+ * @dataProvider dataGetSoftwareTags
+ * @covers ChangeTags::getSoftwareTags
+ */
+ public function testGetSoftwareTags( $softwareTags, $expected ) {
+ $this->setMwGlobals( 'wgSoftwareTags', $softwareTags );
+
+ $actual = ChangeTags::getSoftwareTags();
+ // Order of tags in arrays is not important
+ sort( $expected );
+ sort( $actual );
+ $this->assertEquals( $expected, $actual );
+ }
}
$content = new DummyContentHandlerForTesting( CONTENT_MODEL_WIKITEXT );
$title = Title::newFromText( 'Help:Test' );
// Create a new content object with no content
- $newContent = ContentHandler::makeContent( '', $title, null, null, CONTENT_MODEL_WIKITEXT );
+ $newContent = ContentHandler::makeContent( '', $title, CONTENT_MODEL_WIKITEXT, null );
// first check, if we become a blank page created summary with the right bitmask
$autoSummary = $content->getAutosummary( null, $newContent, 97 );
- $this->assertEquals( $autoSummary, 'Created blank page' );
+ $this->assertEquals( $autoSummary,
+ wfMessage( 'autosumm-newblank' )->inContentLanguage()->text() );
// now check, what we become with another bitmask
$autoSummary = $content->getAutosummary( null, $newContent, 92 );
$this->assertEquals( $autoSummary, '' );
}
+ /**
+ * Test software tag that is added when content model of the page changes
+ * @covers ContentHandler::getChangeTag
+ */
+ public function testGetChangeTag() {
+ $this->setMwGlobals( 'wgSoftwareTags', [ 'mw-contentmodelchange' => true ] );
+ $wikitextContentHandler = new DummyContentHandlerForTesting( CONTENT_MODEL_WIKITEXT );
+ // Create old content object with javascript content model
+ $oldContent = ContentHandler::makeContent( '', null, CONTENT_MODEL_JAVASCRIPT, null );
+ // Create new content object with wikitext content model
+ $newContent = ContentHandler::makeContent( '', null, CONTENT_MODEL_WIKITEXT, null );
+ // Get the tag for this edit
+ $tag = $wikitextContentHandler->getChangeTag( $oldContent, $newContent, EDIT_UPDATE );
+ $this->assertSame( $tag, 'mw-contentmodelchange' );
+ }
+
/*
public function testSupportsSections() {
$this->markTestIncomplete( "not yet implemented" );
'/^Created page .*Hello/'
],
+ [
+ null,
+ '',
+ EDIT_NEW,
+ '/^Created blank page$/'
+ ],
+
[
'Hello there, world!',
'',
);
}
+ public static function dataGetChangeTag() {
+ return [
+ [
+ null,
+ '#REDIRECT [[Foo]]',
+ 0,
+ 'mw-new-redirect'
+ ],
+
+ [
+ 'Lorem ipsum dolor',
+ '#REDIRECT [[Foo]]',
+ 0,
+ 'mw-new-redirect'
+ ],
+
+ [
+ '#REDIRECT [[Foo]]',
+ 'Lorem ipsum dolor',
+ 0,
+ 'mw-removed-redirect'
+ ],
+
+ [
+ '#REDIRECT [[Foo]]',
+ '#REDIRECT [[Bar]]',
+ 0,
+ 'mw-changed-redirect-target'
+ ],
+
+ [
+ null,
+ 'Lorem ipsum dolor',
+ EDIT_NEW,
+ null // mw-newpage is not defined as a tag
+ ],
+
+ [
+ null,
+ '',
+ EDIT_NEW,
+ null // mw-newblank is not defined as a tag
+ ],
+
+ [
+ 'Lorem ipsum dolor',
+ '',
+ 0,
+ 'mw-blank'
+ ],
+
+ [
+ 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
+ eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
+ voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
+ clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.',
+ 'Ipsum',
+ 0,
+ 'mw-replace'
+ ],
+
+ [
+ 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy
+ eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam
+ voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet
+ clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.',
+ 'Duis purus odio, rhoncus et finibus dapibus, facilisis ac urna. Pellentesque
+ arcu, tristique nec tempus nec, suscipit vel arcu. Sed non dolor nec ligula
+ congue tempor. Quisque pellentesque finibus orci a molestie. Nam maximus, purus
+ euismod finibus mollis, dui ante malesuada felis, dignissim rutrum diam sapien.',
+ 0,
+ null
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider dataGetChangeTag
+ * @covers WikitextContentHandler::getChangeTag
+ */
+ public function testGetChangeTag( $old, $new, $flags, $expected ) {
+ $this->setMwGlobals( 'wgSoftwareTags', [
+ 'mw-new-redirect' => true,
+ 'mw-removed-redirect' => true,
+ 'mw-changed-redirect-target' => true,
+ 'mw-newpage' => true,
+ 'mw-newblank' => true,
+ 'mw-blank' => true,
+ 'mw-replace' => true,
+ ] );
+ $oldContent = is_null( $old ) ? null : new WikitextContent( $old );
+ $newContent = is_null( $new ) ? null : new WikitextContent( $new );
+
+ $tag = $this->handler->getChangeTag( $oldContent, $newContent, $flags );
+
+ $this->assertSame( $expected, $tag );
+ }
+
/**
* @todo Text case requires database, should be done by a test class in the Database group
*/
$this->assertEquals( "one", $page->getContent()->getNativeData() );
}
+ /**
+ * Tests tagging for edits that do rollback action
+ * @covers WikiPage::doRollback
+ */
+ public function testDoRollbackTagging() {
+ if ( !in_array( 'mw-rollback', ChangeTags::getSoftwareTags() ) ) {
+ $this->markTestSkipped( 'Rollback tag deactivated, skipped the test.' );
+ }
+
+ $admin = new User();
+ $admin->setName( 'Administrator' );
+ $admin->addToDatabase();
+
+ $text = 'First line';
+ $page = $this->newPage( 'WikiPageTest_testDoRollbackTagging' );
+ $page->doEditContent(
+ ContentHandler::makeContent( $text, $page->getTitle(), CONTENT_MODEL_WIKITEXT ),
+ 'Added first line',
+ EDIT_NEW,
+ false,
+ $admin
+ );
+
+ $secondUser = new User();
+ $secondUser->setName( '92.65.217.32' );
+ $text .= '\n\nSecond line';
+ $page = new WikiPage( $page->getTitle() );
+ $page->doEditContent(
+ ContentHandler::makeContent( $text, $page->getTitle(), CONTENT_MODEL_WIKITEXT ),
+ 'Adding second line',
+ 0,
+ false,
+ $secondUser
+ );
+
+ // Now, try the rollback
+ $admin->addGroup( 'sysop' ); // Make the test user a sysop
+ $token = $admin->getEditToken( 'rollback' );
+ $errors = $page->doRollback(
+ $secondUser->getName(),
+ 'testing rollback',
+ $token,
+ false,
+ $resultDetails,
+ $admin
+ );
+
+ // If doRollback completed without errors
+ if ( $errors === [] ) {
+ $tags = $resultDetails[ 'tags' ];
+ $this->assertContains( 'mw-rollback', $tags );
+ }
+ }
+
public static function provideGetAutoDeleteReason() {
return [
[