overrideConfigValue( 'CiteResponsiveReferences', true );
$this->overrideConfigValue( 'CiteResponsiveReferencesThreshold', 10 );
}
private function getSiteConfig( $options ) {
$objectFactory = $this->getServiceContainer()->getObjectFactory();
$siteConfig = new class( $options, $objectFactory ) extends MockSiteConfig {
private ObjectFactory $objectFactory;
public function __construct(
array $opts,
ObjectFactory $objectFactory
) {
parent::__construct( $opts );
$this->objectFactory = $objectFactory;
}
public function getObjectFactory(): ObjectFactory {
return $this->objectFactory;
}
};
// Ensure that the Cite module is registered!
$extensionParsoidModules =
ExtensionRegistry::getInstance()->getAttribute( 'ParsoidModules' );
foreach ( $extensionParsoidModules as $configOrSpec ) {
$siteConfig->registerExtensionModule( $configOrSpec );
}
return $siteConfig;
}
/**
* @param string $wt
* @param array $pageOpts
* @param bool $wrapSections
* @return Element
*/
private function parseWT( string $wt, array $pageOpts = [], $wrapSections = false ): Element {
$siteConfig = $this->getSiteConfig( [] );
$dataAccess = new MockDataAccess( $siteConfig, [] );
$parsoid = new Parsoid( $siteConfig, $dataAccess );
$content = new MockPageContent( [ 'main' => $wt ] );
$pageConfig = new MockPageConfig( $siteConfig, $pageOpts, $content );
$html = $parsoid->wikitext2html( $pageConfig, [ "wrapSections" => $wrapSections ] );
$doc = DOMUtils::parseHTML( $html );
$docBody = DOMCompat::getBody( $doc );
return( $docBody );
}
private function wtToLint( string $wt, array $options = [] ): array {
$opts = [
'prefix' => $options['prefix'] ?? 'enwiki',
'pageName' => $options['pageName'] ?? 'main',
'wrapSections' => false
];
$siteOptions = [ 'linting' => true ] + $options;
$siteConfig = $this->getSiteConfig( $siteOptions );
$dataAccess = new class( $siteConfig, [] ) extends MockDataAccess {
/** @inheritDoc */
public function addTrackingCategory(
PageConfig $pageConfig,
ContentMetadataCollector $metadata,
string $key
): void {
if ( $key === 'cite-tracking-category-cite-error' ) {
$tv = TitleValue::tryNew( 14, 'Pages with reference errors' );
$metadata->addCategory( $tv );
return;
}
parent::addTrackingCategory( $pageConfig, $metadata, $key );
}
};
$parsoid = new Parsoid( $siteConfig, $dataAccess );
$content = new MockPageContent( [ $opts['pageName'] => $wt ] );
$pageConfig = new MockPageConfig( $siteConfig, [], $content );
return $parsoid->wikitext2lint( $pageConfig, [] );
}
/**
* Wikilinks use ./ prefixed urls. For reasons of consistency,
* we should use a similar format for internal cite urls.
* This spec ensures that we don't inadvertently break that requirement.
* should use ./ prefixed urls for cite links
* @covers \Wikimedia\Parsoid\Wt2Html\ParserPipeline
*/
public function testWikilinkUseDotSlashPrefix(): void {
$description = "Regression Specs: should use ./ prefixed urls for cite links";
$wt = "a [[Foo]] [b]";
$docBody = $this->parseWT( $wt, [ 'title' => 'Main_Page' ] );
$attrib = DOMCompat::getAttribute(
DOMCompat::querySelectorAll( $docBody, ".mw-ref a" )[0],
'href'
);
$this->assertEquals( './Main_Page#cite_note-1', $attrib, $description );
$attrib = DOMCompat::getAttribute(
DOMCompat::querySelectorAll( $docBody, "#cite_note-1 a" )[0],
'href'
);
$this->assertEquals( './Main_Page#cite_ref-1', $attrib, $description );
}
/**
* I1f572f996a7c2b3b852752f5348ebb60d8e21c47 introduced a backwards
* incompatibility. This test asserts that selser will restore content
* for invalid follows that would otherwise be dropped since it wasn't
* span wrapped.
* @covers \Cite\Parsoid\Ref::domToWikitext
*/
public function testSelserFollowsWrap(): void {
$wt = 'Hi ho [hi ho]';
$html = <<Hi ho [1]
EOT;
$editedHtml = <<Ha ha [1]
EOT;
$siteConfig = $this->getSiteConfig( [] );
$dataAccess = new MockDataAccess( $siteConfig, [] );
$parsoid = new Parsoid( $siteConfig, $dataAccess );
$content = new MockPageContent( [ 'main' => $wt ] );
$pageConfig = new MockPageConfig( $siteConfig, [], $content );
// Without selser
$editedWt = $parsoid->html2wikitext( $pageConfig, $editedHtml, [], null );
$this->assertEquals( "Ha ha \n\n", $editedWt );
// // With selser
$selserData = new SelserData( $wt, $html );
$editedWt = $parsoid->html2wikitext( $pageConfig, $editedHtml, [], $selserData );
$this->assertEquals( "Ha ha [hi ho]\n\n", $editedWt );
}
/**
* @covers \Wikimedia\Parsoid\Wt2Html\ParserPipeline
*/
public function testLintIssueInRefTags(): void {
$desc = "should attribute linter issues to the ref tag";
$result = $this->wtToLint( "a [x] " );
$this->assertCount( 1, $result, $desc );
$this->assertEquals( 'missing-end-tag', $result[0]['type'], $desc );
$this->assertEquals( [ 7, 11, 3, 0 ], $result[0]['dsr'], $desc );
$this->assertTrue( isset( $result[0]['params'] ), $desc );
$this->assertEquals( 'b', $result[0]['params']['name'], $desc );
$desc = "should attribute linter issues to the ref tag even if references is templated";
$result = $this->wtToLint( "a [x] {{1x|}}" );
$this->assertCount( 1, $result, $desc );
$this->assertEquals( 'missing-end-tag', $result[0]['type'], $desc );
$this->assertEquals( [ 7, 11, 3, 0 ], $result[0]['dsr'], $desc );
$this->assertTrue( isset( $result[0]['params'] ), $desc );
$this->assertEquals( 'b', $result[0]['params']['name'], $desc );
$desc = "should attribute linter issues to the ref tag even when " .
"ref and references are both templated";
$wt = "a [x] b [{{1x|x}}] " .
"{{1x|c [y]}} {{1x|}}";
$result = $this->wtToLint( $wt );
$this->assertCount( 3, $result, $desc );
$this->assertEquals( 'missing-end-tag', $result[0]['type'], $desc );
$this->assertEquals( [ 7, 11, 3, 0 ], $result[0]['dsr'], $desc );
$this->assertTrue( isset( $result[0]['params'] ), $desc );
$this->assertEquals( 'b', $result[0]['params']['name'], $desc );
$this->assertEquals( 'missing-end-tag', $result[1]['type'], $desc );
$this->assertEquals( [ 25, 36, null, null ], $result[1]['dsr'], $desc );
$this->assertTrue( isset( $result[1]['params'] ), $desc );
$this->assertEquals( 'b', $result[1]['params']['name'], $desc );
$this->assertTrue( isset( $result[1]['templateInfo'] ), $desc );
$this->assertEquals( 'Template:1x', $result[1]['templateInfo']['name'], $desc );
$this->assertEquals( 'missing-end-tag', $result[2]['type'], $desc );
$this->assertEquals( [ 43, 67, null, null ], $result[2]['dsr'], $desc );
$this->assertTrue( isset( $result[2]['params'] ), $desc );
$this->assertEquals( 'b', $result[2]['params']['name'], $desc );
$this->assertTrue( isset( $result[2]['templateInfo'] ), $desc );
$this->assertEquals( 'Template:1x', $result[2]['templateInfo']['name'], $desc );
$desc = "should attribute linter issues properly when ref " .
"tags are in non-templated references tag";
$wt = "a x b " .
"[{{1x|boo}}] ";
$result = $this->wtToLint( $wt );
$this->assertCount( 2, $result, $desc );
$this->assertEquals( 'missing-end-tag', $result[0]['type'], $desc );
$this->assertEquals( [ 7, 11, 3, 0 ], $result[0]['dsr'], $desc );
$this->assertTrue( isset( $result[0]['params'] ), $desc );
$this->assertEquals( 's', $result[0]['params']['name'], $desc );
$this->assertEquals( 'missing-end-tag', $result[1]['type'], $desc );
$this->assertEquals( [ 64, 77, null, null ], $result[1]['dsr'], $desc );
$this->assertTrue( isset( $result[1]['params'] ), $desc );
$this->assertEquals( 'b', $result[1]['params']['name'], $desc );
$this->assertTrue( isset( $result[1]['templateInfo'] ), $desc );
$this->assertEquals( 'Template:1x', $result[1]['templateInfo']['name'], $desc );
$desc = "should lint inside ref with redefinition";
$wt = "[123]\n" .
"345\n" .
"";
$result = $this->wtToLint( $wt );
$this->assertCount( 1, $result, $desc );
$this->assertEquals( 'missing-end-tag', $result[0]['type'], $desc );
$this->assertEquals( [ 44, 50, 3, 0 ], $result[0]['dsr'], $desc );
$this->assertTrue( isset( $result[0]['params'] ), $desc );
$this->assertEquals( 's', $result[0]['params']['name'], $desc );
$desc = "should not get into a cycle trying to lint ref in ref";
$result = $this->wtToLint(
"{{#tag:ref||name='x'}}{{#tag:ref||name='y'}}"
);
$this->wtToLint( "{{#tag:ref||name=x}}" );
}
/**
* @covers \Cite\Parsoid\References::processAttributeEmbeddedHTML
*/
public function testProcessAttributeEmbeddedHTML() {
$doc = DOMUtils::parseHTML( '' );
DOMDataUtils::prepareDoc( $doc );
$elt = $doc->createElement( 'a' );
DOMDataUtils::setDataMw( $elt, new DataMw( [ 'body' => (object)[ 'html' => 'old' ] ] ) );
$refs = new References( $this->createNoOpMock( Config::class ) );
$refs->processAttributeEmbeddedHTML(
$this->createNoOpMock( ParsoidExtensionAPI::class ),
$elt,
fn () => 'new'
);
$this->assertSame( 'new', DOMDataUtils::getDataMw( $elt )->body->html );
}
}