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]

  1. hi ho
EOT; $editedHtml = <<Ha ha [1]

  1. hi ho
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 ); } }