wiki.techinc.nl/tests/parser/ParserTestResultNormalizer.php
Timo Tijhof 128debb64b tests: Change use of AtEase to at operator
Follows-up I361fde0de7f4406bce6ed075ed397effa5be3359.

Per T253461, not mass-changing source code, but the use of the native
error silencing operator (@) is especially useful in tests because:

1. It requires any/all statements to be explicitly marked. The
   suppressWarnings/restoreWarnings sections encourage developers to
   be "lazy" and thus encapsulate more than needed if there are multiple
   ones near each other, which would ignore potentially important
   warnings in a test case, which is generally exactly the time when
   it is really useful to get warnings etc.

2. It avoids leaking state, for example in LBFactoryTest the
   assertFalse call would throw a PHPUnit assertion error (not meant
   to be caught by the local catch), and thus won't reach
   AtEase::restoreWarnings. This then causes later code to end up
   in a mismatching state and creates a confusing error_reporting
   state.

See .phpcs.xml, where the at operator is allowed for all test code.

Change-Id: I68d1725d685e0a7586468bc9de6dc29ceea31b8a
2022-02-24 21:29:51 +00:00

84 lines
2.4 KiB
PHP

<?php
/**
* @ingroup Testing
*/
class ParserTestResultNormalizer {
protected $doc, $xpath, $invalid;
public static function normalize( $text, $funcs ) {
$norm = new self( $text );
if ( $norm->invalid ) {
return $text;
}
foreach ( $funcs as $func ) {
$norm->$func();
}
return $norm->serialize();
}
protected function __construct( $text ) {
$this->doc = new DOMDocument( '1.0', 'utf-8' );
// Parsing a supposedly-XHTML document with an XML parser is not
// guaranteed to give accurate results. For example, it may introduce
// differences in the number of line breaks in <pre> tags.
if ( !@$this->doc->loadXML( '<html><body>' . $text . '</body></html>' ) ) {
$this->invalid = true;
}
$this->xpath = new DOMXPath( $this->doc );
$this->body = $this->xpath->query( '//body' )->item( 0 );
}
protected function removeTbody() {
foreach ( $this->xpath->query( '//tbody' ) as $tbody ) {
while ( $tbody->firstChild ) {
$child = $tbody->firstChild;
$tbody->removeChild( $child );
$tbody->parentNode->insertBefore( $child, $tbody );
}
$tbody->parentNode->removeChild( $tbody );
}
}
/**
* The point of this function is to produce a normalized DOM in which
* Tidy's output matches the output of RemexHtml. Tidy both trims
* and pretty-prints, so this requires fairly aggressive treatment.
*
* In particular, note that Tidy converts <pre>x</pre> to <pre>\nx\n</pre>,
* which theoretically affects display since the second line break is not
* ignored by compliant HTML parsers.
*
* This function also removes empty elements, as does Tidy.
*/
protected function trimWhitespace() {
foreach ( $this->xpath->query( '//text()' ) as $child ) {
if ( strtolower( $child->parentNode->nodeName ) === 'pre' ) {
// Just trim one line break from the start and end
if ( substr_compare( $child->data, "\n", 0 ) === 0 ) {
$child->data = substr( $child->data, 1 );
}
if ( substr_compare( $child->data, "\n", -1 ) === 0 ) {
$child->data = substr( $child->data, 0, -1 );
}
} else {
// Trim all whitespace
$child->data = trim( $child->data );
}
if ( $child->data === '' ) {
$child->parentNode->removeChild( $child );
}
}
}
/**
* Serialize the XML DOM for comparison purposes. This does not generate HTML.
* @return string
*/
protected function serialize() {
return strtr( $this->doc->saveXML( $this->body ),
[ '<body>' => '', '</body>' => '' ] );
}
}