DOMNodeComparator.php 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. <?php declare(strict_types=1);
  2. /*
  3. * This file is part of sebastian/comparator.
  4. *
  5. * (c) Sebastian Bergmann <sebastian@phpunit.de>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace SebastianBergmann\Comparator;
  11. use function assert;
  12. use function mb_strtolower;
  13. use function sprintf;
  14. use DOMDocument;
  15. use DOMNode;
  16. use ValueError;
  17. final class DOMNodeComparator extends ObjectComparator
  18. {
  19. public function accepts(mixed $expected, mixed $actual): bool
  20. {
  21. return $expected instanceof DOMNode && $actual instanceof DOMNode;
  22. }
  23. /**
  24. * @param array<mixed> $processed
  25. *
  26. * @throws ComparisonFailure
  27. */
  28. public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false, array &$processed = []): void
  29. {
  30. assert($expected instanceof DOMNode);
  31. assert($actual instanceof DOMNode);
  32. $expectedAsString = $this->nodeToText($expected, true, $ignoreCase);
  33. $actualAsString = $this->nodeToText($actual, true, $ignoreCase);
  34. if ($expectedAsString !== $actualAsString) {
  35. $type = $expected instanceof DOMDocument ? 'documents' : 'nodes';
  36. throw new ComparisonFailure(
  37. $expected,
  38. $actual,
  39. $expectedAsString,
  40. $actualAsString,
  41. sprintf("Failed asserting that two DOM %s are equal.\n", $type),
  42. );
  43. }
  44. }
  45. /**
  46. * Returns the normalized, whitespace-cleaned, and indented textual
  47. * representation of a DOMNode.
  48. */
  49. private function nodeToText(DOMNode $node, bool $canonicalize, bool $ignoreCase): string
  50. {
  51. if ($canonicalize) {
  52. $document = new DOMDocument;
  53. try {
  54. $c14n = $node->C14N();
  55. assert(!empty($c14n));
  56. @$document->loadXML($c14n);
  57. } catch (ValueError) {
  58. }
  59. $node = $document;
  60. }
  61. if ($node instanceof DOMDocument) {
  62. $document = $node;
  63. } else {
  64. $document = $node->ownerDocument;
  65. }
  66. assert($document instanceof DOMDocument);
  67. $document->formatOutput = true;
  68. $document->normalizeDocument();
  69. if ($node instanceof DOMDocument) {
  70. $text = $node->saveXML();
  71. } else {
  72. $text = $document->saveXML($node);
  73. }
  74. assert($text !== false);
  75. if ($ignoreCase) {
  76. return mb_strtolower($text, 'UTF-8');
  77. }
  78. return $text;
  79. }
  80. }