mediawiki-extensions-Cite/tests/phpunit/integration/FootnoteMarkFormatterTest.php
Adam Wight 87d1229bf2 Expose the footnote mark formatter label method
Behavior change: previously, an error would be rendered once the
custom markers run out. After this patch there is a graceful fallback
to default group rendering (eg. "lower-greek 1000").
This is a slight improvement, but is user-facing so should be
discussed before merging.

In future work we'll render custom marks programmatically so this edge
case would be unreachable, and since the error message only exists to
nudge editors to extend the custom group symbol sequence, this would
also become wasted effort.

This patch splits out a lower-level method which produces the bare
mark label, with no link or wikitext formatting.  The patch narrows
and simplifies the interface so that the method can be made available
to Parsoid, and will be converted to a service in a separate patch.

Bug: T377454
Change-Id: I719b60b46cdef0be7463d76e9125d75ab4f333ae
2024-10-30 12:14:10 +01:00

174 lines
4.7 KiB
PHP

<?php
namespace Cite\Tests\Integration;
use Cite\AnchorFormatter;
use Cite\Cite;
use Cite\FootnoteMarkFormatter;
use Cite\ReferenceMessageLocalizer;
use Cite\Tests\TestUtils;
use MediaWiki\Message\Message;
use MediaWiki\Parser\Parser;
use Wikimedia\TestingAccessWrapper;
/**
* @covers \Cite\FootnoteMarkFormatter
* @license GPL-2.0-or-later
*/
class FootnoteMarkFormatterTest extends \MediaWikiIntegrationTestCase {
/**
* @dataProvider provideLinkRef
*/
public function testLinkRef( array $ref, string $expectedOutput ) {
$anchorFormatter = $this->createMock( AnchorFormatter::class );
$anchorFormatter->method( 'jumpLink' )->willReturnArgument( 0 );
$anchorFormatter->method( 'backLinkTarget' )->willReturnCallback(
static fn ( ...$args ) => implode( '+', $args )
);
$messageLocalizer = $this->createMock( ReferenceMessageLocalizer::class );
$messageLocalizer->method( 'localizeSeparators' )->willReturnArgument( 0 );
$messageLocalizer->method( 'localizeDigits' )->willReturnArgument( 0 );
$messageLocalizer->method( 'msg' )->willReturnCallback(
function ( $key, ...$params ) {
$customizedGroup = $key === 'cite_link_label_group-foo';
$msg = $this->createMock( Message::class );
$msg->method( 'isDisabled' )->willReturn( !$customizedGroup );
$msg->method( 'plain' )->willReturn( $customizedGroup
? 'a b c'
: "($key|" . implode( '|', $params ) . ')'
);
return $msg;
}
);
$mockParser = $this->createNoOpMock( Parser::class, [ 'recursiveTagParse' ] );
$mockParser->method( 'recursiveTagParse' )->willReturnArgument( 0 );
$formatter = new FootnoteMarkFormatter(
$anchorFormatter,
$messageLocalizer
);
$ref = TestUtils::refFromArray( $ref );
$output = $formatter->linkRef( $mockParser, $ref );
$this->assertSame( $expectedOutput, $output );
}
public static function provideLinkRef() {
return [
'Default label' => [
[
'name' => null,
'group' => '',
'number' => 50003,
'key' => 50004,
],
'(cite_reference_link|50004+|50004|50003)'
],
'Default label, named group' => [
[
'name' => null,
'group' => 'bar',
'number' => 3,
'key' => 4,
],
'(cite_reference_link|4+|4|bar 3)'
],
'Custom label' => [
[
'name' => null,
'group' => 'foo',
'number' => 3,
'key' => 4,
],
'(cite_reference_link|4+|4|c)'
],
'Custom label overrun' => [
[
'name' => null,
'group' => 'foo',
'number' => 10,
'key' => 4,
],
'(cite_reference_link|4+|4|foo 10)'
],
'Named ref' => [
[
'name' => 'a',
'group' => '',
'number' => 3,
'key' => 4,
'count' => 1,
],
'(cite_reference_link|a+4-0|a-4|3)'
],
'Named ref reused' => [
[
'name' => 'a',
'group' => '',
'number' => 3,
'key' => 4,
'count' => 50002,
],
'(cite_reference_link|a+4-50001|a-4|3)'
],
'Subreference' => [
[
'name' => null,
'group' => '',
'number' => 3,
'key' => 4,
'extends' => 'b',
'extendsIndex' => 50002,
],
'(cite_reference_link|4+|4|3.50002)'
],
];
}
/**
* @dataProvider provideCustomizedLinkLabels
*/
public function testFetchCustomizedLinkLabel( $expectedLabel, $offset, $group, $labelList ) {
$mockMessageLocalizer = $this->createMock( ReferenceMessageLocalizer::class );
$mockMessageLocalizer->method( 'msg' )->willReturnCallback(
function ( ...$args ) use ( $labelList ) {
$msg = $this->createMock( Message::class );
$msg->method( 'isDisabled' )->willReturn( $labelList === null );
$msg->method( 'plain' )->willReturn( $labelList );
return $msg;
}
);
/** @var FootnoteMarkFormatter $formatter */
$formatter = TestingAccessWrapper::newFromObject( new FootnoteMarkFormatter(
$this->createMock( AnchorFormatter::class ),
$mockMessageLocalizer
) );
$output = $formatter->fetchCustomizedLinkLabel( $group, $offset );
$this->assertSame( $expectedLabel, $output );
}
public static function provideCustomizedLinkLabels() {
yield [ null, 1, '', null ];
yield [ null, 2, '', null ];
yield [ null, 1, 'foo', null ];
yield [ null, 2, 'foo', null ];
yield [ 'a', 1, 'foo', 'a b c' ];
yield [ 'b', 2, 'foo', 'a b c' ];
yield [ 'å', 1, 'foo', 'å β' ];
yield [ null, 4, 'foo', 'a b c' ];
}
public function testDefaultGroupCannotHaveCustomLinkLabels() {
/** @var FootnoteMarkFormatter $formatter */
$formatter = TestingAccessWrapper::newFromObject( new FootnoteMarkFormatter(
$this->createNoOpMock( AnchorFormatter::class ),
// Assert that ReferenceMessageLocalizer::msg( 'cite_link_label_group-' ) isn't called
$this->createNoOpMock( ReferenceMessageLocalizer::class )
) );
$this->assertNull( $formatter->fetchCustomizedLinkLabel( Cite::DEFAULT_GROUP, 1 ) );
}
}