public static function diff($from, $to)
{
if (is_string($from)) {
$from = preg_split('(\\r\\n|\\r|\\n)', $from);
}
if (is_string($to)) {
$to = preg_split('(\\r\\n|\\r|\\n)', $to);
}
$buffer = "--- Expected\n+++ Actual\n";
$start = array();
$end = array();
$fromLength = count($from);
$toLength = count($to);
$length = min($fromLength, $toLength);
for ($i = 0; $i < $length; ++$i) {
if ($from[$i] === $to[$i]) {
$start[] = $from[$i];
unset($from[$i], $to[$i]);
} else {
break;
}
}
$length -= $i;
for ($i = 1; $i < $length; ++$i) {
if ($from[$fromLength - $i] === $to[$toLength - $i]) {
array_unshift($end, $from[$fromLength - $i]);
unset($from[$fromLength - $i], $to[$toLength - $i]);
} else {
break;
}
}
$common = self::longestCommonSubsequence(array_values($from), array_values($to));
$diff = array();
$line = 0;
foreach ($start as $token) {
$diff[] = array($token, 0);
}
reset($from);
reset($to);
foreach ($common as $token) {
while (($fromToken = reset($from)) !== $token) {
$diff[] = array(array_shift($from), 2);
}
while (($toToken = reset($to)) !== $token) {
$diff[] = array(array_shift($to), 1);
}
$diff[] = array($token, 0);
array_shift($from);
array_shift($to);
}
while (($token = array_shift($from)) !== NULL) {
$diff[] = array($token, 2);
}
while (($token = array_shift($to)) !== NULL) {
$diff[] = array($token, 1);
}
foreach ($end as $token) {
$diff[] = array($token, 0);
}
$inOld = FALSE;
$i = 0;
$old = array();
foreach ($diff as $line) {
if ($line[1] === 0) {
if ($inOld === FALSE) {
$inOld = $i;
}
} else {
if ($inOld !== FALSE) {
if ($i - $inOld > 5) {
$old[$inOld] = $i - 1;
}
$inOld = FALSE;
}
}
++$i;
}
$start = isset($old[0]) ? $old[0] : 0;
$end = count($diff);
$i = 0;
if ($tmp = array_search($end, $old)) {
$end = $tmp;
}
$newChunk = TRUE;
for ($i = $start; $i < $end; $i++) {
if (isset($old[$i])) {
$buffer .= "\n";
$newChunk = TRUE;
$i = $old[$i];
}
if ($newChunk) {
// TODO: Implement chunk range information.
$buffer .= "@@ @@\n";
$newChunk = FALSE;
}
if ($diff[$i][1] === 1) {
$buffer .= '+' . $diff[$i][0] . "\n";
} else {
if ($diff[$i][1] === 2) {
$buffer .= '-' . $diff[$i][0] . "\n";
} else {
$buffer .= ' ' . $diff[$i][0] . "\n";
}
}
}
return $buffer;
}
/** * Returns a string describing the difference between the expected and the * actual object. * * @return string */ public function toString() { $diff = PHPUnit_Util_Diff::diff(print_r($this->expected, TRUE), print_r($this->actual, TRUE)); if ($diff !== FALSE) { return trim($diff); } // Fallback: Either diff is not available or the print_r() output for // the expected and the actual object are equal (but the objects are // not). $expectedClass = get_class($this->expected); $actualClass = get_class($this->actual); if ($expectedClass !== $actualClass) { return sprintf("%s%sexpected class <%s>\n" . '%sgot class <%s>', $this->message, $this->message != '' ? ' ' : '', $expectedClass, $this->message != '' ? str_repeat(' ', strlen($this->message) + 1) : '', $actualClass); } else { $expectedReflection = new ReflectionClass($expectedClass); $actualReflection = new ReflectionClass($actualClass); $diff = "in object of class <{$expectedClass}>:\n"; $i = 0; foreach ($expectedReflection->getProperties() as $expectedAttribute) { if ($expectedAttribute->isPrivate() || $expectedAttribute->isProtected()) { continue; } $actualAttribute = $actualReflection->getProperty($expectedAttribute->getName()); $expectedValue = $expectedAttribute->getValue($this->expected); $actualValue = $actualAttribute->getValue($this->actual); if ($expectedValue !== $actualValue) { if ($i > 0) { $diff .= "\n"; } ++$i; $expectedType = gettype($expectedValue); $actualType = gettype($actualValue); if ($expectedType !== $actualType) { $diffObject = new PHPUnit_Framework_ComparisonFailure_Type($expectedValue, $actualValue, $this->message . 'attribute <' . $expectedAttribute->getName() . '>: '); $diff .= $diffObject->toString(); } elseif (is_object($expectedValue)) { if (get_class($expectedValue) !== get_class($actualValue)) { $diffObject = new PHPUnit_Framework_ComparisonFailure_Type($expectedValue, $actualValue, $this->message . 'attribute <' . $expectedAttribute->getName() . '>: '); $diff .= $diffObject->toString(); } else { $diff .= 'attribute <' . $expectedAttribute->getName() . '> contains object <' . get_class($expectedValue) . '> with different attributes'; } } else { $diffObject = PHPUnit_Framework_ComparisonFailure::diffIdentical($expectedValue, $actualValue, $this->message . 'attribute <' . $expectedAttribute->getName() . '>: '); $diff .= $diffObject->toString(); } } } return $diff; } }