| Current File : /home/jvzmxxx/wiki/extensions/Wikibase/client/tests/phpunit/includes/LangLinkHandlerTest.php |
<?php
namespace Wikibase\Client\Tests;
use HashSiteStore;
use ParserOutput;
use Site;
use TestSites;
use Title;
use Wikibase\Client\Hooks\LanguageLinkBadgeDisplay;
use Wikibase\DataModel\Entity\Item;
use Wikibase\DataModel\Entity\ItemId;
use Wikibase\DataModel\SiteLink;
use Wikibase\LangLinkHandler;
use Wikibase\NamespaceChecker;
use Wikibase\NoLangLinkHandler;
use Wikibase\Lib\Tests\MockRepository;
/**
* @covers Wikibase\LangLinkHandler
*
* @group WikibaseClient
* @group Wikibase
* @group Database
*
* @license GPL-2.0+
* @author Daniel Kinzler
*/
class LangLinkHandlerTest extends \MediaWikiTestCase {
/**
* @var MockRepository|null
*/
private $mockRepo = null;
/**
* @var LangLinkHandler
*/
private $langLinkHandler;
private function getItems() {
$items = array();
$item = new Item( new ItemId( 'Q1' ) );
$item->setLabel( 'en', 'Foo' );
$links = $item->getSiteLinkList();
$links->addNewSiteLink( 'dewiki', 'Foo de' );
$links->addNewSiteLink( 'enwiki', 'Foo en', array( new ItemId( 'Q17' ) ) );
$links->addNewSiteLink( 'srwiki', 'Foo sr' );
$links->addNewSiteLink( 'dewiktionary', 'Foo de word' );
$links->addNewSiteLink( 'enwiktionary', 'Foo en word' );
$items[] = $item;
$item = new Item( new ItemId( 'Q2' ) );
$item->setLabel( 'en', 'Talk:Foo' );
$links = $item->getSiteLinkList();
$links->addNewSiteLink( 'dewiki', 'Talk:Foo de' );
$links->addNewSiteLink( 'enwiki', 'Talk:Foo en' );
$links->addNewSiteLink( 'srwiki', 'Talk:Foo sr' );
$items[] = $item;
return $items;
}
protected function setUp() {
parent::setUp();
$this->langLinkHandler = $this->getLangLinkHandler();
}
/**
* @return LangLinkHandler
*/
private function getLangLinkHandler() {
$this->mockRepo = new MockRepository();
foreach ( $this->getItems() as $item ) {
$this->mockRepo->putEntity( $item );
}
$siteStore = new HashSiteStore( TestSites::getSites() );
return new LangLinkHandler(
$this->getLanguageLinkBadgeDisplay(),
new NamespaceChecker( array( NS_TALK ) ),
$this->mockRepo,
$this->mockRepo,
$siteStore,
'srwiki',
'wikipedia'
);
}
/**
* @return LanguageLinkBadgeDisplay
*/
private function getLanguageLinkBadgeDisplay() {
$badgeDisplay = $this->getMockBuilder( LanguageLinkBadgeDisplay::class )
->disableOriginalConstructor()
->getMock();
$badgeDisplay->expects( $this->any() )
->method( 'attachBadgesToOutput' )
->will( $this->returnCallback( function ( array $siteLinks, ParserOutput $parserOutput ) {
$badges = $this->linksToBadges( $siteLinks );
$parserOutput->setExtensionData( 'wikibase_badges', $badges );
} ) );
return $badgeDisplay;
}
/**
* @param SiteLink[] $siteLinks
*
* @return string[]
*/
public function linksToBadges( array $siteLinks ) {
$badgesByPrefix = array();
foreach ( $siteLinks as $link ) {
$badges = $link->getBadges();
if ( empty( $badges ) ) {
continue;
}
// strip "wiki" suffix
$key = preg_replace( '/wiki$/', '', $link->getSiteId() );
$badgesByPrefix[$key] = array_map( function( ItemId $id ) {
return $id->getSerialization();
}, $badges );
}
return $badgesByPrefix;
}
public function provideGetEntityLinks() {
return array(
array( // #0
'Xoo', // page
array() // expected links
),
array( // #1
'Foo_sr', // page
array( // expected links
'dewiki' => 'Foo de',
'enwiki' => 'Foo en',
'srwiki' => 'Foo sr',
'dewiktionary' => 'Foo de word',
'enwiktionary' => 'Foo en word',
)
),
);
}
/**
* @dataProvider provideGetEntityLinks
*/
public function testGetEntityLinks( $title, array $expectedLinks ) {
if ( is_string( $title ) ) {
$title = Title::newFromText( $title );
}
$links = array();
foreach ( $this->langLinkHandler->getEntityLinks( $title ) as $link ) {
$links[$link->getSiteId()] = $link->getPageName();
}
$this->assertArrayEquals( $expectedLinks, $links, false, true );
}
public function provideGetNoExternalLangLinks() {
return array(
array( // #0
array()
),
array( // #1
array( '*' )
),
array( // #2
array( 'de' )
),
array( // #3
array( 'xy', 'de', 'en' )
),
);
}
protected function makeParserOutput( array $langLinks, array $noExternalLangLinks = array() ) {
$out = new ParserOutput();
NoLangLinkHandler::setNoExternalLangLinks( $out, $noExternalLangLinks );
foreach ( $langLinks as $lang => $link ) {
$out->addLanguageLink( "$lang:$link" );
}
return $out;
}
/**
* @dataProvider provideGetNoExternalLangLinks
*/
public function testGetNoExternalLangLinks( array $noExternalLangLinks ) {
$out = $this->makeParserOutput( array(), $noExternalLangLinks );
$nel = $this->langLinkHandler->getNoExternalLangLinks( $out );
$this->assertEquals( $noExternalLangLinks, $nel );
}
public function provideExcludeRepoLinks() {
return array(
array( // #0
array(),
array(),
array()
),
array( // #1
array( 'de' ),
array( 'cs' ),
array( 'de', 'cs' )
),
array(
array( 'de' ),
array( '*' ),
array( 'de', '*' )
),
array( // #3
array( 'xy', 'de', 'en' ),
array(),
array( 'xy', 'de', 'en' )
)
);
}
public function provideUseRepoLinks() {
return array(
array( // #0
'Foo_sr',
array(),
true
),
array( // #1
'Foo_sr',
array( '*' ),
false
),
array( // #2
'Foo_sr',
array( 'de' ),
true
),
array( // #3
'Talk:Foo_sr',
array(),
false
),
);
}
/**
* @dataProvider provideUseRepoLinks
*/
public function testUseRepoLinks( $title, array $noExternalLangLinks, $expected ) {
if ( is_string( $title ) ) {
$title = Title::newFromText( $title );
$title->resetArticleID( 1 );
}
$out = $this->makeParserOutput( array(), $noExternalLangLinks );
$useRepoLinks = $this->langLinkHandler->useRepoLinks( $title, $out );
$this->assertEquals( $expected, $useRepoLinks, "use repository links" );
}
public function provideGetEffectiveRepoLinks() {
return array(
array( // #0: local overrides remote
'Foo_sr', // title
array( // langlinks
'de' => 'Xoo de',
'nl' => 'Foo nl',
),
array( // noexternallinks
),
array( // expectedLinks
'enwiki' => 'Foo en',
)
),
array( // #1: namespace not covered
'Talk:Foo_sr', // title
array( // langlinks
'de' => 'Talk:Foo de',
'nl' => 'Talk:Foo nl',
),
array( // noexternallinks
),
array( // expectedLinks
)
),
array( // #2: disabled
'Foo_sr', // title
array( // langlinks
'de' => 'Foo de',
'nl' => 'Foo nl',
),
array( // noexternallinks
'*'
),
array( // expectedLinks
)
),
array( // #3: suppressed
'Foo_sr', // title
array( // langlinks
'de' => 'Foo de',
'nl' => 'Foo nl',
),
array( // noexternallinks
'en'
),
array( // expectedLinks
)
),
array( // #4: suppressed redundantly
'Foo_sr', // title
array( // langlinks
'de' => 'Foo de',
'nl' => 'Foo nl',
),
array( // noexternallinks
'de'
),
array( // expectedLinks
'enwiki' => 'Foo en',
)
),
);
}
/**
* @dataProvider provideGetEffectiveRepoLinks
*/
public function testGetEffectiveRepoLinks(
$title,
array $langLinks,
array $noExternalLangLinks,
array $expectedLinks
) {
if ( is_string( $title ) ) {
$title = Title::newFromText( $title );
}
$out = $this->makeParserOutput( $langLinks, $noExternalLangLinks );
$links = $this->langLinkHandler->getEffectiveRepoLinks( $title, $out );
$links = $this->getPlainLinks( $links );
$this->assertArrayEquals( $expectedLinks, $links, false, true );
}
/**
* @param SiteLink[] $links
*
* @return array
*/
private function getPlainLinks( array $links ) {
$flat = array();
foreach ( $links as $link ) {
$key = $link->getSiteId();
$flat[$key] = $link->getPageName();
}
return $flat;
}
public function provideAddLinksFromRepository() {
$cases = $this->provideGetEffectiveRepoLinks();
$badges = array(
// as defined by getItems()
'Foo_en' => array(
'en' => array( 'Q17' ),
),
'Foo_sr' => array(
'en' => array( 'Q17' ),
),
);
foreach ( $cases as $i => $case ) {
// convert associative array to list of links
$langLinks = $this->mapToLinks( $case[1] );
$expectedLinks = $this->mapToLinks( $case[3] );
// expect the expected effective links plus the provided language links
$expectedLinks = array_merge( $expectedLinks, $langLinks );
if ( !in_array( '*', $case[2] ) ) {
$expectedBadges = isset( $badges[ $case[0] ] ) ? $badges[ $case[0] ] : array();
// no badges for languages mentioned in $noExternalLangLinks
$expectedBadges = array_diff_key( $expectedBadges, array_flip( $case[2] ) );
} else {
$expectedBadges = array();
}
$cases[$i] = array(
$case[0],
$case[1],
$case[2],
$expectedLinks,
$expectedBadges
);
}
return $cases;
}
/**
* @dataProvider provideAddLinksFromRepository
*/
public function testAddLinksFromRepository(
$title,
array $langLinks,
array $noExternalLangLinks,
array $expectedLinks,
array $expectedBadges
) {
if ( is_string( $title ) ) {
$title = Title::newFromText( $title );
}
$out = $this->makeParserOutput( $langLinks, $noExternalLangLinks );
$this->langLinkHandler->addLinksFromRepository( $title, $out );
$this->assertArrayEquals( $expectedLinks, $out->getLanguageLinks(), false, false );
$this->assertArrayEquals( $expectedBadges, $out->getExtensionData( 'wikibase_badges' ), false, true );
}
protected function mapToLinks( $map ) {
$links = array();
foreach ( $map as $wiki => $page ) {
$lang = preg_replace( '/wiki$/', '', $wiki );
$links[] = "$lang:$page";
}
return $links;
}
public function provideFilterRepoLinksByGroup() {
return array(
array( // #0: nothing
array(), array(), array()
),
array( // #1: nothing allowed
array(
'dewiki' => 'Foo de',
'enwiki' => 'Foo en',
'srwiki' => 'Foo sr',
'dewiktionary' => 'Foo de word',
'enwiktionary' => 'Foo en word',
),
array(),
array()
),
array( // #2: nothing there
array(),
array( 'wikipedia' ),
array()
),
array( // #3: wikipedia only
array(
'dewiki' => 'Foo de',
'enwiki' => 'Foo en',
'srwiki' => 'Foo sr',
'dewiktionary' => 'Foo de word',
'enwiktionary' => 'Foo en word',
),
array( 'wikipedia' ),
array(
'dewiki' => 'Foo de',
'enwiki' => 'Foo en',
'srwiki' => 'Foo sr',
),
),
);
}
/**
* @dataProvider provideFilterRepoLinksByGroup
*/
public function testFilterRepoLinksByGroup(
array $repoLinks,
array $allowedGroups,
array $expectedLinks
) {
$actualLinks = $this->langLinkHandler->filterRepoLinksByGroup( $repoLinks, $allowedGroups );
$this->assertEquals( $expectedLinks, $actualLinks );
}
public function provideSuppressRepoLinks() {
return array(
array( // #0: nothing
array(), array(), array()
),
array( // #1: nothing allowed
array(
'dewiki' => 'Foo de',
'enwiki' => 'Foo en',
'srwiki' => 'Foo sr',
'dewiktionary' => 'Foo de word',
'enwiktionary' => 'Foo en word',
),
array( '*' ),
array()
),
array( // #2: nothing there
array(),
array( 'de' ),
array()
),
array( // #3: no de
array(
'dewiki' => 'Foo de',
'enwiki' => 'Foo en',
'srwiki' => 'Foo sr',
'enwiktionary' => 'Foo en word',
),
array( 'de' ),
array(
'enwiki' => 'Foo en',
//NOTE: srwiki is removed because that's a self-link
'enwiktionary' => 'Foo en word',
),
),
);
}
/**
* @dataProvider provideSuppressRepoLinks
*/
public function testSuppressRepoLinks( array $repoLinks, array $nel, array $expectedLinks ) {
$out = new ParserOutput();
$out->setProperty( 'noexternallanglinks', serialize( $nel ) );
$actualLinks = $this->langLinkHandler->suppressRepoLinks( $out, $repoLinks );
$this->assertEquals( $expectedLinks, $actualLinks );
}
/**
* @dataProvider getInterwikiCodeFromSiteProvider
*/
public function testGetInterwikiCodeFromSite( $site, $expected ) {
$interwikiCode = $this->langLinkHandler->getInterwikiCodeFromSite( $site );
$this->assertEquals( $expected, $interwikiCode, 'interwiki code matches' );
}
public function getInterwikiCodeFromSiteProvider() {
$enwiki = new Site();
$enwiki->setGlobalId( 'enwiki' );
$enwiki->setLanguageCode( 'en' );
$bexold = new Site();
$bexold->setGlobalId( 'be_x_oldwiki' );
$bexold->setLanguageCode( 'be-x-old' );
$dewikivoyage = new Site();
$dewikivoyage->setGlobalId( 'dewikivoyage' );
$dewikivoyage->setLanguageCode( 'de' );
return array(
array( $enwiki, 'en' ),
array( $bexold, 'be-x-old' ),
array( $dewikivoyage, 'de' )
);
}
}