Page MenuHomeWickedGov Phorge

ChangeTagsTest.php
No OneTemporary

Size
27 KB
Referenced Files
None
Subscribers
None

ChangeTagsTest.php

<?php
use MediaWiki\Language\RawMessage;
use MediaWiki\MainConfigNames;
use MediaWiki\MediaWikiServices;
use Wikimedia\Rdbms\Platform\ISQLPlatform;
/**
* @covers \ChangeTags
* @group Database
*/
class ChangeTagsTest extends MediaWikiIntegrationTestCase {
protected function tearDown(): void {
parent::tearDown();
}
private function emptyChangeTagsTables() {
$dbw = $this->getDb();
$dbw->newDeleteQueryBuilder()
->deleteFrom( 'change_tag' )
->where( ISQLPlatform::ALL_ROWS )
->execute();
$dbw->newDeleteQueryBuilder()
->deleteFrom( 'change_tag_def' )
->where( ISQLPlatform::ALL_ROWS )
->execute();
}
// TODO most methods are not tested
public function testBuildTagFilterSelector_allTags() {
// Set `activeOnly` to false
// Expect that at least all the software defined tags are returned
$allTags = MediaWikiServices::getInstance()->getChangeTagsStore()->listDefinedTags();
$allTagsList = ChangeTags::getChangeTagListSummary(
RequestContext::getMain(),
RequestContext::getMain()->getLanguage(),
ChangeTags::TAG_SET_ALL
);
$this->assertTrue(
count( $allTagsList ) >= count( $allTags ),
'`activeOnly` is false, expect all software tags'
);
}
public function testBuildTagFilterSelector_allSoftwareTags() {
// Set both `activeOnly` and `useAllTags` to false
// Expect that only software defined tags are returned
$allSoftwareTags = MediaWikiServices::getInstance()->getChangeTagsStore()->getSoftwareTags( true );
$allSoftwareTagsList = ChangeTags::getChangeTagListSummary(
RequestContext::getMain(),
RequestContext::getMain()->getLanguage(),
ChangeTags::TAG_SET_ALL,
ChangeTags::USE_SOFTWARE_TAGS_ONLY
);
$this->assertTrue(
count( $allSoftwareTagsList ) == count( $allSoftwareTags ),
'`activeOnly` and `useAllTags` are false, expect only software tags'
);
}
public function testBuildTagFilterSelector_activeOnlyNoHits() {
// Enable and test `activeOnly` and expect no tags returned,
// as there are currently no tagged edits in the test database
$emptyTagListSummary = ChangeTags::getChangeTagListSummary(
RequestContext::getMain(),
RequestContext::getMain()->getLanguage(),
ChangeTags::TAG_SET_ACTIVE_ONLY
);
$this->assertCount( 0, $emptyTagListSummary, '`activeOnly` is true and no hits, expect no tags' );
// Assert that by default, an empty select is returned, as no tags have been used yet
$this->assertEquals(
[
'<label for="tagfilter"><a href="/wiki/Special:Tags" title="Special:Tags">Tag</a> filter:</label>',
'<input class="mw-tagfilter-input mw-ui-input mw-ui-input-inline" size="20" id="tagfilter" list="tagfilter-datalist" name="tagfilter"><datalist id="tagfilter-datalist"></datalist>'
],
ChangeTags::buildTagFilterSelector(
'', false, RequestContext::getMain()
)
);
}
public function testBuildTagFilterSelector_activeOnly() {
// Disable patrolling so reverts will happen without approval
$this->overrideConfigValues( [ MainConfigNames::UseRCPatrol => false ] );
// Make an edit and replace the content, adding the `mw-replace` tag to the revision
$page = $this->getExistingTestPage();
$this->editPage( $page, '1' );
$this->editPage(
$page, '0', '', NS_MAIN, $this->getTestUser()->getUser()
);
// Ensure all deferred updates are run
DeferredUpdates::doUpdates();
// Assert that only the `mw-replace` tag is returned
$replaceOnlyTagList = ChangeTags::getChangeTagListSummary(
RequestContext::getMain(),
RequestContext::getMain()->getLanguage()
);
$this->assertCount( 1, $replaceOnlyTagList, '`activeOnly` is true with 1 hit, return 1 tag' );
$this->assertEquals(
'mw-replace', $replaceOnlyTagList[0]['name'],
'`activeOnly` is true with 1 hit, return expected tag'
);
// Assert that the tag is reflected in the default markup returned
$this->assertEquals(
[
'<label for="tagfilter"><a href="/wiki/Special:Tags" title="Special:Tags">Tag</a> filter:</label>',
'<input class="mw-tagfilter-input mw-ui-input mw-ui-input-inline" size="20" id="tagfilter" list="tagfilter-datalist" name="tagfilter"><datalist id="tagfilter-datalist"><option value="mw-replace">Replaced</option></datalist>'
],
ChangeTags::buildTagFilterSelector(
'', false, RequestContext::getMain()
),
'`activeOnly` is true with 1 hit, return expected tag markup'
);
}
/** @dataProvider provideModifyDisplayQuery */
public function testModifyDisplayQuery(
$origQuery,
$filter_tag,
$useTags,
$avoidReopeningTables,
$modifiedQuery,
$exclude = false
) {
$this->overrideConfigValue( MainConfigNames::UseTagFilter, $useTags );
if (
$avoidReopeningTables &&
$this->getDb()->getType() === 'mysql' &&
str_contains( $this->getDb()->getSoftwareLink(), 'MySQL' )
) {
$this->markTestSkipped( 'See T256006' );
}
$rcId = 123;
ChangeTags::updateTags( [ 'foo', 'bar', '0' ], [], $rcId );
// HACK resolve deferred group concats (see comment in provideModifyDisplayQuery)
if ( isset( $modifiedQuery['fields']['ts_tags'] ) ) {
$modifiedQuery['fields']['ts_tags'] = $this->getDb()
->buildGroupConcatField( ...$modifiedQuery['fields']['ts_tags'] );
}
if ( isset( $modifiedQuery['exception'] ) ) {
$this->expectException( $modifiedQuery['exception'] );
}
ChangeTags::modifyDisplayQuery(
$origQuery['tables'],
$origQuery['fields'],
$origQuery['conds'],
$origQuery['join_conds'],
$origQuery['options'],
$filter_tag,
$exclude
);
if ( !isset( $modifiedQuery['exception'] ) ) {
$this->assertArrayEquals(
$modifiedQuery,
$origQuery,
/* ordered = */ false,
/* named = */ true
);
}
}
public static function provideModifyDisplayQuery() {
// HACK if we call $dbr->buildGroupConcatField() now, it will return the wrong table names
// We have to have the test runner call it instead
$baseConcats = [ ',', [ 'change_tag', 'change_tag_def' ], 'ctd_name' ];
$joinConds = [ 'change_tag_def' => [ 'JOIN', 'ct_tag_id=ctd_id' ] ];
$groupConcats = [
'recentchanges' => array_merge( $baseConcats, [ [ 'ct_rc_id=rc_id' ], $joinConds ] ),
'logging' => array_merge( $baseConcats, [ [ 'ct_log_id=log_id' ], $joinConds ] ),
'revision' => array_merge( $baseConcats, [ [ 'ct_rev_id=rev_id' ], $joinConds ] ),
'archive' => array_merge( $baseConcats, [ [ 'ct_rev_id=ar_rev_id' ], $joinConds ] ),
];
return [
'simple recentchanges query' => [
[
'tables' => [ 'recentchanges' ],
'fields' => [ 'rc_id', 'rc_timestamp' ],
'conds' => [ "rc_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
],
'', // no tag filter
true, // tag filtering enabled
false, // not avoiding reopening tables
[
'tables' => [ 'recentchanges' ],
'fields' => [ 'rc_id', 'rc_timestamp', 'ts_tags' => $groupConcats['recentchanges'] ],
'conds' => [ "rc_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
]
],
"simple query with strings, tagfilter=''" => [
[
'tables' => 'recentchanges',
'fields' => 'rc_id',
'conds' => "rc_timestamp > '20170714183203'",
'join_conds' => [],
'options' => 'ORDER BY rc_timestamp DESC',
],
'', // no tag filter
true, // tag filtering enabled
false, // not avoiding reopening tables
[
'tables' => [ 'recentchanges' ],
'fields' => [ 'rc_id', 'ts_tags' => $groupConcats['recentchanges'] ],
'conds' => [ "rc_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY rc_timestamp DESC' ],
]
],
'simple query with strings, tagfilter=false' => [
[
'tables' => 'recentchanges',
'fields' => 'rc_id',
'conds' => "rc_timestamp > '20170714183203'",
'join_conds' => [],
'options' => 'ORDER BY rc_timestamp DESC',
],
false, // no tag filter
true, // tag filtering enabled
false, // not avoiding reopening tables
[
'tables' => [ 'recentchanges' ],
'fields' => [ 'rc_id', 'ts_tags' => $groupConcats['recentchanges'] ],
'conds' => [ "rc_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY rc_timestamp DESC' ],
]
],
'simple query with strings, tagfilter=null' => [
[
'tables' => 'recentchanges',
'fields' => 'rc_id',
'conds' => "rc_timestamp > '20170714183203'",
'join_conds' => [],
'options' => 'ORDER BY rc_timestamp DESC',
],
null, // no tag filter
true, // tag filtering enabled
false, // not avoiding reopening tables
[
'tables' => [ 'recentchanges' ],
'fields' => [ 'rc_id', 'ts_tags' => $groupConcats['recentchanges'] ],
'conds' => [ "rc_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY rc_timestamp DESC' ],
]
],
'recentchanges query with single tag filter' => [
[
'tables' => [ 'recentchanges' ],
'fields' => [ 'rc_id', 'rc_timestamp' ],
'conds' => [ "rc_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
],
'foo',
true, // tag filtering enabled
false, // not avoiding reopening tables
[
'tables' => [ 'recentchanges', 'changetagdisplay' => 'change_tag' ],
'fields' => [ 'rc_id', 'rc_timestamp', 'ts_tags' => $groupConcats['recentchanges'] ],
'conds' => [ "rc_timestamp > '20170714183203'", 'changetagdisplay.ct_tag_id' => [ 1 ] ],
'join_conds' => [ 'changetagdisplay' => [ 'JOIN', 'changetagdisplay.ct_rc_id=rc_id' ] ],
'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
]
],
'recentchanges query with "0" tag filter' => [
[
'tables' => [ 'recentchanges' ],
'fields' => [ 'rc_id', 'rc_timestamp' ],
'conds' => [ "rc_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
],
'0',
true, // tag filtering enabled
false, // not avoiding reopening tables
[
'tables' => [ 'recentchanges', 'changetagdisplay' => 'change_tag' ],
'fields' => [ 'rc_id', 'rc_timestamp', 'ts_tags' => $groupConcats['recentchanges'] ],
'conds' => [ "rc_timestamp > '20170714183203'", 'changetagdisplay.ct_tag_id' => [ 3 ] ],
'join_conds' => [ 'changetagdisplay' => [ 'JOIN', 'changetagdisplay.ct_rc_id=rc_id' ] ],
'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
]
],
'logging query with single tag filter and strings' => [
[
'tables' => 'logging',
'fields' => 'log_id',
'conds' => "log_timestamp > '20170714183203'",
'join_conds' => [],
'options' => [ 'ORDER BY' => [ 'log_timestamp DESC', 'log_id DESC' ] ],
],
'foo',
true, // tag filtering enabled
false, // not avoiding reopening tables
[
'tables' => [ 'logging', 'changetagdisplay' => 'change_tag' ],
'fields' => [ 'log_id', 'ts_tags' => $groupConcats['logging'] ],
'conds' => [ "log_timestamp > '20170714183203'", 'changetagdisplay.ct_tag_id' => [ 1 ] ],
'join_conds' => [ 'changetagdisplay' => [ 'JOIN', 'changetagdisplay.ct_log_id=log_id' ] ],
'options' => [ 'ORDER BY' => [ 'log_timestamp DESC', 'log_id DESC' ] ],
]
],
'revision query with single tag filter' => [
[
'tables' => [ 'revision' ],
'fields' => [ 'rev_id', 'rev_timestamp' ],
'conds' => [ "rev_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY' => 'rev_timestamp DESC' ],
],
'foo',
true, // tag filtering enabled
false, // not avoiding reopening tables
[
'tables' => [ 'revision', 'changetagdisplay' => 'change_tag' ],
'fields' => [ 'rev_id', 'rev_timestamp', 'ts_tags' => $groupConcats['revision'] ],
'conds' => [ "rev_timestamp > '20170714183203'", 'changetagdisplay.ct_tag_id' => [ 1 ] ],
'join_conds' => [ 'changetagdisplay' => [ 'JOIN', 'changetagdisplay.ct_rev_id=rev_id' ] ],
'options' => [ 'ORDER BY' => 'rev_timestamp DESC' ],
]
],
'archive query with single tag filter' => [
[
'tables' => [ 'archive' ],
'fields' => [ 'ar_id', 'ar_timestamp' ],
'conds' => [ "ar_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY' => 'ar_timestamp DESC' ],
],
'foo',
true, // tag filtering enabled
false, // not avoiding reopening tables
[
'tables' => [ 'archive', 'changetagdisplay' => 'change_tag' ],
'fields' => [ 'ar_id', 'ar_timestamp', 'ts_tags' => $groupConcats['archive'] ],
'conds' => [ "ar_timestamp > '20170714183203'", 'changetagdisplay.ct_tag_id' => [ 1 ] ],
'join_conds' => [ 'changetagdisplay' => [ 'JOIN', 'changetagdisplay.ct_rev_id=ar_rev_id' ] ],
'options' => [ 'ORDER BY' => 'ar_timestamp DESC' ],
]
],
'archive query with single tag filter, avoiding reopening tables' => [
[
'tables' => [ 'archive' ],
'fields' => [ 'ar_id', 'ar_timestamp' ],
'conds' => [ "ar_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY' => 'ar_timestamp DESC' ],
],
'foo',
true, // tag filtering enabled
true, // avoid reopening tables
[
'tables' => [ 'archive', 'changetagdisplay' => 'change_tag' ],
'fields' => [ 'ar_id', 'ar_timestamp', 'ts_tags' => $groupConcats['archive'] ],
'conds' => [ "ar_timestamp > '20170714183203'", 'changetagdisplay.ct_tag_id' => [ 1 ] ],
'join_conds' => [ 'changetagdisplay' => [ 'JOIN', 'changetagdisplay.ct_rev_id=ar_rev_id' ] ],
'options' => [ 'ORDER BY' => 'ar_timestamp DESC' ],
]
],
'unsupported table name throws exception (even without tag filter)' => [
[
'tables' => [ 'foobar' ],
'fields' => [ 'fb_id', 'fb_timestamp' ],
'conds' => [ "fb_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY' => 'fb_timestamp DESC' ],
],
'',
true, // tag filtering enabled
false, // not avoiding reopening tables
[ 'exception' => InvalidArgumentException::class ]
],
'tag filter ignored when tag filtering is disabled' => [
[
'tables' => [ 'archive' ],
'fields' => [ 'ar_id', 'ar_timestamp' ],
'conds' => [ "ar_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY' => 'ar_timestamp DESC' ],
],
'foo',
false, // tag filtering disabled
false, // not avoiding reopening tables
[
'tables' => [ 'archive' ],
'fields' => [ 'ar_id', 'ar_timestamp', 'ts_tags' => $groupConcats['archive'] ],
'conds' => [ "ar_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY' => 'ar_timestamp DESC' ],
]
],
'recentchanges query with multiple tag filter' => [
[
'tables' => [ 'recentchanges' ],
'fields' => [ 'rc_id', 'rc_timestamp' ],
'conds' => [ "rc_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
],
[ 'foo', 'bar' ],
true, // tag filtering enabled
false, // not avoiding reopening tables
[
'tables' => [ 'recentchanges', 'changetagdisplay' => 'change_tag' ],
'fields' => [ 'rc_id', 'rc_timestamp', 'ts_tags' => $groupConcats['recentchanges'] ],
'conds' => [ "rc_timestamp > '20170714183203'", 'changetagdisplay.ct_tag_id' => [ 1, 2 ] ],
'join_conds' => [ 'changetagdisplay' => [ 'JOIN', 'changetagdisplay.ct_rc_id=rc_id' ] ],
'options' => [ 'ORDER BY' => 'rc_timestamp DESC', 'DISTINCT' ],
]
],
'recentchanges query with exclusive multiple tag filter' => [
[
'tables' => [ 'recentchanges' ],
'fields' => [ 'rc_id', 'rc_timestamp' ],
'conds' => [ "rc_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
],
[ 'foo', 'bar' ],
true, // tag filtering enabled
false, // not avoiding reopening tables
[
'tables' => [ 'recentchanges', 'changetagdisplay' => 'change_tag' ],
'fields' => [ 'rc_id', 'rc_timestamp', 'ts_tags' => $groupConcats['recentchanges'] ],
'conds' => [ "rc_timestamp > '20170714183203'", 'changetagdisplay.ct_tag_id' => null ],
'join_conds' => [ 'changetagdisplay' => [ 'LEFT JOIN', [ 'changetagdisplay.ct_rc_id=rc_id', 'changetagdisplay.ct_tag_id' => [ 1, 2 ] ] ] ],
'options' => [ 'ORDER BY' => 'rc_timestamp DESC' ],
],
true // exclude
],
'recentchanges query with multiple tag filter that already has DISTINCT' => [
[
'tables' => [ 'recentchanges' ],
'fields' => [ 'rc_id', 'rc_timestamp' ],
'conds' => [ "rc_timestamp > '20170714183203'" ],
'join_conds' => [],
'options' => [ 'DISTINCT', 'ORDER BY' => 'rc_timestamp DESC' ],
],
[ 'foo', 'bar' ],
true, // tag filtering enabled
false, // not avoiding reopening tables
[
'tables' => [ 'recentchanges', 'changetagdisplay' => 'change_tag' ],
'fields' => [ 'rc_id', 'rc_timestamp', 'ts_tags' => $groupConcats['recentchanges'] ],
'conds' => [ "rc_timestamp > '20170714183203'", 'changetagdisplay.ct_tag_id' => [ 1, 2 ] ],
'join_conds' => [ 'changetagdisplay' => [ 'JOIN', 'changetagdisplay.ct_rc_id=rc_id' ] ],
'options' => [ 'DISTINCT', 'ORDER BY' => 'rc_timestamp DESC' ],
]
],
'recentchanges query with multiple tag filter with strings' => [
[
'tables' => 'recentchanges',
'fields' => 'rc_id',
'conds' => "rc_timestamp > '20170714183203'",
'join_conds' => [],
'options' => 'ORDER BY rc_timestamp DESC',
],
[ 'foo', 'bar' ],
true, // tag filtering enabled
false, // not avoiding reopening tables
[
'tables' => [ 'recentchanges', 'changetagdisplay' => 'change_tag' ],
'fields' => [ 'rc_id', 'ts_tags' => $groupConcats['recentchanges'] ],
'conds' => [ "rc_timestamp > '20170714183203'", 'changetagdisplay.ct_tag_id' => [ 1, 2 ] ],
'join_conds' => [ 'changetagdisplay' => [ 'JOIN', 'changetagdisplay.ct_rc_id=rc_id' ] ],
'options' => [ 'ORDER BY rc_timestamp DESC', 'DISTINCT' ],
]
],
'recentchanges query with multiple tag filter with strings, avoiding reopening tables' => [
[
'tables' => 'recentchanges',
'fields' => 'rc_id',
'conds' => "rc_timestamp > '20170714183203'",
'join_conds' => [],
'options' => 'ORDER BY rc_timestamp DESC',
],
[ 'foo', 'bar' ],
true, // tag filtering enabled
true, // avoid reopening tables
[
'tables' => [ 'recentchanges', 'changetagdisplay' => 'change_tag' ],
'fields' => [ 'rc_id', 'ts_tags' => $groupConcats['recentchanges'] ],
'conds' => [ "rc_timestamp > '20170714183203'", 'changetagdisplay.ct_tag_id' => [ 1, 2 ] ],
'join_conds' => [ 'changetagdisplay' => [ 'JOIN', 'changetagdisplay.ct_rc_id=rc_id' ] ],
'options' => [ 'ORDER BY rc_timestamp DESC', 'DISTINCT' ],
]
],
];
}
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->overrideConfigValue( MainConfigNames::SoftwareTags, $softwareTags );
$actual = ChangeTags::getSoftwareTags();
// Order of tags in arrays is not important
sort( $expected );
sort( $actual );
$this->assertEquals( $expected, $actual );
}
public function testUpdateTags() {
$this->emptyChangeTagsTables();
$rcId = 123;
$revId = 341;
ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId, $revId );
$this->newSelectQueryBuilder()
->select( [ 'ctd_name', 'ctd_id', 'ctd_count' ] )
->from( 'change_tag_def' )
->assertResultSet( [
// values of fields 'ctd_name', 'ctd_id', 'ctd_count'
[ 'tag1', 1, 1 ],
[ 'tag2', 2, 1 ],
] );
$this->newSelectQueryBuilder()
->from( 'change_tag' )
->select( [ 'ct_tag_id', 'ct_rc_id', 'ct_rev_id' ] )
->assertResultSet( [
// values of fields 'ct_tag_id', 'ct_rc_id', 'ct_rev_id'
[ 1, 123, 341 ],
[ 2, 123, 341 ],
] );
$rcId = 124;
$revId = 342;
ChangeTags::updateTags( [ 'tag1' ], [], $rcId, $revId );
ChangeTags::updateTags( [ 'tag3' ], [], $rcId, $revId );
$this->newSelectQueryBuilder()
->select( [ 'ctd_name', 'ctd_id', 'ctd_count' ] )
->from( 'change_tag_def' )
->assertResultSet( [
// values of fields 'ctd_name', 'ctd_id', 'ctd_count'
[ 'tag1', 1, 2 ],
[ 'tag2', 2, 1 ],
[ 'tag3', 3, 1 ],
] );
$this->newSelectQueryBuilder()
->select( [ 'ct_tag_id', 'ct_rc_id', 'ct_rev_id' ] )
->from( 'change_tag' )
->assertResultSet( [
// values of fields 'ct_tag_id', 'ct_rc_id', 'ct_rev_id'
[ 1, 123, 341 ],
[ 1, 124, 342 ],
[ 2, 123, 341 ],
[ 3, 124, 342 ],
] );
}
public function testUpdateTagsSkipDuplicates() {
$this->emptyChangeTagsTables();
$rcId = 123;
ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
ChangeTags::updateTags( [ 'tag2', 'tag3' ], [], $rcId );
$this->newSelectQueryBuilder()
->select( [ 'ctd_name', 'ctd_id', 'ctd_count' ] )
->from( 'change_tag_def' )
->assertResultSet( [
// values of fields 'ctd_name', 'ctd_id', 'ctd_count'
[ 'tag1', 1, 1 ],
[ 'tag2', 2, 1 ],
[ 'tag3', 3, 1 ],
] );
$this->newSelectQueryBuilder()
->select( [ 'ct_tag_id', 'ct_rc_id' ] )
->from( 'change_tag' )
->assertResultSet( [
// values of fields 'ct_tag_id', 'ct_rc_id',
[ 1, 123 ],
[ 2, 123 ],
[ 3, 123 ],
] );
}
public function testUpdateTagsDoNothingOnRepeatedCall() {
$this->emptyChangeTagsTables();
$rcId = 123;
ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
$res = ChangeTags::updateTags( [ 'tag2', 'tag1' ], [], $rcId );
$this->assertEquals( [ [], [], [ 'tag1', 'tag2' ] ], $res );
$this->newSelectQueryBuilder()
->select( [ 'ctd_name', 'ctd_id', 'ctd_count' ] )
->from( 'change_tag_def' )
->assertResultSet( [
// values of fields 'ctd_name', 'ctd_id', 'ctd_count'
[ 'tag1', 1, 1 ],
[ 'tag2', 2, 1 ],
] );
$this->newSelectQueryBuilder()
->select( [ 'ct_tag_id', 'ct_rc_id' ] )
->from( 'change_tag' )
->assertResultSet( [
// values of fields 'ct_tag_id', 'ct_rc_id',
[ 1, 123 ],
[ 2, 123 ],
] );
}
public function testDeleteTags() {
$this->emptyChangeTagsTables();
$this->getServiceContainer()->resetServiceForTesting( 'NameTableStoreFactory' );
$rcId = 123;
ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
ChangeTags::updateTags( [], [ 'tag2' ], $rcId );
$this->newSelectQueryBuilder()
->select( [ 'ctd_name', 'ctd_id', 'ctd_count' ] )
->from( 'change_tag_def' )
->assertResultSet( [
// values of fields 'ctd_name', 'ctd_id', 'ctd_count'
[ 'tag1', 1, 1 ],
] );
$this->newSelectQueryBuilder()
->select( [ 'ct_tag_id', 'ct_rc_id' ] )
->from( 'change_tag' )
->assertResultSet( [
// values of fields 'ct_tag_id', 'ct_rc_id',
[ 1, 123 ],
] );
}
public static function provideTags() {
$tags = [ 'tag 1', 'tag 2', 'tag 3' ];
$rcId = 123;
$revId = 456;
$logId = 789;
yield [ $tags, $rcId, null, null ];
yield [ $tags, null, $revId, null ];
yield [ $tags, null, null, $logId ];
yield [ $tags, $rcId, $revId, null ];
yield [ $tags, $rcId, null, $logId ];
yield [ $tags, $rcId, $revId, $logId ];
}
/**
* @dataProvider provideTags
*/
public function testGetTags( array $tags, $rcId, $revId, $logId ) {
ChangeTags::addTags( $tags, $rcId, $revId, $logId );
$actualTags = ChangeTags::getTags( $this->getDb(), $rcId, $revId, $logId );
$this->assertSame( $tags, $actualTags );
}
public function testGetTags_multiple_arguments() {
$rcId = 123;
$revId = 456;
$logId = 789;
ChangeTags::addTags( [ 'tag 1' ], $rcId );
ChangeTags::addTags( [ 'tag 2' ], $rcId, $revId );
ChangeTags::addTags( [ 'tag 3' ], $rcId, $revId, $logId );
$tags3 = [ 'tag 3' ];
$tags2 = array_merge( $tags3, [ 'tag 2' ] );
$tags1 = array_merge( $tags2, [ 'tag 1' ] );
$this->assertArrayEquals( $tags3, ChangeTags::getTags( $this->getDb(), $rcId, $revId, $logId ) );
$this->assertArrayEquals( $tags2, ChangeTags::getTags( $this->getDb(), $rcId, $revId ) );
$this->assertArrayEquals( $tags1, ChangeTags::getTags( $this->getDb(), $rcId ) );
}
public function testGetTagsWithData() {
$rcId1 = 123;
$rcId2 = 456;
$rcId3 = 789;
ChangeTags::addTags( [ 'tag 1' ], $rcId1, null, null, 'data1' );
ChangeTags::addTags( [ 'tag 3_1' ], $rcId3, null, null );
ChangeTags::addTags( [ 'tag 3_2' ], $rcId3, null, null, 'data3_2' );
$data = ChangeTags::getTagsWithData( $this->getDb(), $rcId1 );
$this->assertSame( [ 'tag 1' => 'data1' ], $data );
$data = ChangeTags::getTagsWithData( $this->getDb(), $rcId2 );
$this->assertSame( [], $data );
$data = ChangeTags::getTagsWithData( $this->getDb(), $rcId3 );
$this->assertArrayEquals( [ 'tag 3_1' => null, 'tag 3_2' => 'data3_2' ], $data, false, true );
}
public function testTagUsageStatistics() {
$this->emptyChangeTagsTables();
$this->getServiceContainer()->resetServiceForTesting( 'NameTableStoreFactory' );
$rcId = 123;
ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
$rcId = 124;
ChangeTags::updateTags( [ 'tag1' ], [], $rcId );
$this->assertEquals( [ 'tag1' => 2, 'tag2' => 1 ], ChangeTags::tagUsageStatistics() );
}
public function testListExplicitlyDefinedTags() {
$this->emptyChangeTagsTables();
$rcId = 123;
ChangeTags::updateTags( [ 'tag1', 'tag2' ], [], $rcId );
ChangeTags::defineTag( 'tag2' );
$this->assertEquals( [ 'tag2' ], ChangeTags::listExplicitlyDefinedTags() );
$this->newSelectQueryBuilder()
->select( [ 'ctd_name', 'ctd_user_defined' ] )
->from( 'change_tag_def' )
->assertResultSet( [
// values of fields 'ctd_name', 'ctd_user_defined'
[ 'tag1', 0 ],
[ 'tag2', 1 ],
] );
}
public static function provideFormatSummaryRow() {
yield 'nothing' => [ '', [ '', [] ] ];
yield 'valid tag' => [
'tag1',
[
'<span class="mw-tag-markers">(tag-list-wrapper: 1, '
. '<span class="mw-tag-marker mw-tag-marker-tag1">(tag-tag1)</span>'
. ')</span>',
[ 'mw-tag-tag1' ]
]
];
yield '0 tag' => [
'0',
[
'<span class="mw-tag-markers">(tag-list-wrapper: 1, '
. '<span class="mw-tag-marker mw-tag-marker-0">(tag-0)</span>'
. ')</span>',
[ 'mw-tag-0' ]
]
];
yield 'hidden tag' => [
'hidden-tag',
[
'',
[ 'mw-tag-hidden-tag' ]
]
];
yield 'mutliple tags' => [
'tag1,0,,hidden-tag',
[
'<span class="mw-tag-markers">(tag-list-wrapper: 2, '
. '<span class="mw-tag-marker mw-tag-marker-tag1">(tag-tag1)</span>'
. ' <span class="mw-tag-marker mw-tag-marker-0">(tag-0)</span>'
. ')</span>',
[ 'mw-tag-tag1', 'mw-tag-0', 'mw-tag-hidden-tag' ]
]
];
}
/**
* @dataProvider provideFormatSummaryRow
*/
public function testFormatSummaryRow( $tags, $expected ) {
$qqx = new MockMessageLocalizer();
$localizer = $this->createMock( MessageLocalizer::class );
$localizer->method( 'msg' )
->willReturnCallback( static function ( $key, ...$params ) use ( $qqx ) {
if ( $key === 'tag-hidden-tag' ) {
return new RawMessage( '-' );
}
return $qqx->msg( $key, ...$params );
} );
$out = ChangeTags::formatSummaryRow( $tags, 'dummy', $localizer );
$this->assertSame( $expected, $out );
}
}

File Metadata

Mime Type
text/x-php
Expires
Aug 15 2026, 00:43 (12 w, 6 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
f7/9f/f70eb4b8c6afe2b557479c9d8c26
Default Alt Text
ChangeTagsTest.php (27 KB)

Event Timeline