mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/DiscussionTools
synced 2024-11-16 20:58:28 +00:00
25272e7a4a
These changes ensure that DiscussionTools is independent of DOM library choice, and will not break if/when Parsoid switches to an alternate (more standards-compliant) DOM library. We run `phan` against the Dodo standards-compliant DOM library, so this ends up flagging uses of non-standard PHP extensions to the DOM. These will be suppressed for now with a "Nonstandard DOM" comment that can be grepped for, since they will eventually will need to be rewritten or worked around. Most frequent issues: * Node::nodeValue and Node::textContent and Element::getAttribute() can return null in a spec-compliant implementation. Add `?? ''` to make spec-compliant results consistent w/ what PHP returns. * DOMXPath doesn't accept anything except DOMDocument. These uses should be replaced with DOMCompat::querySelectorAll() or similar (which end up using DOMXPath under the covers for DOMDocument any way, but are implemented more efficiently in a spec-compliant implementation). * A couple of times we have code like: `while ($node->firstChild!==null) { $node = $node->firstChild; }` and phan's analysis isn't strong enough to determine that $node is still non-null after the while. This same issue should appear with DOMDocument but phan doesn't complain for some reason. One apparently legit issue: * Node::insertBefore() is once called in a funny way which leans on the fact that the second option is optional in PHP. This seems to be a workaround for an ancient PHP bug, and can probably be safely removed. Bug: T287611 Bug: T217867 Change-Id: I3c4f41c3819770f85d68157c9f690d650b7266a3
137 lines
3.6 KiB
PHP
137 lines
3.6 KiB
PHP
<?php
|
|
|
|
namespace MediaWiki\Extension\DiscussionTools\Tests;
|
|
|
|
use MediaWiki\Extension\DiscussionTools\CommentParser;
|
|
use MediaWiki\MediaWikiServices;
|
|
use Wikimedia\Parsoid\DOM\Document;
|
|
use Wikimedia\Parsoid\DOM\Element;
|
|
use Wikimedia\Parsoid\Utils\DOMCompat;
|
|
use Wikimedia\Parsoid\Utils\DOMUtils;
|
|
|
|
trait TestUtils {
|
|
|
|
/**
|
|
* Create a Document from a string
|
|
*
|
|
* @param string $html
|
|
* @return Document
|
|
*/
|
|
protected static function createDocument( string $html ): Document {
|
|
$doc = DOMUtils::parseHTML( $html );
|
|
$doc->preserveWhiteSpace = false;
|
|
return $doc;
|
|
}
|
|
|
|
/**
|
|
* Get text from path
|
|
*
|
|
* @param string $relativePath
|
|
* @return string
|
|
*/
|
|
protected static function getText( string $relativePath ): string {
|
|
return file_get_contents( __DIR__ . '/../' . $relativePath );
|
|
}
|
|
|
|
/**
|
|
* Write text to path
|
|
*
|
|
* @param string $relativePath
|
|
* @param string $text
|
|
*/
|
|
protected static function overwriteTextFile( string $relativePath, string $text ): void {
|
|
file_put_contents( __DIR__ . '/../' . $relativePath, $text );
|
|
}
|
|
|
|
/**
|
|
* Get parsed JSON from path
|
|
*
|
|
* @param string $relativePath
|
|
* @param bool $assoc See json_decode()
|
|
* @return array
|
|
*/
|
|
protected static function getJson( string $relativePath, bool $assoc = true ): array {
|
|
$json = json_decode(
|
|
file_get_contents( __DIR__ . '/' . $relativePath ),
|
|
$assoc
|
|
);
|
|
return $json;
|
|
}
|
|
|
|
/**
|
|
* Write JSON to path
|
|
*
|
|
* @param string $relativePath
|
|
* @param array $data
|
|
*/
|
|
protected static function overwriteJsonFile( string $relativePath, array $data ): void {
|
|
$json = json_encode( $data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
|
|
// Tabs instead of 4 spaces
|
|
$json = preg_replace( '/(?:\G|^) {4}/m', "\t", $json );
|
|
file_put_contents( __DIR__ . '/' . $relativePath, $json . "\n" );
|
|
}
|
|
|
|
/**
|
|
* Get HTML from path
|
|
*
|
|
* @param string $relativePath
|
|
* @return string
|
|
*/
|
|
protected static function getHtml( string $relativePath ): string {
|
|
$html = file_get_contents( __DIR__ . '/../' . $relativePath );
|
|
|
|
// Remove all but the body tags from full Parsoid docs
|
|
if ( strpos( $html, '<body' ) !== false ) {
|
|
preg_match( '`(<body[^>]*>)(.*)(</body>)`s', $html, $match );
|
|
$html = "<div>$match[2]</div>";
|
|
}
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* Write HTML to path
|
|
*
|
|
* @param string $relPath
|
|
* @param Document $doc
|
|
* @param string $origRelPath
|
|
*/
|
|
protected static function overwriteHtmlFile( string $relPath, Document $doc, string $origRelPath ): void {
|
|
// Do not use $doc->saveHtml(), it outputs an awful soup of HTML entities for documents with
|
|
// non-ASCII characters
|
|
$html = file_get_contents( __DIR__ . '/../' . $origRelPath );
|
|
|
|
// Replace the body tag only in full Parsoid docs
|
|
if ( strpos( $html, '<body' ) !== false ) {
|
|
$innerHtml = DOMCompat::getInnerHTML( $doc->getElementsByTagName( 'body' )->item( 0 )->firstChild );
|
|
$html = preg_replace(
|
|
'`(<body[^>]*>)(.*)(</body>)`s',
|
|
// Quote \ and $ in the replacement text
|
|
'$1' . strtr( $innerHtml, [ '\\' => '\\\\', '$' => '\\$' ] ) . '$3',
|
|
$html
|
|
);
|
|
} else {
|
|
$html = DOMCompat::getInnerHTML( $doc->getElementsByTagName( 'body' )->item( 0 ) );
|
|
}
|
|
|
|
file_put_contents( __DIR__ . '/../' . $relPath, $html );
|
|
}
|
|
|
|
/**
|
|
* Create a comment parser
|
|
*
|
|
* @param Element $rootNode
|
|
* @param array $data
|
|
* @return CommentParser
|
|
*/
|
|
public static function createParser( Element $rootNode, array $data ): CommentParser {
|
|
$services = MediaWikiServices::getInstance();
|
|
return new CommentParser(
|
|
$rootNode,
|
|
$services->getContentLanguage(),
|
|
$services->getMainConfig(),
|
|
$data
|
|
);
|
|
}
|
|
}
|