1<?php 2/* 3 * This file is part of the Comparator package. 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 11namespace SebastianBergmann\Comparator; 12 13use DOMDocument; 14use DOMNode; 15 16/** 17 * Compares DOMNode instances for equality. 18 */ 19class DOMNodeComparator extends ObjectComparator 20{ 21 /** 22 * Returns whether the comparator can compare two values. 23 * 24 * @param mixed $expected The first value to compare 25 * @param mixed $actual The second value to compare 26 * @return bool 27 */ 28 public function accepts($expected, $actual) 29 { 30 return $expected instanceof DOMNode && $actual instanceof DOMNode; 31 } 32 33 /** 34 * Asserts that two values are equal. 35 * 36 * @param mixed $expected First value to compare 37 * @param mixed $actual Second value to compare 38 * @param float $delta Allowed numerical distance between two values to consider them equal 39 * @param bool $canonicalize Arrays are sorted before comparison when set to true 40 * @param bool $ignoreCase Case is ignored when set to true 41 * @param array $processed List of already processed elements (used to prevent infinite recursion) 42 * 43 * @throws ComparisonFailure 44 */ 45 public function assertEquals($expected, $actual, $delta = 0.0, $canonicalize = false, $ignoreCase = false, array &$processed = array()) 46 { 47 $expectedAsString = $this->nodeToText($expected, true, $ignoreCase); 48 $actualAsString = $this->nodeToText($actual, true, $ignoreCase); 49 50 if ($expectedAsString !== $actualAsString) { 51 if ($expected instanceof DOMDocument) { 52 $type = 'documents'; 53 } else { 54 $type = 'nodes'; 55 } 56 57 throw new ComparisonFailure( 58 $expected, 59 $actual, 60 $expectedAsString, 61 $actualAsString, 62 false, 63 sprintf("Failed asserting that two DOM %s are equal.\n", $type) 64 ); 65 } 66 } 67 68 /** 69 * Returns the normalized, whitespace-cleaned, and indented textual 70 * representation of a DOMNode. 71 * 72 * @param DOMNode $node 73 * @param bool $canonicalize 74 * @param bool $ignoreCase 75 * @return string 76 */ 77 private function nodeToText(DOMNode $node, $canonicalize, $ignoreCase) 78 { 79 if ($canonicalize) { 80 $document = new DOMDocument; 81 $document->loadXML($node->C14N()); 82 83 $node = $document; 84 } 85 86 if ($node instanceof DOMDocument) { 87 $document = $node; 88 } else { 89 $document = $node->ownerDocument; 90 } 91 92 $document->formatOutput = true; 93 $document->normalizeDocument(); 94 95 if ($node instanceof DOMDocument) { 96 $text = $node->saveXML(); 97 } else { 98 $text = $document->saveXML($node); 99 } 100 101 if ($ignoreCase) { 102 $text = strtolower($text); 103 } 104 105 return $text; 106 } 107} 108