RawTextComparator.WS_IGNORE_CHANGE must not compare whitespace

Only the presence or absence of whitespace is significant; but not the
actual whitespace characters. Don't compare whitespace bytes.

Compare the C git implementation at [1].

[1] https://github.com/git/git/blob/0d0e1e8/xdiff/xutils.c#L173

Bug: 563570
Change-Id: I2d0522b637ba6b5c8b911b3376a9df5daa9d4c27
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextIgnoreWhitespaceChangeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextIgnoreWhitespaceChangeTest.java
index b271a04..73b2a72 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextIgnoreWhitespaceChangeTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextIgnoreWhitespaceChangeTest.java
@@ -75,4 +75,32 @@
 		assertTrue(cmp.equals(a, 5, b, 5));
 		assertTrue(cmp.equals(b, 5, a, 5));
 	}
+
+	@Test
+	public void testEqualsWithTabs() {
+		RawText a = new RawText(
+				Constants.encodeASCII("a\tb\t \na\tb\t c \n  foo\na b\na  b"));
+		RawText b = new RawText(
+				Constants.encodeASCII("a b \na b c\n\tfoo\nab\na \tb"));
+
+		// "a\tb\t \n" == "a b \n"
+		assertTrue(cmp.equals(a, 0, b, 0));
+		assertTrue(cmp.equals(b, 0, a, 0));
+
+		// "a\tb\t c \n" == "a b c\n"
+		assertTrue(cmp.equals(a, 1, b, 1));
+		assertTrue(cmp.equals(b, 1, a, 1));
+
+		// " foo" == "\tfoo"
+		assertTrue(cmp.equals(a, 2, b, 2));
+		assertTrue(cmp.equals(b, 2, a, 2));
+
+		// "a b" != "ab"
+		assertFalse(cmp.equals(a, 3, b, 3));
+		assertFalse(cmp.equals(b, 3, a, 3));
+
+		// "a b" == "a \tb "
+		assertTrue(cmp.equals(a, 4, b, 4));
+		assertTrue(cmp.equals(b, 4, a, 4));
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawTextComparator.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawTextComparator.java
index 508d07c..0c41b85 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawTextComparator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RawTextComparator.java
@@ -191,21 +191,15 @@
 			be = trimTrailingWhitespace(b.content, bs, be);
 
 			while (as < ae && bs < be) {
-				byte ac = a.content[as];
-				byte bc = b.content[bs];
+				byte ac = a.content[as++];
+				byte bc = b.content[bs++];
 
-				if (ac != bc)
-					return false;
-
-				if (isWhitespace(ac))
+				if (isWhitespace(ac) && isWhitespace(bc)) {
 					as = trimLeadingWhitespace(a.content, as, ae);
-				else
-					as++;
-
-				if (isWhitespace(bc))
 					bs = trimLeadingWhitespace(b.content, bs, be);
-				else
-					bs++;
+				} else if (ac != bc) {
+					return false;
+				}
 			}
 			return as == ae && bs == be;
 		}
@@ -215,12 +209,12 @@
 			int hash = 5381;
 			end = trimTrailingWhitespace(raw, ptr, end);
 			while (ptr < end) {
-				byte c = raw[ptr];
-				hash = ((hash << 5) + hash) + (c & 0xff);
-				if (isWhitespace(c))
+				byte c = raw[ptr++];
+				if (isWhitespace(c)) {
 					ptr = trimLeadingWhitespace(raw, ptr, end);
-				else
-					ptr++;
+					c = ' ';
+				}
+				hash = ((hash << 5) + hash) + (c & 0xff);
 			}
 			return hash;
 		}