Skip to content

Commit

Permalink
Add formatting for EntitySchema values
Browse files Browse the repository at this point in the history
Extend existing EntitySchemaFormatter to add support for
formatting EntitySchema IDs as plain text and wikitext.

Bug: T362001
Change-Id: I2fa7577318013f6ba7fe97fce1fa087632a5d371
  • Loading branch information
codders committed Apr 26, 2024
1 parent c1ebc64 commit 210685a
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 103 deletions.
41 changes: 38 additions & 3 deletions src/Wikibase/Formatters/EntitySchemaFormatter.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,50 @@ public function format( $value ) {
switch ( $snakFormat->getBaseFormat( $this->format ) ) {
case SnakFormatter::FORMAT_HTML:
return $this->makeHtmlLink( $entitySchemaId );
// TODO: case SnakFormatter::FORMAT_WIKI:
case SnakFormatter::FORMAT_WIKI:
return $this->makeWikiLink( $entitySchemaId );
case SnakFormatter::FORMAT_PLAIN:
// hacky hack to get schema values as links with labels on history, recent changes, etc
return "[[EntitySchema:$entitySchemaId]]";
return $this->makePlainText( $entitySchemaId );
default:
return $entitySchemaId;
}
}

private function makePlainText( string $entitySchemaId ): string {
$schemaPageIdentity = $this->titleFactory->newFromText( $entitySchemaId, NS_ENTITYSCHEMA_JSON );
if ( $schemaPageIdentity === null ) {
return $entitySchemaId;
}
$requestedLanguageCode = $this->options->getOption( ValueFormatter::OPT_LANG );
$labelTerm = $this->labelLookup->getLabelForTitle(
$schemaPageIdentity,
$requestedLanguageCode
);

if ( $labelTerm ) {
return $labelTerm->getText();
}
return $schemaPageIdentity->getText();
}

private function makeWikiLink( string $entitySchemaId ): string {
$schemaPageIdentity = $this->titleFactory->newFromText( $entitySchemaId, NS_ENTITYSCHEMA_JSON );
if ( $schemaPageIdentity === null ) {
return "[[EntitySchema:$entitySchemaId]]";
}
$requestedLanguageCode = $this->options->getOption( ValueFormatter::OPT_LANG );
$labelTerm = $this->labelLookup->getLabelForTitle(
$schemaPageIdentity,
$requestedLanguageCode
);

$linkTitle = 'EntitySchema:' . $entitySchemaId;
if ( $labelTerm ) {
return '[[' . $linkTitle . '|' . wfEscapeWikiText( $labelTerm->getText() ) . ']]';
}
return '[[' . $linkTitle . ']]';
}

private function makeHtmlLink( string $entitySchemaId ): string {
$linkTarget = new TitleValue( NS_ENTITYSCHEMA_JSON, $entitySchemaId );
$schemaPageIdentity = $this->titleFactory->newFromText( $entitySchemaId, NS_ENTITYSCHEMA_JSON );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@
use MediaWiki\Linker\LinkTarget;
use MediaWiki\Title\Title;
use MediaWiki\Title\TitleFactory;
use MediaWikiUnitTestCase;
use MediaWikiIntegrationTestCase;
use PHPUnit\Framework\MockObject\MockObject;
use ValueFormatters\FormatterOptions;
use ValueFormatters\ValueFormatter;
use Wikibase\DataModel\Term\TermFallback;
Expand All @@ -23,7 +24,28 @@
* @covers \EntitySchema\Wikibase\Formatters\EntitySchemaFormatter
* @license GPL-2.0-or-later
*/
class EntitySchemaFormatterTest extends MediaWikiUnitTestCase {
class EntitySchemaFormatterTest extends MediaWikiIntegrationTestCase {

/**
* @var LinkRenderer|MockObject
*/
private $mockLinkRenderer;

/**
* @var LabelLookup|MockObject
*/
private $mockLabelLookup;

/**
* @var TitleFactory|MockObject
*/
private $mockTitleFactory;

public function setUp(): void {
$this->mockLinkRenderer = $this->createMock( LinkRenderer::class );
$this->mockLabelLookup = $this->createMock( LabelLookup::class );
$this->mockTitleFactory = $this->createMock( TitleFactory::class );
}

public static function setUpBeforeClass(): void {
parent::setUpBeforeClass();
Expand All @@ -36,40 +58,95 @@ public static function setUpBeforeClass(): void {

public static function provideTextFormats(): iterable {
return [
[ SnakFormatter::FORMAT_PLAIN, '[[EntitySchema:E123]]' ],
[ SnakFormatter::FORMAT_WIKI, 'E123' ],
[ SnakFormatter::FORMAT_PLAIN, 'E984', 'English Label' ],
[ SnakFormatter::FORMAT_WIKI, '[[EntitySchema:E984]]', '[[EntitySchema:E984|English Label]]' ],
];
}

private function registerTitleWithLabel(
string $schemaId,
string $requestLangCode,
?TermFallback $label
): void {
$stubPageIdentity = $this->createMock( Title::class );
$stubPageIdentity->expects( $this->any() )
->method( 'getText' )
->willReturn( $schemaId );
$this->mockTitleFactory->expects( $this->once() )
->method( 'newFromText' )
->with( $schemaId, NS_ENTITYSCHEMA_JSON )
->willReturn( $stubPageIdentity );
$this->mockLabelLookup->expects( $this->once() )
->method( 'getLabelForTitle' )
->with(
$stubPageIdentity,
$requestLangCode
)
->willReturn( $label );
}

private function createFormatter(
string $format,
FormatterOptions $options,
bool $stubLanguageNameLookupFactory = true
): EntitySchemaFormatter {
$languageNameLookupFactory = $this->createStub( LanguageNameLookupFactory::class );
if ( $stubLanguageNameLookupFactory === false ) {
$languageNameLookupFactory = $this->createMock( LanguageNameLookupFactory::class );
$languageNameLookupFactory->expects( $this->never() )
->method( $this->anything() );
}
return new EntitySchemaFormatter(
$format,
$options,
$this->mockLinkRenderer,
$this->mockLabelLookup,
$this->mockTitleFactory,
$languageNameLookupFactory
);
}

/**
* @dataProvider provideTextFormats
*/
public function testUnhandledFormats( string $format, string $expectedResult ): void {
$linkRenderer = $this->createMock( LinkRenderer::class );
$linkRenderer->expects( $this->never() )
public function testTextFormatsNoLabel(
string $format,
string $expectedResultNoLabel,
string $expectedResultLabel
): void {
$schemaId = 'E984';
$this->mockLinkRenderer->expects( $this->never() )
->method( $this->anything() );
$options = new FormatterOptions( [ ValueFormatter::OPT_LANG => 'en' ] );
$mockLabelLookup = $this->createMock( LabelLookup::class );
$mockLabelLookup->expects( $this->never() )
->method( $this->anything() );
$mockTitleFactory = $this->createMock( TitleFactory::class );
$mockTitleFactory->expects( $this->never() )
->method( $this->anything() );
$languageNameLookupFactory = $this->createMock( LanguageNameLookupFactory::class );
$languageNameLookupFactory->expects( $this->never() )
->method( $this->anything() );
$sut = new EntitySchemaFormatter(
$format,
$options,
$linkRenderer,
$mockLabelLookup,
$mockTitleFactory,
$languageNameLookupFactory
$this->registerTitleWithLabel( $schemaId, 'en', null );
$sut = $this->createFormatter( $format, $options, false );

$this->assertSame(
$expectedResultNoLabel,
$sut->format( new EntitySchemaValue( new EntitySchemaId( $schemaId ) ) )
);
}

/**
* @dataProvider provideTextFormats
*/
public function testTextFormatsWithLabel(
string $format,
string $expectedResultNoLabel,
string $expectedResultLabel
): void {
$schemaId = 'E984';
$englishLabel = 'English Label';
$langCode = 'en';
$options = new FormatterOptions( [ ValueFormatter::OPT_LANG => $langCode ] );
$this->registerTitleWithLabel( $schemaId, 'en',
new TermFallback( $langCode, $englishLabel, $langCode, null ) );

$sut = $this->createFormatter( $format, $options, false );

$this->assertSame(
$expectedResult,
$sut->format( new EntitySchemaValue( new EntitySchemaId( 'E123' ) ) )
$expectedResultLabel,
$sut->format( new EntitySchemaValue( new EntitySchemaId( $schemaId ) ) )
);
}

Expand All @@ -86,39 +163,17 @@ public static function provideHtmlCases(): iterable {
public function testHtmlNoLabel( string $format ): void {
$schemaId = 'E123';
$options = new FormatterOptions( [ ValueFormatter::OPT_LANG => 'en' ] );
$stubPageIdentity = $this->createStub( Title::class );
$mockTitleFactory = $this->createMock( TitleFactory::class );
$mockTitleFactory->expects( $this->once() )
->method( 'newFromText' )
->with( $schemaId, NS_ENTITYSCHEMA_JSON )
->willReturn( $stubPageIdentity );
$stubLanguageNameLookupFactory = $this->createStub( LanguageNameLookupFactory::class );
$mockLabelLookup = $this->createMock( LabelLookup::class );
$mockLabelLookup->expects( $this->once() )
->method( 'getLabelForTitle' )
->with(
$stubPageIdentity,
'en'
)
->willReturn( null );
$this->registerTitleWithLabel( $schemaId, 'en', null );
$fakeLinkHtml = '<a>E123</a>';
$linkRenderer = $this->createMock( LinkRenderer::class );
$linkRenderer->expects( $this->once() )
$this->mockLinkRenderer->expects( $this->once() )
->method( 'makePreloadedLink' )
->with(
$this->callback( $this->getCallbackToAssertLinkTarget( $schemaId ) ),
$schemaId
)
->willReturn( $fakeLinkHtml );

$sut = new EntitySchemaFormatter(
$format,
$options,
$linkRenderer,
$mockLabelLookup,
$mockTitleFactory,
$stubLanguageNameLookupFactory
);
$sut = $this->createFormatter( $format, $options );

$this->assertSame( $fakeLinkHtml, $sut->format( new EntitySchemaValue( new EntitySchemaId( $schemaId ) ) ) );
}
Expand All @@ -131,24 +186,10 @@ public function testHtmlWithLabel( string $format ): void {
$englishLabel = 'English Label';
$langCode = 'en';
$options = new FormatterOptions( [ ValueFormatter::OPT_LANG => $langCode ] );
$stubPageIdentity = $this->createStub( Title::class );
$mockTitleFactory = $this->createMock( TitleFactory::class );
$mockTitleFactory->expects( $this->once() )
->method( 'newFromText' )
->with( $schemaId, NS_ENTITYSCHEMA_JSON )
->willReturn( $stubPageIdentity );
$stubLanguageNameLookupFactory = $this->createStub( LanguageNameLookupFactory::class );
$mockLabelLookup = $this->createMock( LabelLookup::class );
$mockLabelLookup->expects( $this->once() )
->method( 'getLabelForTitle' )
->with(
$stubPageIdentity,
'en'
)
->willReturn( new TermFallback( $langCode, $englishLabel, $langCode, null ) );
$this->registerTitleWithLabel( $schemaId, 'en',
new TermFallback( $langCode, $englishLabel, $langCode, null ) );
$fakeLinkHtml = '<a>English Label</a>';
$linkRenderer = $this->createMock( LinkRenderer::class );
$linkRenderer->expects( $this->once() )
$this->mockLinkRenderer->expects( $this->once() )
->method( 'makePreloadedLink' )
->with(
$this->callback( $this->getCallbackToAssertLinkTarget( $schemaId ) ),
Expand All @@ -158,14 +199,7 @@ public function testHtmlWithLabel( string $format ): void {
)
->willReturn( $fakeLinkHtml );

$sut = new EntitySchemaFormatter(
$format,
$options,
$linkRenderer,
$mockLabelLookup,
$mockTitleFactory,
$stubLanguageNameLookupFactory
);
$sut = $this->createFormatter( $format, $options );

$this->assertSame( $fakeLinkHtml, $sut->format( new EntitySchemaValue( new EntitySchemaId( $schemaId ) ) ) );
}
Expand All @@ -179,24 +213,11 @@ public function testHtmlWithFallbackLabel( string $format ): void {
$langCode = 'en';
$requestLangCode = 'de';
$options = new FormatterOptions( [ ValueFormatter::OPT_LANG => $requestLangCode ] );
$stubPageIdentity = $this->createStub( Title::class );
$mockTitleFactory = $this->createMock( TitleFactory::class );
$mockTitleFactory->expects( $this->once() )
->method( 'newFromText' )
->with( $schemaId, NS_ENTITYSCHEMA_JSON )
->willReturn( $stubPageIdentity );
$stubLanguageNameLookupFactory = $this->createStub( LanguageNameLookupFactory::class );
$mockLabelLookup = $this->createMock( LabelLookup::class );
$mockLabelLookup->expects( $this->once() )
->method( 'getLabelForTitle' )
->with(
$stubPageIdentity,
$requestLangCode
)
->willReturn( new TermFallback( $requestLangCode, $englishLabel, $langCode, null ) );
$this->registerTitleWithLabel( $schemaId, $requestLangCode,
new TermFallback( $requestLangCode, $englishLabel, $langCode, null ) );

$fakeLinkHtml = '<a>English Label</a>';
$linkRenderer = $this->createMock( LinkRenderer::class );
$linkRenderer->expects( $this->once() )
$this->mockLinkRenderer->expects( $this->once() )
->method( 'makePreloadedLink' )
->with(
$this->callback( $this->getCallbackToAssertLinkTarget( $schemaId ) ),
Expand All @@ -206,14 +227,7 @@ public function testHtmlWithFallbackLabel( string $format ): void {
)
->willReturn( $fakeLinkHtml );

$sut = new EntitySchemaFormatter(
$format,
$options,
$linkRenderer,
$mockLabelLookup,
$mockTitleFactory,
$stubLanguageNameLookupFactory
);
$sut = $this->createFormatter( $format, $options );

// expect that LanguageFallbackIndicator adds some element after the main HTML,
// without asserting its exact contents
Expand Down

0 comments on commit 210685a

Please sign in to comment.