Skip to content

Instantly share code, notes, and snippets.

@thekid
Created July 9, 2011 17:56
Show Gist options
  • Save thekid/1073799 to your computer and use it in GitHub Desktop.
Save thekid/1073799 to your computer and use it in GitHub Desktop.
XP Framework: Patch for issue #30
diff --git a/core/src/main/php/unittest/AssertionFailedError.class.php b/core/src/main/php/unittest/AssertionFailedError.class.php
index e4e706c..a6d9377 100644
--- a/core/src/main/php/unittest/AssertionFailedError.class.php
+++ b/core/src/main/php/unittest/AssertionFailedError.class.php
@@ -7,7 +7,7 @@
/**
* Indicates an assertion failed
*
- * @purpose Exception
+ * @test xp://net.xp_framework.unittest.tests.StringComparisonTest
*/
class AssertionFailedError extends XPException {
public
@@ -29,18 +29,61 @@
}
/**
+ * Format the difference between the expected and actual values
+ *
+ * @return string
+ */
+ public function formatDifference() {
+ if (is_string($this->expect) && is_string($this->actual)) {
+ $la= strlen($this->actual);
+ $le= strlen($this->expect);
+ for ($i= 0, $l= min($le, $la); $i < $l; $i++) { // Search from beginning
+ if ($this->expect{$i} !== $this->actual{$i}) break;
+ }
+ for ($j= $le- 1, $k= $la- 1; $k >= $i && $j >= $i; $k--, $j--) { // Search from end
+ if ($this->expect{$j} !== $this->actual{$k}) break;
+ }
+ if ($j < $i && $k < $i) {
+ $expect= '"'.$this->expect.'"';
+ $actual= '"'.$this->actual.'"';
+ } else {
+ $expect= substr($this->expect, $i, $j+ 1- $i);
+ $actual= substr($this->actual, $i, $k+ 1- $i);
+ $c= $i <= $l && $i > 0;
+ $expect= $c ? '"...'.$expect : '"'.$expect; // Common beginning
+ $actual= $c ? '"...'.$actual : '"'.$actual;
+ $expect.= ($j < $le- 1) ? '..."' : '"'; // Common ending
+ $actual.= ($k < $la- 1) ? '..."' : '"';
+ }
+ } else {
+ $ta= typeof($this->actual);
+ $te= typeof($this->expect);
+ if ($ta->equals($te)) {
+ $expect= xp::stringOf($this->expect);
+ $actual= xp::stringOf($this->actual);
+ } else {
+ if ($te instanceof XPClass) {
+ $expect= $this->expect->toString();
+ } else {
+ $expect= NULL == $this->expect ? 'null' : $te->getName().'<'.xp::stringOf($this->expect).'>';
+ }
+ if ($ta instanceof XPClass) {
+ $actual= $this->actual->toString();
+ } else {
+ $actual= NULL == $this->actual ? 'null' : $ta->getName().'<'.xp::stringOf($this->actual).'>';
+ }
+ }
+ }
+ return 'expected: '.$expect.' but was: '.$actual;
+ }
+
+ /**
* Return compound message of this exception.
*
* @return string
*/
public function compoundMessage() {
- return sprintf(
- "%s (%s) { expected: [%s:%s] but was: [%s:%s] }\n",
- $this->getClassName(),
- $this->message,
- xp::typeOf($this->expect), xp::stringOf($this->expect),
- xp::typeOf($this->actual), xp::stringOf($this->actual)
- );
+ return $this->getClassName().' ('.$this->message.') { '.$this->formatDifference().' }';
}
/**
diff --git a/core/src/resources/unittest/unittest.ini b/core/src/resources/unittest/unittest.ini
index be6b518..18e93cf 100644
--- a/core/src/resources/unittest/unittest.ini
+++ b/core/src/resources/unittest/unittest.ini
@@ -29,3 +29,6 @@ class="net.xp_framework.unittest.tests.WebTestCaseTest"
[special]
class="net.xp_framework.unittest.tests.SpecialMethodsTest"
+
+[comparison]
+class="net.xp_framework.unittest.tests.ComparisonTest"
diff --git a/core/src/test/php/net/xp_framework/unittest/tests/ComparisonTest.class.php b/core/src/test/php/net/xp_framework/unittest/tests/ComparisonTest.class.php
new file mode 100644
index 0000000..4054b0d
--- /dev/null
+++ b/core/src/test/php/net/xp_framework/unittest/tests/ComparisonTest.class.php
@@ -0,0 +1,177 @@
+<?php
+/* This class is part of the XP framework
+ *
+ * $Id$
+ */
+
+ uses('unittest.TestCase');
+
+ /**
+ * TestCase
+ *
+ * @see xp://unittest.AssertionFailedError
+ */
+ class ComparisonTest extends TestCase {
+
+ /**
+ * Helper method
+ *
+ * @param var expected
+ * @param var actual
+ * @return string
+ */
+ protected function compare($expected, $actual) {
+ return create(new AssertionFailedError('', $actual, $expected))->formatDifference();
+ }
+
+ /**
+ * Test strings
+ *
+ */
+ #[@test]
+ public function stringWithCommonBeginning() {
+ $prefix= str_repeat('0123456789', 10);
+
+ $this->assertEquals(
+ 'expected: "...3abc" but was: "...Hello Worlddef"',
+ $this->compare($prefix.'3abc', $prefix.'Hello Worlddef')
+ );
+ }
+
+ /**
+ * Test strings
+ *
+ */
+ #[@test]
+ public function stringWithCommonEnding() {
+ $postfix= str_repeat('012345678', 10);
+
+ $this->assertEquals(
+ 'expected: "3..." but was: "Hello World..."',
+ $this->compare('3'.$postfix, 'Hello World'.$postfix)
+ );
+ }
+
+ /**
+ * Test strings
+ *
+ */
+ #[@test]
+ public function stringWithCommonBeginningAndEnding() {
+ $prefix= str_repeat('0123456789', 10);
+ $postfix= str_repeat('012345678', 10);
+
+ $this->assertEquals(
+ 'expected: "...3..." but was: "...Hello World..."',
+ $this->compare($prefix.'3'.$postfix, $prefix.'Hello World'.$postfix)
+ );
+ }
+
+ /**
+ * Test two strings
+ *
+ */
+ #[@test]
+ public function twoStrings() {
+ $this->assertEquals(
+ 'expected: "Hello" but was: "World"',
+ $this->compare('Hello', 'World')
+ );
+ }
+
+ /**
+ * Test two integers
+ *
+ */
+ #[@test]
+ public function twoIntegers() {
+ $this->assertEquals(
+ 'expected: 3 but was: 1',
+ $this->compare(3, 1)
+ );
+ }
+
+ /**
+ * Test two doubles
+ *
+ */
+ #[@test]
+ public function twoDoubles() {
+ $this->assertEquals(
+ 'expected: 3.1 but was: 1.1',
+ $this->compare(3.1, 1.1)
+ );
+ }
+
+ /**
+ * Test two bools
+ *
+ */
+ #[@test]
+ public function twoBools() {
+ $this->assertEquals(
+ 'expected: true but was: false',
+ $this->compare(TRUE, FALSE)
+ );
+ }
+
+ /**
+ * Test two integer arrays
+ *
+ */
+ #[@test]
+ public function twoArrays() {
+ $this->assertEquals(
+ "expected: [\n 0 => 1\n 1 => 2\n] but was: [\n 0 => 2\n 1 => 3\n]",
+ $this->compare(array(1, 2), array(2, 3))
+ );
+ }
+
+ /**
+ * Test string vs null
+ *
+ */
+ #[@test]
+ public function twoObjects() {
+ $this->assertEquals(
+ 'expected: unittest.TestCase<a> but was: unittest.TestCase<b>',
+ $this->compare(new TestCase('a'), new TestCase('b'))
+ );
+ }
+ /**
+ * Test string vs int
+ *
+ */
+ #[@test]
+ public function stringVsInt() {
+ $this->assertEquals(
+ 'expected: string<"3"> but was: int<3>',
+ $this->compare('3', 3)
+ );
+ }
+
+ /**
+ * Test string vs double
+ *
+ */
+ #[@test]
+ public function stringVsDouble() {
+ $this->assertEquals(
+ 'expected: string<"3"> but was: double<3>',
+ $this->compare('3', 3.0)
+ );
+ }
+
+ /**
+ * Test string vs null
+ *
+ */
+ #[@test]
+ public function stringVsNull() {
+ $this->assertEquals(
+ 'expected: string<"null"> but was: null',
+ $this->compare('null', NULL)
+ );
+ }
+ }
+?>
@thekid
Copy link
Author

thekid commented Jul 9, 2011

What the formatDifference() method does:

  • If actual and expected are strings, applies an algorithm to show only difference
  • If actual and expected are of the same type, show their string representations
  • Otherwise:
    • For objects, show their toString output
    • For null, show the string "null" (without quotes)
    • For anything else, show the type name and string representation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment