diff --git a/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs b/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs index 304b1ed96..ae363e57d 100644 --- a/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs +++ b/ICSharpCode.Decompiler/Tests/DecompilerTestBase.cs @@ -6,6 +6,7 @@ using System.Linq; using System.Text; using ICSharpCode.Decompiler.Ast; +using ICSharpCode.Decompiler.Tests.Helpers; using Microsoft.CSharp; using Mono.Cecil; using NUnit.Framework; @@ -19,7 +20,7 @@ namespace ICSharpCode.Decompiler.Tests var lines = File.ReadAllLines(Path.Combine(@"..\..\Tests", samplesFileName)); var testCode = RemoveIgnorableLines(lines); var decompiledTestCode = RoundtripCode(testCode); - Assert.AreEqual(testCode, decompiledTestCode); + CodeAssert.AreEqual(testCode, decompiledTestCode); } static string RemoveIgnorableLines(IEnumerable lines) diff --git a/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs b/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs new file mode 100644 index 000000000..e403bf898 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/Helpers/CodeAssert.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using DiffLib; +using NUnit.Framework; + +namespace ICSharpCode.Decompiler.Tests.Helpers +{ + public class CodeAssert + { + public static void AreEqual(string input1, string input2) + { + var diff = new StringWriter(); + if (!Compare(input1, input2, diff)) { + Assert.Fail(diff.ToString()); + } + } + + static bool Compare(string input1, string input2, StringWriter diff) + { + var differ = new AlignedDiff( + NormalizeAndSplitCode(input1), + NormalizeAndSplitCode(input2), + new CodeLineEqualityComparer(), + new StringSimilarityComparer(), + new StringAlignmentFilter()); + + bool result = true, ignoreChange; + + int line1 = 0, line2 = 0; + + foreach (var change in differ.Generate()) { + switch (change.Change) { + case ChangeType.Same: + diff.Write("{0,4} {1,4} ", ++line1, ++line2); + diff.Write(" "); + diff.WriteLine(change.Element1); + break; + case ChangeType.Added: + diff.Write(" {1,4} ", line1, ++line2); + result &= ignoreChange = ShouldIgnoreChange(change.Element2); + diff.Write(ignoreChange ? " " : " + "); + diff.WriteLine(change.Element2); + break; + case ChangeType.Deleted: + diff.Write("{0,4} ", ++line1, line2); + result &= ignoreChange = ShouldIgnoreChange(change.Element1); + diff.Write(ignoreChange ? " " : " - "); + diff.WriteLine(change.Element1); + break; + case ChangeType.Changed: + diff.Write("{0,4} ", ++line1, line2); + result = false; + diff.Write("(-) "); + diff.WriteLine(change.Element1); + diff.Write(" {1,4} ", line1, ++line2); + diff.Write("(+) "); + diff.WriteLine(change.Element2); + break; + } + } + + return result; + } + + class CodeLineEqualityComparer : IEqualityComparer + { + private IEqualityComparer baseComparer = EqualityComparer.Default; + + public bool Equals(string x, string y) + { + return baseComparer.Equals( + NormalizeLine(x), + NormalizeLine(y) + ); + } + + public int GetHashCode(string obj) + { + return baseComparer.GetHashCode(NormalizeLine(obj)); + } + } + + private static string NormalizeLine(string line) + { + line = line.Trim(); + var index = line.IndexOf("//"); + if (index >= 0) { + return line.Substring(0, index); + } else { + return line; + } + } + + private static bool ShouldIgnoreChange(string line) + { + // for the result, we should ignore blank lines and added comments + return NormalizeLine(line) == string.Empty; + } + + private static IEnumerable NormalizeAndSplitCode(string input) + { + return input.Split(new[] { "\r\n", "\n\r", "\n", "\r" }, StringSplitOptions.None); + } + } +} diff --git a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj index 464daca00..662695e6b 100644 --- a/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler/Tests/ICSharpCode.Decompiler.Tests.csproj @@ -38,6 +38,9 @@ TRACE + + ..\..\packages\DiffLib.1.0.0.55\lib\net35-Client\DiffLib.dll + False .\nunit.framework.dll @@ -54,12 +57,14 @@ + + @@ -101,4 +106,4 @@ - \ No newline at end of file + diff --git a/ICSharpCode.Decompiler/Tests/IncrementDecrement.cs b/ICSharpCode.Decompiler/Tests/IncrementDecrement.cs index e4aa729c9..02a72190f 100644 --- a/ICSharpCode.Decompiler/Tests/IncrementDecrement.cs +++ b/ICSharpCode.Decompiler/Tests/IncrementDecrement.cs @@ -200,7 +200,12 @@ public class IncrementDecrement // { // return this.M()[name]++; // } - + +// public unsafe int PostIncrementOfPointer(int* ptr) +// { +// return *(ptr++); +// } + public int PostIncrementInstanceField() { return this.M().Field--; @@ -225,9 +230,4 @@ public class IncrementDecrement { return (*this.GetPointer())++; } - -// public unsafe int PostIncrementOfPointer(int* ptr) -// { -// return *(ptr++); -// } } diff --git a/ICSharpCode.Decompiler/Tests/TestRunner.cs b/ICSharpCode.Decompiler/Tests/TestRunner.cs index 1befefed0..dfef5cf9c 100644 --- a/ICSharpCode.Decompiler/Tests/TestRunner.cs +++ b/ICSharpCode.Decompiler/Tests/TestRunner.cs @@ -5,8 +5,11 @@ using System; using System.CodeDom.Compiler; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; +using DiffLib; using ICSharpCode.Decompiler.Ast; +using ICSharpCode.Decompiler.Tests.Helpers; using Microsoft.CSharp; using Mono.Cecil; using NUnit.Framework; @@ -82,7 +85,7 @@ namespace ICSharpCode.Decompiler.Tests TestFile(@"..\..\Tests\UnsafeCode.cs"); } - [Test, Ignore("IncrementArrayLocation not yet supported")] + [Test] public void ValueTypes() { TestFile(@"..\..\Tests\ValueTypes.cs"); @@ -109,52 +112,9 @@ namespace ICSharpCode.Decompiler.Tests new Helpers.RemoveCompilerAttribute().Run(decompiler.CompilationUnit); StringWriter output = new StringWriter(); decompiler.GenerateCode(new PlainTextOutput(output)); - StringWriter diff = new StringWriter(); - if (!Compare(code, output.ToString(), diff)) { - throw new Exception("Test failure." + Environment.NewLine + diff.ToString()); - } + CodeAssert.AreEqual(code, output.ToString()); } - - static bool Compare(string input1, string input2, StringWriter diff) - { - bool ok = true; - int numberOfContinuousMistakes = 0; - StringReader r1 = new StringReader(input1); - StringReader r2 = new StringReader(input2); - string line1, line2; - while ((line1 = r1.ReadLine()) != null) { - string trimmed = line1.Trim(); - if (trimmed.Length == 0 || trimmed.StartsWith("//", StringComparison.Ordinal) | trimmed.StartsWith("#", StringComparison.Ordinal)) { - diff.WriteLine(" " + line1); - continue; - } - line2 = r2.ReadLine(); - while (line2 != null && string.IsNullOrWhiteSpace(line2)) - line2 = r2.ReadLine(); - if (line2 == null) { - ok = false; - diff.WriteLine("-" + line1); - continue; - } - if (line1.Trim() != line2.Trim()) { - ok = false; - if (numberOfContinuousMistakes++ > 5) - return false; - diff.WriteLine("-" + line1); - diff.WriteLine("+" + line2); - } else { - if (numberOfContinuousMistakes > 0) - numberOfContinuousMistakes--; - diff.WriteLine(" " + line1); - } - } - while ((line2 = r2.ReadLine()) != null) { - ok = false; - diff.WriteLine("+" + line2); - } - return ok; - } - + static AssemblyDefinition Compile(string code) { CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary { { "CompilerVersion", "v4.0" } }); diff --git a/ICSharpCode.Decompiler/Tests/packages.config b/ICSharpCode.Decompiler/Tests/packages.config new file mode 100644 index 000000000..4d992b424 --- /dev/null +++ b/ICSharpCode.Decompiler/Tests/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/packages/DiffLib.1.0.0.55/DiffLib.1.0.0.55.nupkg b/packages/DiffLib.1.0.0.55/DiffLib.1.0.0.55.nupkg new file mode 100644 index 000000000..b03c58b99 Binary files /dev/null and b/packages/DiffLib.1.0.0.55/DiffLib.1.0.0.55.nupkg differ diff --git a/packages/DiffLib.1.0.0.55/lib/net35-Client/DiffLib.XML b/packages/DiffLib.1.0.0.55/lib/net35-Client/DiffLib.XML new file mode 100644 index 000000000..beb4c26cd --- /dev/null +++ b/packages/DiffLib.1.0.0.55/lib/net35-Client/DiffLib.XML @@ -0,0 +1,641 @@ + + + + DiffLib + + + + + This class holds a single collection from either the first or the second, or both, + collections given to the class, along + with the type of change that the elements produce. + + + + + Initializes a new instance of . + + + The type of change this details. + + + The element from the first collection. If is , then + this parameter has no meaning. + + + The element from the second collection. If is , then + this parameter has no meaning. + + + + + Indicates whether the current object is equal to another object of the same type. + + + true if the current object is equal to the parameter; otherwise, false. + + An object to compare with this object. + + + + Determines whether the specified is equal to the current . + + + true if the specified is equal to the current ; otherwise, false. + + The to compare with the current . 2 + + + + Serves as a hash function for a particular type. + + + A hash code for the current . + + 2 + + + + Returns a that represents the current . + + + A that represents the current . + + 2 + + + + The type of change this details. + + + + + The element from the first collection. If is , then + the value of this property has no meaning. + + + + + The element from the second collection. If is , then + the value of this property has no meaning. + + + + + This enum is used by to specify how + the two elements from the two collections relate. + + + + + The two elements are the same. + + + + + The second element was added in the second collection. + + + + + The first element was removed from the second collection. + + + + + The first element was changed/replaced with the second element in the second collection. + + + + + This class implements the basic diff algorithm by recursively applying the Longest Common Substring + on pieces of the collections, and reporting sections that are similar, and those that are not, + in the appropriate sequence. + + + The types of elements in the collections being compared. + + + + + Initializes a new instance of + using the default instance for the + type. + + + The first collection of items. + + + The second collection of items. + + + is null. + - or - + is null. + + + + + Initializes a new instance of . + + + The first collection of items. + + + The second collection of items. + + + The that will be used to compare elements from + with elements from . + + + is null. + - or - + is null. + - or - + is null. + + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Generates the diff between the two collections. + + + + + This class contains a single section of diff output from the + method. + + + + + Initializes a new instance of . + + + If true, then the section specifies a section from the first + collection that is equal to a section from the second collection; + otherwise, if false, then the section from the first + collection was replaced with the section from the second collection. + + + The length of the section in the first collection. Can be 0 if + the section specifies that new content was added in the second + collection. + + + The length of the section in the second collection. Can be 0 if + the section specifies that old content was deleted in the second + collection. + + + is negative. + - or - + is negative. + + + is true but is not equal to . + + + + + Indicates whether the current object is equal to another object of the same type. + + + true if the current object is equal to the parameter; otherwise, false. + + An object to compare with this object. + + + + Determines whether the specified is equal to the current . + + + true if the specified is equal to the current ; otherwise, false. + + The to compare with the current . 2 + + + + Serves as a hash function for a particular type. + + + A hash code for the current . + + 2 + + + + Returns a that represents the current . + + + A that represents the current . + + 2 + + + + Gets whether the specifies equal sections in the two + collections, or differing sections. + + + If true, then the section specifies a section from the first + collection that is equal to a section from the second collection; + otherwise, if false, then the section from the first + collection was replaced with the section from the second collection. + + + + + The length of the section in the first collection. + + + + + The length of the section in the second collection. + + + + + This interface must be implemented by classes that will do similarity-filtering + during alignment () to determine + if two aligned elements are similar enough to report + them as a change, instead of as a delete plus an add. + + + The type of elements being compared. + + + + + Determines if the two values are similar enough to align them + as a change, instead of not aligning them but reporting them + as a delete plus an add instead. + + + The first value to compare against . + + + The second value to compare against . + + + true if the two values are similar enough to report + them as a change; false if the two values aren't similar enough + but needs to be reported as a delete plus an add. + + + + + This interface must be implemented by classes that will do similarity-calculation + for use with the class. + + + The type of elements being compared. + + + + + Does a similarity comparison between the two values and returns their + similarity, a value ranging from 0.0 to 1.0, where 0.0 means they're + completely different and 1.0 means they have the same value. + + + The first value to compare. + + + The second value to compare. + + + A value ranging from 0.0 to 1.0, where 0.0 means they're + completely different and 1.0 means they have the same value. + + + + + This class implements the LCS algorithm, to find the longest common substring that exists + in two collections, and return the locations of those substrings. + + + The types of elements in the collections being compared. + + + + + Initializes a new instance of the class + using the default instance for the + type. + + + The first collection of items. + + + The second collection of items. + + + is null. + - or - + is null. + + + + + Initializes a new instance of the class. + + + The first collection of items. + + + The second collection of items. + + + The that will be used to compare elements from + with elements from . + + + is null. + - or - + is null. + - or - + is null. + + + + + Finds the longest common substring and returns its position in the two collections, and + its length, or null if no such common substring can be located. + + + A containing the positions of the two substrings, one position + for each collection, both 0-based, and the length of the substring. If no common substring can be found, null + will be returned. + + + + + Finds the longest common substring and returns its position in the two collections, and + its length, or null if no such common substring can be located. + + + The starting position in the first collection, 0-based. Included in the search. + + + The ending position in the first collection, 0-based. Not included in the search. + + + The starting position in the second collection, 0-based. Included in the search. + + + The ending position in the second collection, 0-based. Not included in the search. + + + A containing the positions of the two substrings, one position + for each collection, both 0-based, and the length of the substring. If no common substring can be found, null + will be returned. + + + is less than 0. + - or - + is greater than . + - or - + is greater than the length of the first collection. + - or - + is less than 0. + - or - + is greater than . + - or - + is greater than the length of the second collection. + + + + + This class holds the result of calling . + + + + + Initializes a new instance of . + + + The position in the first collection, 0-based. + + + The position in the second collection, 0-based. + + + The length of the common substring. + + + is negative. + - or - + is negative. + - or - + is zero or negative. + + + + + Indicates whether the current object is equal to another object of the same type. + + + true if the current object is equal to the parameter; otherwise, false. + + An object to compare with this object. + + + + Determines whether the specified is equal to the current . + + + true if the specified is equal to the current ; otherwise, false. + + The to compare with the current . 2 + + + + Serves as a hash function for a particular type. + + + A hash code for the current . + + 2 + + + + Returns a that represents the current . + + + A that represents the current . + + 2 + + + + The position in the first collection, 0-based. + + + + + The position in the second collection, 0-based. + + + + + The length of the common substring. + + + + + This class implements a slightly more advanced diff algorithm than by + taking the output from and attempting to align individual elements inside + replace-blocks. This is mostly suitable for text file diffs. + + + The types of elements in the collections being compared. + + + + + Initializes a new instance of . + + + The first collection of items. + + + The second collection of items. + + + The that will be used to compare elements from + with elements from . + + + The that will be used to attempt to align elements + inside blocks that consists of elements from the first collection being replaced + with elements from the second collection. + + + The that will be used to determine if + two aligned elements are similar enough to be report them as a change from + one to another, or to report them as one being deleted and the other added in + its place. + + + is null. + - or - + is null. + - or - + is null. + - or - + is null. + + + + + Returns an enumerator that iterates through the collection. + + + A that can be used to iterate through the collection. + + 1 + + + + Generates the diff, one line of output at a time. + + + A collection of objects, one for + each line in the first or second collection (sometimes one instance for a line + from both, when lines are equal or similar.) + + + + + This class implements for strings, doing a very basic "diff" between the two, + and calculating how much of the text occurs in both. + + + + + Does a similarity comparison between the two values and returns their + similarity, a value ranging from 0.0 to 1.0, where 0.0 means they're + completely different and 1.0 means they have the same value. + + + The first value to compare. + + + The second value to compare. + + + A value ranging from 0.0 to 1.0, where 0.0 means they're + completely different and 1.0 means they have the same value. + + + + + This class implements for strings, doing a very basic "diff" between the two, + and calculating how much of the text occurs in both. + + + + + Initializes a new instance of the class. + + + + + Initializes a new instance of the class. + + + The diff predicate used to determine if the strings are + similar enough (see for details. + + is null. + + + + Determines if the two values are similar enough to align them + as a change, instead of not aligning them but reporting them + as a delete plus an add instead. + + + The first value to compare against . + + + The second value to compare against . + + + true if the two values are similar enough to report + them as a change; false if the two values aren't similar enough + but needs to be reported as a delete plus an add. + + + + + This delegate is used by to + determine if the two strings are similar enough to report them + as a change, instead of as a delete plus and add. + + + The first string to compare. + + + The second string to compare. + + + The diff between and . + + + true if the strings are similar enough (reported as a change); + otherwise, false (reported as a delete plus an add.) + + + + diff --git a/packages/DiffLib.1.0.0.55/lib/net35-Client/DiffLib.dll b/packages/DiffLib.1.0.0.55/lib/net35-Client/DiffLib.dll new file mode 100644 index 000000000..d5963dea0 Binary files /dev/null and b/packages/DiffLib.1.0.0.55/lib/net35-Client/DiffLib.dll differ diff --git a/packages/repositories.config b/packages/repositories.config new file mode 100644 index 000000000..b50e06119 --- /dev/null +++ b/packages/repositories.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file