mirror of https://github.com/icsharpcode/ILSpy.git
13 changed files with 438 additions and 36 deletions
@ -0,0 +1,114 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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