PageRenderTime 55ms CodeModel.GetById 7ms RepoModel.GetById 0ms app.codeStats 0ms

/script/lib/PHPUnit/Util/Diff.php

https://bitbucket.org/chamilo/chamilo/
PHP | 261 lines | 149 code | 40 blank | 72 comment | 35 complexity | c938d66d0195cd641509dcbb8a5cbb37 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1, LGPL-3.0, GPL-3.0, MIT
  1. <?php
  2. /**
  3. * PHPUnit
  4. *
  5. * Copyright (c) 2002-2011, Sebastian Bergmann <sebastian@phpunit.de>.
  6. * All rights reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * * Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * * Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * * Neither the name of Sebastian Bergmann nor the names of his
  21. * contributors may be used to endorse or promote products derived
  22. * from this software without specific prior written permission.
  23. *
  24. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  25. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  26. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  27. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  28. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  29. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  30. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  31. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  32. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
  34. * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  35. * POSSIBILITY OF SUCH DAMAGE.
  36. *
  37. * @package PHPUnit
  38. * @subpackage Util
  39. * @author Sebastian Bergmann <sebastian@phpunit.de>
  40. * @author Kore Nordmann <mail@kore-nordmann.de>
  41. * @copyright 2002-2011 Sebastian Bergmann <sebastian@phpunit.de>
  42. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  43. * @link http://www.phpunit.de/
  44. * @since File available since Release 3.4.0
  45. */
  46. /**
  47. * Diff implementation.
  48. *
  49. * @package PHPUnit
  50. * @subpackage Util
  51. * @author Sebastian Bergmann <sebastian@phpunit.de>
  52. * @author Kore Nordmann <mail@kore-nordmann.de>
  53. * @copyright 2002-2011 Sebastian Bergmann <sebastian@phpunit.de>
  54. * @license http://www.opensource.org/licenses/bsd-license.php BSD License
  55. * @version Release: 3.5.9
  56. * @link http://www.phpunit.de/
  57. * @since Class available since Release 3.4.0
  58. */
  59. class PHPUnit_Util_Diff
  60. {
  61. /**
  62. * Returns the diff between two arrays or strings.
  63. *
  64. * @param array|string $from
  65. * @param array|string $to
  66. * @return string
  67. */
  68. public static function diff($from, $to)
  69. {
  70. if (is_string($from)) {
  71. $from = preg_split('(\r\n|\r|\n)', $from);
  72. }
  73. if (is_string($to)) {
  74. $to = preg_split('(\r\n|\r|\n)', $to);
  75. }
  76. $buffer = "--- Expected\n+++ Actual\n";
  77. $start = array();
  78. $end = array();
  79. $fromLength = count($from);
  80. $toLength = count($to);
  81. $length = min($fromLength, $toLength);
  82. for ($i = 0; $i < $length; ++$i) {
  83. if ($from[$i] === $to[$i]) {
  84. $start[] = $from[$i];
  85. unset($from[$i], $to[$i]);
  86. } else {
  87. break;
  88. }
  89. }
  90. $length -= $i;
  91. for ($i = 1; $i < $length; ++$i) {
  92. if ($from[$fromLength - $i] === $to[$toLength - $i]) {
  93. array_unshift($end, $from[$fromLength - $i]);
  94. unset($from[$fromLength - $i], $to[$toLength - $i]);
  95. } else {
  96. break;
  97. }
  98. }
  99. $common = self::longestCommonSubsequence(
  100. array_values($from), array_values($to)
  101. );
  102. $diff = array();
  103. $line = 0;
  104. foreach ($start as $token) {
  105. $diff[] = array($token, 0 /* OLD */);
  106. }
  107. reset($from);
  108. reset($to);
  109. foreach ($common as $token) {
  110. while ((($fromToken = reset($from)) !== $token)) {
  111. $diff[] = array(array_shift($from), 2 /* REMOVED */);
  112. }
  113. while ((($toToken = reset($to)) !== $token)) {
  114. $diff[] = array(array_shift($to), 1 /* ADDED */);
  115. }
  116. $diff[] = array($token, 0 /* OLD */);
  117. array_shift($from);
  118. array_shift($to);
  119. }
  120. while (($token = array_shift($from)) !== NULL) {
  121. $diff[] = array($token, 2 /* REMOVED */);
  122. }
  123. while (($token = array_shift($to)) !== NULL) {
  124. $diff[] = array($token, 1 /* ADDED */);
  125. }
  126. foreach ($end as $token) {
  127. $diff[] = array($token, 0 /* OLD */);
  128. }
  129. $inOld = FALSE;
  130. $i = 0;
  131. $old = array();
  132. foreach ($diff as $line) {
  133. if ($line[1] === 0 /* OLD */) {
  134. if ($inOld === FALSE) {
  135. $inOld = $i;
  136. }
  137. }
  138. else if ($inOld !== FALSE) {
  139. if (($i - $inOld) > 5) {
  140. $old[$inOld] = $i - 1;
  141. }
  142. $inOld = FALSE;
  143. }
  144. ++$i;
  145. }
  146. $start = isset($old[0]) ? $old[0] : 0;
  147. $end = count($diff);
  148. $i = 0;
  149. if ($tmp = array_search($end, $old)) {
  150. $end = $tmp;
  151. }
  152. $newChunk = TRUE;
  153. for ($i = $start; $i < $end; $i++) {
  154. if (isset($old[$i])) {
  155. $buffer .= "\n";
  156. $newChunk = TRUE;
  157. $i = $old[$i];
  158. }
  159. if ($newChunk) {
  160. // TODO: Implement chunk range information.
  161. $buffer .= "@@ @@\n";
  162. $newChunk = FALSE;
  163. }
  164. if ($diff[$i][1] === 1 /* ADDED */) {
  165. $buffer .= '+' . $diff[$i][0] . "\n";
  166. }
  167. else if ($diff[$i][1] === 2 /* REMOVED */) {
  168. $buffer .= '-' . $diff[$i][0] . "\n";
  169. }
  170. else {
  171. $buffer .= ' ' . $diff[$i][0] . "\n";
  172. }
  173. }
  174. return $buffer;
  175. }
  176. /**
  177. * Calculates the longest common subsequence of two arrays.
  178. *
  179. * @param array $from
  180. * @param array $to
  181. * @return array
  182. */
  183. protected static function longestCommonSubsequence(array $from, array $to)
  184. {
  185. $common = array();
  186. $matrix = array();
  187. $fromLength = count($from);
  188. $toLength = count($to);
  189. for ($i = 0; $i <= $fromLength; ++$i) {
  190. $matrix[$i][0] = 0;
  191. }
  192. for ($j = 0; $j <= $toLength; ++$j) {
  193. $matrix[0][$j] = 0;
  194. }
  195. for ($i = 1; $i <= $fromLength; ++$i) {
  196. for ($j = 1; $j <= $toLength; ++$j) {
  197. $matrix[$i][$j] = max(
  198. $matrix[$i-1][$j],
  199. $matrix[$i][$j-1],
  200. $from[$i-1] === $to[$j-1] ? $matrix[$i-1][$j-1] + 1 : 0
  201. );
  202. }
  203. }
  204. $i = $fromLength;
  205. $j = $toLength;
  206. while ($i > 0 && $j > 0) {
  207. if ($from[$i-1] === $to[$j-1]) {
  208. array_unshift($common, $from[$i-1]);
  209. --$i;
  210. --$j;
  211. }
  212. else if ($matrix[$i][$j-1] > $matrix[$i-1][$j]) {
  213. --$j;
  214. }
  215. else {
  216. --$i;
  217. }
  218. }
  219. return $common;
  220. }
  221. }