浏览代码

add DiffHelper

euromark 12 年之前
父节点
当前提交
c654ec74a0
共有 2 个文件被更改,包括 370 次插入0 次删除
  1. 250 0
      Test/Case/View/Helper/DiffHelperTest.php
  2. 120 0
      View/Helper/DiffHelper.php

+ 250 - 0
Test/Case/View/Helper/DiffHelperTest.php

@@ -0,0 +1,250 @@
+<?php
+
+App::uses('DiffHelper', 'Tools.View/Helper');
+App::uses('HtmlHelper', 'View/Helper');
+App::uses('View', 'View');
+App::uses('MyCakeTestCase', 'Tools.TestSuite');
+
+/**
+ * render: unified/inline
+ * engine: native/shell (shell only on linux!)
+ * 2010-06-24 ms
+ */
+class DiffHelperTest extends MyCakeTestCase {
+
+/**
+ * setUp method
+ */
+	public function setUp() {
+		parent::setUp();
+
+		$this->Diff = new DiffHelper(new View(null));
+		$this->Diff->Html = new HtmlHelper(new View(null));
+
+		$style = <<<CSS
+<style type="text/css">
+del {
+	color: red;
+}
+ins {
+	color: green;
+}
+
+</style>
+CSS;
+		$this->out($style);
+	}
+
+	public function testAutoEngine() {
+		$engine = extension_loaded('xdiff') ? 'Xdiff' : 'Native';
+		$this->out('auto engine: ' . $engine);
+	}
+
+	/**
+	 * string renderer
+	 * source: 'context', 'unified', or 'autodetect'
+	 * engine:
+	 * - auto
+	 * - context from unified
+	 * - unified from context
+	 */
+	public function testReverse() {
+		$this->out('String - autodetect', false);
+		$text = <<<TEXT
+***************
+*** 1 ****
+! 99999999777
+--- 1 ----
+! 9999944449977
+TEXT;
+ 		$res = $this->Diff->reverse($text);
+ 		$this->out($res);
+
+ 		$this->out('String - Context - render as Unified', false);
+		$text = <<<TEXT
+***************
+*** 1 ****
+! 99999999777
+--- 1 ----
+! 9999944449977
+TEXT;
+		$this->Diff->renderType('unified');
+		$res = $this->Diff->reverse($text, array('mode' => 'context'));
+ 		$this->out($res);
+	}
+
+	/**
+	 * @expectedException HORDE_TEXT_DIFF_EXCEPTION
+	 */
+	public function testReverseUnifiedDiffNotDetectable() {
+		$this->out('Unified - String', false);
+		$text = <<<TEXT
+@@ -1,3 +1,3 @@
+ 1dfdf
+-jtzth6h6h6th6
++jtzh6h6th6
+ xcsdfdf
+TEXT;
+		$this->Diff->reverse($text);
+	}
+
+	/**
+	 * auto engine + inline Render
+	 * Fastest way
+	 *
+	 * 2010-09-04 ms
+	 */
+	public function testDiffDefault() {
+		$t1 = array(
+			'errgrshrth',
+			'srhrthrt777 ssshsrjtz jrjtjtjt',
+			'1dfdf'.PHP_EOL.'jtzth6h6h6th6'.PHP_EOL.'xcsdfdf',
+			'99999999777'
+		);
+		$t2 = array(
+			'errgrsh3333rth',
+			'srhrthrt777 hsrthsrjt888 jrjtjtjt',
+			'1dfdf'.PHP_EOL.'jtzh6h6th6'.PHP_EOL.'xcsdfdf',
+			'9999944449977'
+		);
+		$this->out('Inline - auto', false);
+		for ($i = 0; $i < 4; $i++) {
+			$res = $this->Diff->compare($t1[$i], $t2[$i]);
+			$this->out($res);
+		}
+	}
+
+	/**
+	 * inline render
+	 * engine:
+	 * - native
+	 * - shell
+	 * - xdiff (skip if not available)
+	 */
+	public function testDiffInline() {
+		$t1 = array(
+			'errgrshrth',
+			'srhrthrt777 ssshsrjtz jrjtjtjt',
+			'1dfdf'.PHP_EOL.'jtzth6h6h6th6'.PHP_EOL.'xcsdfdf',
+			'99999999777'
+		);
+		$t2 = array(
+			'errgrsh3333rth',
+			'srhrthrt777 hsrthsrjt888 jrjtjtjt',
+			'1dfdf'.PHP_EOL.'jtzh6h6th6'.PHP_EOL.'xcsdfdf',
+			'9999944449977'
+		);
+
+		$this->out('Inline - Native', false);
+		for ($i = 0; $i < 4; $i++) {
+			$this->assertTrue($this->Diff->renderType('inline'));
+			$this->assertTrue($this->Diff->engineType('native'));
+			$res = $this->Diff->compare($t1[$i], $t2[$i]);
+			$this->out($res);
+		}
+
+		$this->out('Inline - Shell', false);
+		for ($i = 0; $i < 4; $i++) {
+			$this->assertTrue($this->Diff->renderType('inline'));
+			$this->assertTrue($this->Diff->engineType('shell'));
+			$res = $this->Diff->compare($t1[$i], $t2[$i]);
+			$this->out($res);
+		}
+
+		$this->skipIf(!extension_loaded('xdiff'), 'xdiff not available');
+
+		$this->out('Inline - Xdiff', false);
+		for ($i = 0; $i < 4; $i++) {
+			$this->assertTrue($this->Diff->renderType('inline'));
+			$this->assertTrue($this->Diff->engineType('xdiff'));
+			$res = $this->Diff->compare($t1[$i], $t2[$i]);
+			$this->out($res);
+		}
+	}
+
+	/**
+	 * unified renderer
+	 */
+	public function testDiffUnified() {
+		$t1 = array(
+			'errgrshrth',
+			'srhrthrt777 ssshsrjtz jrjtjtjt',
+			'1dfdf'.PHP_EOL.'jtzth6h6h6th6'.PHP_EOL.'xcsdfdf',
+			'99999999777'
+		);
+		$t2 = array(
+			'errgrsh3333rth',
+			'srhrthrt777 hsrthsrjt888 jrjtjtjt',
+			'1dfdf'.PHP_EOL.'jtzh6h6th6'.PHP_EOL.'xcsdfdf',
+			'9999944449977'
+		);
+
+		$max = 4;
+
+		$this->out('Unified - Native', false);
+		for ($i = 0; $i < $max; $i++) {
+			$this->assertTrue($this->Diff->renderType('unified'));
+			$this->assertTrue($this->Diff->engineType('native'));
+			$res = $this->Diff->compare($t1[$i], $t2[$i]);
+			$this->out($res);
+
+		}
+
+		$this->out('Unified - Shell', false);
+		for ($i = 0; $i < 4; $i++) {
+			$this->assertTrue($this->Diff->renderType('unified'));
+			$this->assertTrue($this->Diff->engineType('shell'));
+			$res = $this->Diff->compare($t1[$i], $t2[$i]);
+			$this->out($res);
+
+		}
+
+		$this->skipIf(!extension_loaded('xdiff'), 'xdiff not available');
+
+		$this->out('Unified - Xdiff', false);
+		for ($i = 0; $i < $max; $i++) {
+			$this->assertTrue($this->Diff->renderType('unified'));
+			$this->assertTrue($this->Diff->engineType('xdiff'));
+			$res = $this->Diff->compare($t1[$i], $t2[$i]);
+			$this->out($res);
+
+		}
+	}
+
+	/**
+	 * context renderer
+	 */
+	public function testDiffContext() {
+		$t1 = array(
+			'errgrshrth',
+			'srhrthrt777 ssshsrjtz jrjtjtjt',
+			'1dfdf'.PHP_EOL.'jtzth6h6h6th6'.PHP_EOL.'xcsdfdf',
+			'99999999777'
+		);
+		$t2 = array(
+			'errgrsh3333rth',
+			'srhrthrt777 hsrthsrjt888 jrjtjtjt',
+			'1dfdf'.PHP_EOL.'jtzh6h6th6'.PHP_EOL.'xcsdfdf',
+			'9999944449977'
+		);
+
+		$this->out('Context - Native', false);
+		for ($i = 0; $i < 4; $i++) {
+			$this->assertTrue($this->Diff->renderType('context'));
+			$this->assertTrue($this->Diff->engineType('native'));
+			$res = $this->Diff->compare($t1[$i], $t2[$i]);
+			$this->out($res);
+
+		}
+
+		$this->out('Context - Shell', false);
+		for ($i = 0; $i < 4; $i++) {
+			$this->assertTrue($this->Diff->renderType('context'));
+			$this->assertTrue($this->Diff->engineType('shell'));
+			$res = $this->Diff->compare($t1[$i], $t2[$i]);
+			$this->out($res);
+
+		}
+	}
+
+}

+ 120 - 0
View/Helper/DiffHelper.php

@@ -0,0 +1,120 @@
+<?php
+App::uses('AppHelper', 'View/Helper');
+App::uses('DiffLib', 'Tools.Lib');
+
+/**
+ * DiffHelper class
+ *
+ * This class is a wrapper for PEAR Text_Diff with modified renderers from Horde
+ * You need the stable Text_Diff from PEAR and (if you want to use them) two
+ * renderers attached with this helper (sidebyside.php and character.php)
+ *
+ * To use this helper you either have to use the Vendor files in the Tools Plugin.
+ * Wraps the DiffLib (which does all the heavy lifting) for the view layer.
+ *
+ * @author Marcin Domanski aka kabturek <blog@kabturek.info>
+ * @license MIT
+ * @modified Mark Scherer (Make it work with 2.x and clean it up into Lib + Helper)
+ */
+class DiffHelper extends AppHelper {
+
+	public $helpers = array('Html');
+
+	/**
+	 * Construct function
+	 * Loads the vendor classes and sets the include path for autoloader to work
+	 *
+	 * @return void
+	 */
+	public function __construct($View = null, $settings = array()) {
+		parent::__construct($View, $settings);
+
+		$this->Diff = new DiffLib();
+	}
+
+	/**
+	 * @param string $renderType
+	 * 'unified', 'inline', 'context', 'sidebyside'
+	 * defaults to "inline"
+	 * @return boolean true on success, false otherwise
+	 * 2010-01-12 ms
+	 */
+	public function renderType($type = null) {
+		return $this->Diff->renderType($type);
+	}
+
+	/**
+	 * @param string $engineType
+	 * 'auto', 'native', 'xdiff', 'shell', 'string'
+	 * defaults to "auto"
+	 * @return boolean true on success, false otherwise
+	 * 2010-01-12 ms
+	 */
+	public function engineType($type = null) {
+		return $this->Diff->engineType($type);
+	}
+
+	/**
+	 * compare function
+	 * Compares two strings/arrays using the specified method and renderer
+	 *
+	 * @param mixed $original
+	 * @param mixed $changed
+	 * @param array $options
+	 * - div: true/false
+	 * - class: defaults to "diff"
+	 * - escape: defaults to true
+	 * @return string $output
+	 */
+	public function compare($original, $changed, $options = array()) {
+		$original = $this->_prep($original);
+
+		$changed = $this->_prep($changed);
+
+		$string = $this->Diff->compare($original, $changed, $options);
+		if (isset($options['div']) && $options['div'] === false) {
+			return $string;
+		}
+		$defaults = array(
+			'class' => 'diff'
+		);
+		$options = array_merge($defaults, $options);
+		$options['escape'] = null;
+		return $this->Html->tag('div', $string, $options);
+	}
+
+	/**
+	 * @param string $string Either context or unified diff snippet
+	 * @param array $options
+	 * - mode (autodetect, context, unified)
+	 */
+	public function reverse($string, $options = array()) {
+		$string = $this->Diff->reverse($string, $options);
+		if (isset($options['div']) && $options['div'] === false) {
+			return $string;
+		}
+		$defaults = array(
+			'class' => 'diff'
+		);
+		$options = array_merge($defaults, $options);
+		$options['escape'] = null;
+		return $this->Html->tag('div', $string, $options);
+	}
+
+	/**
+	 * Prep for security
+	 * maybe switch to do that after comparison?
+	 *
+	 * @param string $string
+	 * @param array $options
+	 * @return string
+	 * 2010-01-12 ms
+	 */
+	protected function _prep($string, $options = array()) {
+		if ($this->renderer === 'inline' || isset($options['escape']) && $options['escape'] === false) {
+			return $string;
+		}
+		return h($string);
+	}
+
+}