mirror of https://github.com/icsharpcode/ILSpy.git
13 changed files with 438 additions and 36 deletions
@ -0,0 +1,114 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Text; |
||||||
|
using System.IO; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Tests |
||||||
|
{ |
||||||
|
static class CodeSampleFileParser |
||||||
|
{ |
||||||
|
public static IEnumerable<string> ListSections(string s) |
||||||
|
{ |
||||||
|
var query = from line in ToLines(s) |
||||||
|
let sectionName = ReadSectionName(line) |
||||||
|
where sectionName != null |
||||||
|
select sectionName; |
||||||
|
return query; |
||||||
|
} |
||||||
|
|
||||||
|
public static string GetSection(string sectionName, string s) |
||||||
|
{ |
||||||
|
var lines = ToLines(s); |
||||||
|
|
||||||
|
bool sectionFound = false; |
||||||
|
var sectionText = new StringBuilder(); |
||||||
|
|
||||||
|
Action<string> parser = null; |
||||||
|
|
||||||
|
Action<string> commonSectionReader = line => |
||||||
|
{ |
||||||
|
if (IsCommonSectionEnd(line)) |
||||||
|
parser = null; |
||||||
|
else |
||||||
|
sectionText.AppendLine(line); |
||||||
|
}; |
||||||
|
|
||||||
|
Action<string> namedSectionReader = line => |
||||||
|
{ |
||||||
|
string name = ReadSectionName(line); |
||||||
|
if (name == null) |
||||||
|
sectionText.AppendLine(line); |
||||||
|
else if (name != sectionName) |
||||||
|
parser = null; |
||||||
|
}; |
||||||
|
|
||||||
|
Action<string> defaultReader = line => |
||||||
|
{ |
||||||
|
if (IsCommonSectionStart(line)) |
||||||
|
parser = commonSectionReader; |
||||||
|
else if (ReadSectionName(line) == sectionName) |
||||||
|
{ |
||||||
|
parser = namedSectionReader; |
||||||
|
sectionFound = true; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
foreach(var line in lines) |
||||||
|
{ |
||||||
|
(parser ?? defaultReader)(line); |
||||||
|
} |
||||||
|
|
||||||
|
if (sectionFound) |
||||||
|
return sectionText.ToString(); |
||||||
|
else |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
public static bool IsCommentOrBlank(string s) |
||||||
|
{ |
||||||
|
if(String.IsNullOrWhiteSpace(s)) |
||||||
|
return true; |
||||||
|
return s.Trim().StartsWith("//"); |
||||||
|
} |
||||||
|
|
||||||
|
public static string ConcatLines(IEnumerable<string> lines) |
||||||
|
{ |
||||||
|
var buffer = new StringBuilder(); |
||||||
|
foreach (var line in lines) |
||||||
|
{ |
||||||
|
buffer.AppendLine(line); |
||||||
|
} |
||||||
|
return buffer.ToString(); |
||||||
|
} |
||||||
|
|
||||||
|
static string ReadSectionName(string line) |
||||||
|
{ |
||||||
|
line = line.TrimStart(); |
||||||
|
if (line.StartsWith("//$$")) |
||||||
|
return line.Substring(4).Trim(); |
||||||
|
else |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
static bool IsCommonSectionStart(string line) |
||||||
|
{ |
||||||
|
return line.Trim() == "//$CS"; |
||||||
|
} |
||||||
|
|
||||||
|
static bool IsCommonSectionEnd(string line) |
||||||
|
{ |
||||||
|
return line.Trim() == "//$CE"; |
||||||
|
} |
||||||
|
|
||||||
|
static IEnumerable<string> ToLines(string s) |
||||||
|
{ |
||||||
|
var reader = new StringReader(s); |
||||||
|
string line; |
||||||
|
while ((line = reader.ReadLine()) != null) |
||||||
|
{ |
||||||
|
yield return line; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
using System; |
||||||
|
namespace aa |
||||||
|
{ |
||||||
|
public static class CustomAtributes |
||||||
|
{ |
||||||
|
[Flags] |
||||||
|
public enum EnumWithFlag |
||||||
|
{ |
||||||
|
All = 15, |
||||||
|
None = 0, |
||||||
|
Item1 = 1, |
||||||
|
Item2 = 2, |
||||||
|
Item3 = 4, |
||||||
|
Item4 = 8 |
||||||
|
} |
||||||
|
[AttributeUsage(AttributeTargets.All)] |
||||||
|
public class MyAttribute : Attribute |
||||||
|
{ |
||||||
|
public MyAttribute(CustomAtributes.EnumWithFlag en) |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
|
[CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.Item1 | CustomAtributes.EnumWithFlag.Item2)] |
||||||
|
private static int field; |
||||||
|
[CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.All)] |
||||||
|
public static string Property |
||||||
|
{ |
||||||
|
get |
||||||
|
{ |
||||||
|
return "aa"; |
||||||
|
} |
||||||
|
} |
||||||
|
[Obsolete("some message")] |
||||||
|
public static void ObsoletedMethod() |
||||||
|
{ |
||||||
|
Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, AttributeTargets.Property | AttributeTargets.Field); |
||||||
|
AttributeTargets attributeTargets = AttributeTargets.Property | AttributeTargets.Field; |
||||||
|
Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, attributeTargets); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -1,27 +0,0 @@ |
|||||||
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
|
||||||
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
|
||||||
|
|
||||||
using System; |
|
||||||
|
|
||||||
|
|
||||||
public static class CustomAtributes |
|
||||||
{ |
|
||||||
[Flags] |
|
||||||
public enum EnumWithFlag |
|
||||||
{ |
|
||||||
// Item1,
|
|
||||||
Item2 |
|
||||||
} |
|
||||||
[AttributeUsage(AttributeTargets.All)] |
|
||||||
public class MyAttribute : Attribute |
|
||||||
{ |
|
||||||
} |
|
||||||
[Obsolete("some message")] |
|
||||||
public static void ObsoletedMethod() |
|
||||||
{ |
|
||||||
//Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, (AttributeTargets)(AttributeTargets.Property | AttributeTargets.Field));
|
|
||||||
Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, AttributeTargets.Property | AttributeTargets.Field); |
|
||||||
AttributeTargets attributeTargets = AttributeTargets.Property | AttributeTargets.Field; |
|
||||||
Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, attributeTargets); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,81 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
//$CS
|
||||||
|
using System; |
||||||
|
//$CE
|
||||||
|
|
||||||
|
//$$ ParameterlessAttributeUsage
|
||||||
|
namespace ParameterLessAttributeUsage |
||||||
|
{ |
||||||
|
[Flags] |
||||||
|
public enum EnumWithFlagsAttribute |
||||||
|
{ |
||||||
|
None |
||||||
|
} |
||||||
|
} |
||||||
|
//$$ AttributeWithEnumArgument
|
||||||
|
namespace AttributeWithEnumArgument |
||||||
|
{ |
||||||
|
[AttributeUsage(AttributeTargets.All)] |
||||||
|
public class MyAttributeAttribute : Attribute |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
|
//$$ AttributeWithEnumExpressionArgument
|
||||||
|
namespace AttributeWithEnumExpressionArgument |
||||||
|
{ |
||||||
|
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Interface)] |
||||||
|
public class MyAttributeAttribute : Attribute |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
|
//$$ AttributeWithStringExpressionArgument
|
||||||
|
namespace AttributeWithStringExpressionArgument |
||||||
|
{ |
||||||
|
[Obsolete("message")] |
||||||
|
public class ObsoletedClass |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
|
//$$ AttributeAppliedToEvent (ignored)
|
||||||
|
namespace AttributeAppliedToEvent |
||||||
|
{ |
||||||
|
[AttributeUsage(AttributeTargets.Event)] |
||||||
|
public class MyAttributeAttribute : Attribute |
||||||
|
{ |
||||||
|
} |
||||||
|
public class TestClass |
||||||
|
{ |
||||||
|
[MyAttribute] |
||||||
|
public event EventHandler MyEvent; |
||||||
|
} |
||||||
|
} |
||||||
|
//$$ AttributeAppliedToField
|
||||||
|
namespace AttributeAppliedToField |
||||||
|
{ |
||||||
|
[AttributeUsage(AttributeTargets.Field)] |
||||||
|
public class MyAttributeAttribute : Attribute |
||||||
|
{ |
||||||
|
} |
||||||
|
public class TestClass |
||||||
|
{ |
||||||
|
[MyAttribute] |
||||||
|
public int Field; |
||||||
|
} |
||||||
|
} |
||||||
|
//$$ AttributeAppliedToMethod
|
||||||
|
namespace AttributeAppliedToMethod |
||||||
|
{ |
||||||
|
[AttributeUsage(AttributeTargets.Method)] |
||||||
|
public class MyAttributeAttribute : Attribute |
||||||
|
{ |
||||||
|
} |
||||||
|
public class TestClass |
||||||
|
{ |
||||||
|
[MyAttribute] |
||||||
|
public void Method() |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Text; |
||||||
|
using MbUnit.Framework; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Tests.CustomAttributes |
||||||
|
{ |
||||||
|
public class CustomAttributeTests : DecompilerTestBase |
||||||
|
{ |
||||||
|
[StaticTestFactory] |
||||||
|
public static IEnumerable<Test> CustomAttributeSamples() |
||||||
|
{ |
||||||
|
return GenerateSectionTests(@"CustomAttributes\CustomAttributeSamples.cs"); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void CustomAttributesMultiTest() |
||||||
|
{ |
||||||
|
ValidateFileRoundtrip(@"CustomAttributes\CustomAttributes.cs"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
|
||||||
|
// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
|
||||||
|
|
||||||
|
using System; |
||||||
|
|
||||||
|
|
||||||
|
namespace aa |
||||||
|
{ |
||||||
|
public static class CustomAtributes |
||||||
|
{ |
||||||
|
[Flags] |
||||||
|
public enum EnumWithFlag |
||||||
|
{ |
||||||
|
All = 15, |
||||||
|
None = 0, |
||||||
|
Item1 = 1, |
||||||
|
Item2 = 2, |
||||||
|
Item3 = 4, |
||||||
|
Item4 = 8 |
||||||
|
} |
||||||
|
[AttributeUsage(AttributeTargets.All)] |
||||||
|
public class MyAttribute : Attribute |
||||||
|
{ |
||||||
|
public MyAttribute(CustomAtributes.EnumWithFlag en) |
||||||
|
{ |
||||||
|
} |
||||||
|
} |
||||||
|
[CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.Item1 | CustomAtributes.EnumWithFlag.Item2)] |
||||||
|
private static int field; |
||||||
|
[CustomAtributes.MyAttribute(CustomAtributes.EnumWithFlag.All)] |
||||||
|
public static string Property |
||||||
|
{ |
||||||
|
get |
||||||
|
{ |
||||||
|
return "aa"; |
||||||
|
} |
||||||
|
} |
||||||
|
[Obsolete("some message")] |
||||||
|
public static void ObsoletedMethod() |
||||||
|
{ |
||||||
|
//Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, (AttributeTargets)(AttributeTargets.Property | AttributeTargets.Field));
|
||||||
|
Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, AttributeTargets.Property | AttributeTargets.Field); |
||||||
|
AttributeTargets attributeTargets = AttributeTargets.Property | AttributeTargets.Field; |
||||||
|
Console.WriteLine("{0} $$$ {1}", AttributeTargets.Interface, attributeTargets); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Text; |
||||||
|
using Mono.Cecil; |
||||||
|
using System.IO; |
||||||
|
using Decompiler; |
||||||
|
using Microsoft.CSharp; |
||||||
|
using System.CodeDom.Compiler; |
||||||
|
using MbUnit.Framework; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Tests |
||||||
|
{ |
||||||
|
public abstract class DecompilerTestBase |
||||||
|
{ |
||||||
|
protected static IEnumerable<Test> GenerateSectionTests(string samplesFileName) |
||||||
|
{ |
||||||
|
string code = File.ReadAllText(Path.Combine(@"..\..\Tests", samplesFileName)); |
||||||
|
foreach (var sectionName in CodeSampleFileParser.ListSections(code)) |
||||||
|
{ |
||||||
|
if (sectionName.EndsWith("(ignored)", StringComparison.OrdinalIgnoreCase)) |
||||||
|
continue; |
||||||
|
|
||||||
|
var testedSectionName = sectionName; |
||||||
|
yield return new TestCase(testedSectionName, () => |
||||||
|
{ |
||||||
|
var testCode = CodeSampleFileParser.GetSection(testedSectionName, code); |
||||||
|
System.Diagnostics.Debug.WriteLine(testCode); |
||||||
|
var decompiledTestCode = RoundtripCode(testCode); |
||||||
|
Assert.AreEqual(testCode, decompiledTestCode); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected static void ValidateFileRoundtrip(string samplesFileName) |
||||||
|
{ |
||||||
|
var lines = File.ReadAllLines(Path.Combine(@"..\..\Tests", samplesFileName)); |
||||||
|
var testCode = RemoveIgnorableLines(lines); |
||||||
|
var decompiledTestCode = RoundtripCode(testCode); |
||||||
|
Assert.AreEqual(testCode, decompiledTestCode); |
||||||
|
} |
||||||
|
|
||||||
|
static string RemoveIgnorableLines(IEnumerable<string> lines) |
||||||
|
{ |
||||||
|
return CodeSampleFileParser.ConcatLines(lines.Where(l => !CodeSampleFileParser.IsCommentOrBlank(l))); |
||||||
|
} |
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compiles and decompiles a source code.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="code">The source code to copile.</param>
|
||||||
|
/// <returns>The decompilation result of compiled source code.</returns>
|
||||||
|
static string RoundtripCode(string code) |
||||||
|
{ |
||||||
|
AssemblyDefinition assembly = Compile(code); |
||||||
|
AstBuilder decompiler = new AstBuilder(new DecompilerContext()); |
||||||
|
decompiler.AddAssembly(assembly); |
||||||
|
StringWriter output = new StringWriter(); |
||||||
|
decompiler.GenerateCode(new PlainTextOutput(output)); |
||||||
|
return output.ToString(); |
||||||
|
} |
||||||
|
|
||||||
|
static AssemblyDefinition Compile(string code) |
||||||
|
{ |
||||||
|
CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } }); |
||||||
|
CompilerParameters options = new CompilerParameters(); |
||||||
|
options.ReferencedAssemblies.Add("System.Core.dll"); |
||||||
|
CompilerResults results = provider.CompileAssemblyFromSource(options, code); |
||||||
|
try |
||||||
|
{ |
||||||
|
if (results.Errors.Count > 0) |
||||||
|
{ |
||||||
|
StringBuilder b = new StringBuilder("Compiler error:"); |
||||||
|
foreach (var error in results.Errors) |
||||||
|
{ |
||||||
|
b.AppendLine(error.ToString()); |
||||||
|
} |
||||||
|
throw new Exception(b.ToString()); |
||||||
|
} |
||||||
|
return AssemblyDefinition.ReadAssembly(results.PathToAssembly); |
||||||
|
} |
||||||
|
finally |
||||||
|
{ |
||||||
|
File.Delete(results.PathToAssembly); |
||||||
|
results.TempFiles.Delete(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
using System; |
||||||
|
using System.Collections.Generic; |
||||||
|
using System.Linq; |
||||||
|
using System.Text; |
||||||
|
using MbUnit.Framework; |
||||||
|
|
||||||
|
namespace ICSharpCode.Decompiler.Tests.Types |
||||||
|
{ |
||||||
|
public class TypeTests : DecompilerTestBase |
||||||
|
{ |
||||||
|
[Test] |
||||||
|
public void ValueTypes() |
||||||
|
{ |
||||||
|
ValidateFileRoundtrip(@"Types\ValueTypes.cs"); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void PropertiesAndEvents() |
||||||
|
{ |
||||||
|
ValidateFileRoundtrip(@"Types\PropertiesAndEvents.cs"); |
||||||
|
} |
||||||
|
|
||||||
|
[Test] |
||||||
|
public void DelegateConstruction() |
||||||
|
{ |
||||||
|
ValidateFileRoundtrip(@"Types\DelegateConstruction.cs"); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue