diff --git a/src/ParseDiff.Tests/ParseDiff.Tests.csproj b/src/ParseDiff.Tests/ParseDiff.Tests.csproj index b3631a7..45add9e 100644 --- a/src/ParseDiff.Tests/ParseDiff.Tests.csproj +++ b/src/ParseDiff.Tests/ParseDiff.Tests.csproj @@ -53,6 +53,7 @@ + diff --git a/src/ParseDiff.Tests/TestEquality.cs b/src/ParseDiff.Tests/TestEquality.cs new file mode 100644 index 0000000..bb1f28d --- /dev/null +++ b/src/ParseDiff.Tests/TestEquality.cs @@ -0,0 +1,179 @@ +namespace ParseDiff.Tests +{ + + using System; + using System.Linq; + using Microsoft.VisualStudio.TestTools.UnitTesting; + using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert; + + [TestClass] + public class TestEquality + { + [TestMethod] + public void SameDiffShouldBeEqual() + { + var diff = @" +diff --git a/file b/file +index 123..456 789 +--- a/file ++++ b/file +@@ -1,2 +1,2 @@ +- line1 ++ line2"; + + var files1 = Diff.Parse(diff, Environment.NewLine).ToArray(); + var files2 = Diff.Parse(diff, Environment.NewLine).ToArray(); + + AreEqual(files1.First(), files2.First()); + IsTrue(Enumerable.SequenceEqual(files1, files2)); + } + + + [TestMethod] + public void DifferentDiffShouldNotBeEqual() + { + var diff1 = @" +diff --git a/file b/file +index 123..456 789 +--- a/file ++++ b/file +@@ -1,2 +1,2 @@ +- line1 ++ line2"; + + var diff2 = @" +diff -r 514fc757521e lib/parsers.coffee +--- a/lib/parsers.coffee Thu Jul 09 00:56:36 2015 +0200 ++++ b/lib/parsers.coffee Fri Jul 10 16:23:43 2015 +0200 +@@ -43,6 +43,9 @@ + files[file] = { added: added, deleted: deleted } + files ++ diff: (out) -> ++ files = {} ++ + module.exports = Parsers + module.exports.version = (out) -> +"; + var files1 = Diff.Parse(diff1, Environment.NewLine).ToArray(); + var files2 = Diff.Parse(diff2, Environment.NewLine).ToArray(); + + AreNotEqual(files1.First(), files2.First()); + IsFalse(Enumerable.SequenceEqual(files1, files2)); + } + + [TestMethod] + public void DifferentChunksDiffShouldNotBeEqual() + { + var diff1 = @" +diff -r 514fc757521e lib/parsers.coffee +--- a/lib/parsers.coffee Thu Jul 09 00:56:36 2015 +0200 ++++ b/lib/parsers.coffee Fri Jul 10 16:23:43 2015 +0200 +@@ -43,6 +43,9 @@ + files[file] = { added: added, deleted: deleted } + files ++ diff: (out) -> ++ files = {} ++ + module.exports = Parsers + module.exports.version = (out) -> +"; + + var diff2 = @" +diff -r 514fc757521e lib/parsers.coffee +--- a/lib/parsers.coffee Thu Jul 09 00:56:36 2015 +0200 ++++ b/lib/parsers.coffee Fri Jul 10 16:23:43 2015 +0200 +@@ -43,6 +43,9 @@ + files[file] = { added: added, deleted: deleted } + files ++ diff: (out) -> ++ XXX files = {} ++ + module.exports = Parsers + module.exports.version = (out) -> +"; + var files1 = Diff.Parse(diff1, Environment.NewLine).ToArray(); + var files2 = Diff.Parse(diff2, Environment.NewLine).ToArray(); + + AreNotEqual(files1.First(), files2.First()); + IsFalse(Enumerable.SequenceEqual(files1, files2)); + } + + [TestMethod] + public void RebasedPatchesShouldBeEqual() + { + var patch1 = @" +# HG changeset patch +# User xxx +# Date 1483371015 -3600 +# Mon Jan 02 16:30:15 2017 +0100 +# Node ID e5c9a138e019a6c2851c2bcd7960046b65c0fa9f +# Parent b612ff73463ca19be65c7f1235c275bd011a9feb +Change 111 + +diff -r b612ff73463c -r e5c9a138e019 1.txt +--- a/1.txt Thu Dec 22 14:58:46 2016 +0100 ++++ b/1.txt Mon Jan 02 16:30:15 2017 +0100 +@@ -1,5 +1,5 @@ + qwesfsafadsadsadsadsadsad +-zxcxzczxcxc ++zxCHANGEzxcxc + + +xxx +"; + var patch2 = @" +# HG changeset patch +# User xxx +# Date 1483371015 -3600 +# Mon Jan 02 16:30:15 2017 +0100 +# Node ID 43339e170990fe2873b2866d5d916b6ec3ae0956 +# Parent 4afd4b93aa45455be267d5e4541094daea9b02f3 +Change 111 + +diff -r 4afd4b93aa45 -r 43339e170990 1.txt +--- a/1.txt Thu Dec 22 14:59:09 2016 +0100 ++++ b/1.txt Mon Jan 02 16:30:15 2017 +0100 +@@ -1,5 +1,5 @@ + qwesfsafadsadsadsadsadsad +-zxcxzczxcxc ++zxCHANGEzxcxc + + +xxx +"; + + var files1 = Diff.Parse(patch1).ToArray(); + var files2 = Diff.Parse(patch2).ToArray(); + + AreEqual(files1.First(), files2.First()); + IsTrue(Enumerable.SequenceEqual(files1, files2)); + } + + [TestMethod] + public void DifferentIndexesShouldNotBeEqual() + { + var diffWithIndexLine = @" +diff --git a/file b/file +index 123..456 789 +--- a/file ++++ b/file +@@ -1,2 +1,2 @@ +- line1 ++ line2"; + var diffWithNoIndexLine = @" +diff --git a/file b/file +--- a/file ++++ b/file +@@ -1,2 +1,2 @@ +- line1 ++ line2"; + + var files1 = Diff.Parse(diffWithIndexLine, Environment.NewLine).ToArray(); + var files2 = Diff.Parse(diffWithNoIndexLine, Environment.NewLine).ToArray(); + + AreNotEqual(files1.First(), files2.First()); + AreNotEqual(files2.First(), files1.First()); + IsFalse(Enumerable.SequenceEqual(files1, files2)); + } + } +} diff --git a/src/ParseDiff/ChunkDiff.cs b/src/ParseDiff/ChunkDiff.cs index e8b3a34..5d22c14 100644 --- a/src/ParseDiff/ChunkDiff.cs +++ b/src/ParseDiff/ChunkDiff.cs @@ -1,8 +1,10 @@ namespace ParseDiff { + using System; using System.Collections.Generic; + using System.Linq; - public class ChunkDiff + public class ChunkDiff : IEquatable { public ChunkDiff(string content, int oldStart, int oldLines, int newStart, int newLines) { @@ -24,5 +26,36 @@ public ChunkDiff(string content, int oldStart, int oldLines, int newStart, int n public int NewStart { get; } public int NewLines { get; } + + public bool Equals(ChunkDiff other) + { + return + Equals(Content, other.Content) && + Equals(OldStart, other.OldStart) && + Equals(OldLines, other.OldLines) && + Equals(NewStart, other.NewStart) && + Equals(NewLines, other.NewLines) && + Enumerable.SequenceEqual(Changes, other.Changes); + } + + public override bool Equals(object obj) + { + return Equals(obj as ChunkDiff); + } + + public override int GetHashCode() + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + hash = hash * 23 + Content?.GetHashCode() ?? 0; + hash = hash * 23 + OldStart; + hash = hash * 23 + OldLines; + hash = hash * 23 + NewStart; + hash = hash * 23 + NewLines; + hash = hash * 23 + Changes.GetHashCode(); + return hash; + } + } } } diff --git a/src/ParseDiff/FileDiff.cs b/src/ParseDiff/FileDiff.cs index 1ac809c..f6376f8 100644 --- a/src/ParseDiff/FileDiff.cs +++ b/src/ParseDiff/FileDiff.cs @@ -5,7 +5,7 @@ using System.Linq; using System.Text.RegularExpressions; - public class FileDiff + public class FileDiff : IEquatable { public ICollection Chunks { get; } = new List(); @@ -188,5 +188,46 @@ private static string parseFileFallback(string s) ? s.Substring(2) : s; } + + public bool Equals(FileDiff other) + { + return + Equals(Deletions, other.Deletions) && + Equals(Additions, other.Additions) && + Equals(To, other.To) && + Equals(From, other.From) && + Equals(Type, other.Type) && + IndexEquals(other.Index) && + Enumerable.SequenceEqual(Chunks, other.Chunks); + } + + private bool IndexEquals(IEnumerable otherIndex) + { + return + Index == null + ? otherIndex == null + : (otherIndex != null && Enumerable.SequenceEqual(Index, otherIndex)); + } + + public override bool Equals(object obj) + { + return Equals(obj as FileDiff); + } + + public override int GetHashCode() + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + hash = hash * 23 + Deletions; + hash = hash * 23 + Additions; + hash = hash * 23 + To?.GetHashCode() ?? 0; + hash = hash * 23 + From?.GetHashCode() ?? 0; + hash = hash * 23 + Type.GetHashCode(); + hash = hash * 23 + Index?.GetHashCode() ?? 0; + hash = hash * 23 + Chunks.GetHashCode(); + return hash; + } + } } } diff --git a/src/ParseDiff/LineDiff.cs b/src/ParseDiff/LineDiff.cs index fac8f62..f97fb44 100644 --- a/src/ParseDiff/LineDiff.cs +++ b/src/ParseDiff/LineDiff.cs @@ -1,6 +1,8 @@ namespace ParseDiff { - public class LineDiff + using System; + + public class LineDiff : IEquatable { public LineDiff(LineChangeType type, int index, string content) { @@ -32,5 +34,34 @@ public LineDiff(int oldIndex, int newIndex, string content) public int NewIndex { get; } public LineChangeType Type { get; } + + public bool Equals(LineDiff other) + { + return + Equals(Content, other.Content) && + Equals(Index, other.Index) && + Equals(OldIndex, other.OldIndex) && + Equals(NewIndex, other.NewIndex) && + Equals(Type, other.Type); + } + + public override bool Equals(object obj) + { + return Equals(obj as LineDiff); + } + + public override int GetHashCode() + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + hash = hash * 23 + Content?.GetHashCode() ?? 0; + hash = hash * 23 + Index; + hash = hash * 23 + OldIndex; + hash = hash * 23 + NewIndex; + hash = hash * 23 + Type.GetHashCode(); + return hash; + } + } } }