. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the name of Sebastian Bergmann nor the names of his * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * @category Testing * @package PHPUnit * @author Kore Nordmann * @author Sebastian Bergmann * @copyright 2002-2009 Sebastian Bergmann * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @link http://www.phpunit.de/ * @since File available since Release 3.0.0 */ require_once 'PHPUnit/Framework.php'; require_once 'PHPUnit/Util/Filter.php'; require_once 'PHPUnit/Util/Type.php'; PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT'); /** * Constraint that checks if one value is equal to another. * * Equality is checked with PHP's == operator, the operator is explained in detail * at {@url http://www.php.net/manual/en/types.comparisons.php}. * Two values are equal if they have the same value disregarding type. * * The expected value is passed in the constructor. * * @category Testing * @package PHPUnit * @author Kore Nordmann * @author Sebastian Bergmann * @copyright 2002-2009 Sebastian Bergmann * @license http://www.opensource.org/licenses/bsd-license.php BSD License * @version Release: 3.3.17 * @link http://www.phpunit.de/ * @since Class available since Release 3.0.0 */ class PHPUnit_Framework_Constraint_IsEqual extends PHPUnit_Framework_Constraint { protected $value; protected $delta = 0; protected $maxDepth = 10; protected $canonicalizeEol = FALSE; public function __construct($value, $delta = 0, $maxDepth = 10, $canonicalizeEol = FALSE) { $this->value = $value; $this->delta = $delta; $this->maxDepth = $maxDepth; $this->canonicalizeEol = $canonicalizeEol; } /** * Evaluates the constraint for parameter $other. Returns TRUE if the * constraint is met, FALSE otherwise. * * @param mixed $other Value or object to evaluate. * @return bool */ public function evaluate($other) { return $this->recursiveComparison($this->value, $other); } /** * @param mixed $other The value passed to evaluate() which failed the * constraint check. * @param string $description A string with extra description of what was * going on while the evaluation failed. * @param boolean $not Flag to indicate negation. * @throws PHPUnit_Framework_ExpectationFailedException */ public function fail($other, $description, $not = FALSE) { $failureDescription = $this->failureDescription( $other, $description, $not ); if (!$not) { if ($this->value instanceof DOMDocument) { $value = $this->domToText($this->value); } else { $value = $this->value; } if ($other instanceof DOMDocument) { $other = $this->domToText($other); } throw new PHPUnit_Framework_ExpectationFailedException( $failureDescription, PHPUnit_Framework_ComparisonFailure::diffEqual($value, $other), $description ); } else { throw new PHPUnit_Framework_ExpectationFailedException( $failureDescription, NULL ); } } /** * Returns a string representation of the constraint. * * @return string */ public function toString() { $delta = ''; if (is_string($this->value)) { if (strpos($this->value, "\n") !== FALSE) { return 'is equal to '; } else { return sprintf( 'is equal to ', $this->value ); } } else { if ($this->delta != 0) { $delta = sprintf( ' with delta <%F>', $this->delta ); } return sprintf( 'is equal to %s%s', PHPUnit_Util_Type::toString($this->value), $delta ); } } /** * Perform the actual recursive comparision of two values * * @param mixed $a First value * @param mixed $b Second value * @param int $depth Depth * @return bool */ protected function recursiveComparison($a, $b, $depth = 0) { if ($a === $b) { return TRUE; } if ($depth >= $this->maxDepth) { return TRUE; } if (is_numeric($a) XOR is_numeric($b)) { return FALSE; } if (is_array($a) XOR is_array($b)) { return FALSE; } if (is_object($a) XOR is_object($b)) { return FALSE; } if ($a instanceof SplObjectStorage XOR $b instanceof SplObjectStorage) { return FALSE; } if ($a instanceof SplObjectStorage) { foreach ($a as $object) { if (!$b->contains($object)) { return FALSE; } } foreach ($b as $object) { if (!$a->contains($object)) { return FALSE; } } return TRUE; } if ($a instanceof DOMDocument || $b instanceof DOMDocument) { if (!$a instanceof DOMDocument) { $_a = new DOMDocument; $_a->preserveWhiteSpace = FALSE; $_a->loadXML($a); $a = $_a; unset($_a); } if (!$b instanceof DOMDocument) { $_b = new DOMDocument; $_b->preserveWhiteSpace = FALSE; $_b->loadXML($b); $b = $_b; unset($_b); } if (version_compare(PHP_VERSION, '5.2.0RC1', '>=')) { return ($a->C14N() == $b->C14N()); } else { return ($a->saveXML() == $b->saveXML()); } } if (is_object($a) && is_object($b) && (get_class($a) !== get_class($b))) { return FALSE; } // Normal comparision for scalar values. if ((!is_array($a) && !is_object($a)) || (!is_array($b) && !is_object($b))) { if (is_numeric($a) && is_numeric($b)) { // Optionally apply delta on numeric values. return $this->numericComparison($a, $b); } if ($this->canonicalizeEol && PHP_EOL != "\n" && is_string($a) && is_string($b)) { $a = str_replace(PHP_EOL, "\n", $a); $b = str_replace(PHP_EOL, "\n", $b); } return ($a == $b); } if (is_object($a)) { $a = (array)$a; $b = (array)$b; } foreach ($a as $key => $v) { if (!array_key_exists($key, $b)) { // Abort on missing key in $b. return FALSE; } if (!$this->recursiveComparison($a[$key], $b[$key], $depth + 1)) { // FALSE, if child comparision fails. return FALSE; } // Unset key to check whether all keys of b are compared. unset($b[$key]); } if (count($b)) { // There is something in $b, that is missing in $a. return FALSE; } return TRUE; } /** * Compares two numeric values - use delta if applicable. * * @param mixed $a * @param mixed $b * @return bool */ protected function numericComparison($a, $b) { if ($this->delta === FALSE) { return ($a == $b); } else { return (abs($a - $b) <= $this->delta); } } /** * Returns the normalized, whitespace-cleaned, and indented textual * representation of a DOMDocument. * * @param DOMDocument $document * @return string */ protected function domToText(DOMDocument $document) { $document->formatOutput = TRUE; $document->normalizeDocument(); return $document->saveXML(); } } ?>