class PHPUnit_Util_Diff

Diff implementation.

@package PHPUnit @subpackage Util @author Sebastian Bergmann <sebastian@phpunit.de> @author Kore Nordmann <mail@kore-nordmann.de> @copyright 2001-2013 Sebastian Bergmann <sebastian@phpunit.de> @license http://www.opensource.org/licenses/BSD-3-Clause The BSD 3-Clause License @link http://www.phpunit.de/ @since Class available since Release 3.4.0

Hierarchy

Expanded class hierarchy of PHPUnit_Util_Diff

File

drupal/core/vendor/phpunit/phpunit/PHPUnit/Util/Diff.php, line 59

View source
class PHPUnit_Util_Diff {

  /**
   * Returns the diff between two arrays or strings as string.
   *
   * @param  array|string $from
   * @param  array|string $to
   * @return string
   */
  public static function diff($from, $to) {
    $buffer = "--- Expected\n+++ Actual\n";
    $diff = self::diffToArray($from, $to);
    $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) {
        $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 the diff between two arrays or strings as array.
   *
   * every array-entry containts two elements:
   *   - [0] => string $token
   *   - [1] => 2|1|0
   *
   * - 2: REMOVED: $token was removed from $from
   * - 1: ADDED: $token was added to $from
   * - 0: OLD: $token is not changed in $to
   *
   * @param  array|string $from
   * @param  array|string $to
   * @return array
   */
  public static function diffToArray($from, $to) {
    preg_match_all('(\\r\\n|\\r|\\n)', $from, $fromMatches);
    preg_match_all('(\\r\\n|\\r|\\n)', $to, $toMatches);
    if (is_string($from)) {
      $from = preg_split('(\\r\\n|\\r|\\n)', $from);
    }
    if (is_string($to)) {
      $to = preg_split('(\\r\\n|\\r|\\n)', $to);
    }
    $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;
    if (isset($fromMatches[0]) && $toMatches[0] && count($fromMatches[0]) === count($toMatches[0]) && $fromMatches[0] !== $toMatches[0]) {
      $diff[] = array(
        '#Warning: Strings contain different line endings!',
        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,
      );
    }
    return $diff;
  }

  /**
   * Calculates the longest common subsequence of two arrays.
   *
   * @param  array $from
   * @param  array $to
   * @return array
   */
  protected static function longestCommonSubsequence(array $from, array $to) {
    $common = array();
    $matrix = array();
    $fromLength = count($from);
    $toLength = count($to);
    for ($i = 0; $i <= $fromLength; ++$i) {
      $matrix[$i][0] = 0;
    }
    for ($j = 0; $j <= $toLength; ++$j) {
      $matrix[0][$j] = 0;
    }
    for ($i = 1; $i <= $fromLength; ++$i) {
      for ($j = 1; $j <= $toLength; ++$j) {
        $matrix[$i][$j] = max($matrix[$i - 1][$j], $matrix[$i][$j - 1], $from[$i - 1] === $to[$j - 1] ? $matrix[$i - 1][$j - 1] + 1 : 0);
      }
    }
    $i = $fromLength;
    $j = $toLength;
    while ($i > 0 && $j > 0) {
      if ($from[$i - 1] === $to[$j - 1]) {
        array_unshift($common, $from[$i - 1]);
        --$i;
        --$j;
      }
      else {
        if ($matrix[$i][$j - 1] > $matrix[$i - 1][$j]) {
          --$j;
        }
        else {
          --$i;
        }
      }
    }
    return $common;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
PHPUnit_Util_Diff::diff public static function Returns the diff between two arrays or strings as string.
PHPUnit_Util_Diff::diffToArray public static function Returns the diff between two arrays or strings as array.
PHPUnit_Util_Diff::longestCommonSubsequence protected static function Calculates the longest common subsequence of two arrays.