You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

87 lines
3.0 KiB

  1. using ICSharpCode.Decompiler.Ast;
  2. using ICSharpCode.Decompiler.Tests.Helpers;
  3. using ICSharpCode.NRefactory.CSharp;
  4. using Mono.Cecil;
  5. using NUnit.Framework;
  6. using System;
  7. using System.Collections.Generic;
  8. using System.Diagnostics;
  9. using System.IO;
  10. using System.Linq;
  11. using System.Reflection;
  12. using System.Text;
  13. using System.Threading.Tasks;
  14. namespace ICSharpCode.Decompiler.Tests.FSharpPatterns
  15. {
  16. public class TestHelpers
  17. {
  18. public static string FuzzyReadResource(string resourceName)
  19. {
  20. var asm = Assembly.GetExecutingAssembly();
  21. var allResources = asm.GetManifestResourceNames();
  22. var fullResourceName = allResources.Single(r => r.EndsWith(resourceName, StringComparison.OrdinalIgnoreCase));
  23. return new StreamReader(asm.GetManifestResourceStream(fullResourceName)).ReadToEnd();
  24. }
  25. static Lazy<string> ilasm = new Lazy<string>(() => ToolLocator.FindTool("ilasm.exe"));
  26. static Lazy<string> ildasm = new Lazy<string>(() => ToolLocator.FindTool("ildasm.exe"));
  27. public static string CompileIL(string source)
  28. {
  29. if (ilasm.Value == null)
  30. Assert.NotNull(ilasm.Value, "Could not find ILASM.exe");
  31. var tmp = Path.GetTempFileName();
  32. File.Delete(tmp);
  33. var sourceFile = Path.ChangeExtension(tmp, ".il");
  34. File.WriteAllText(sourceFile, source);
  35. var asmFile = Path.ChangeExtension(sourceFile, ".dll");
  36. var args = string.Format("{0} /dll /debug /output:{1}", sourceFile, asmFile);
  37. using (var proc = Process.Start(new ProcessStartInfo(ilasm.Value, args) { UseShellExecute = false, }))
  38. {
  39. proc.WaitForExit();
  40. Assert.AreEqual(0, proc.ExitCode);
  41. }
  42. File.Delete(sourceFile);
  43. Assert.True(File.Exists(asmFile), "Assembly File does not exist");
  44. return asmFile;
  45. }
  46. public static void RunIL(string ilCode, string expectedCSharpCode)
  47. {
  48. var asmFilePath = CompileIL(ilCode);
  49. CompareAssemblyAgainstCSharp(expectedCSharpCode, asmFilePath);
  50. }
  51. private static void CompareAssemblyAgainstCSharp(string expectedCSharpCode, string asmFilePath)
  52. {
  53. var module = ModuleDefinition.ReadModule(asmFilePath);
  54. try
  55. {
  56. try { module.ReadSymbols(); } catch { }
  57. AstBuilder decompiler = new AstBuilder(new DecompilerContext(module));
  58. decompiler.AddAssembly(module);
  59. new Helpers.RemoveCompilerAttribute().Run(decompiler.SyntaxTree);
  60. StringWriter output = new StringWriter();
  61. // the F# assembly contains a namespace `<StartupCode$tmp6D55>` where the part after tmp is randomly generated.
  62. // remove this from the ast to simplify the diff
  63. var startupCodeNode = decompiler.SyntaxTree.Children.OfType<NamespaceDeclaration>().SingleOrDefault(d => d.Name.StartsWith("<StartupCode$", StringComparison.Ordinal));
  64. if (startupCodeNode != null)
  65. startupCodeNode.Remove();
  66. decompiler.GenerateCode(new PlainTextOutput(output));
  67. var fullCSharpCode = output.ToString();
  68. CodeAssert.AreEqual(expectedCSharpCode, output.ToString());
  69. }
  70. finally
  71. {
  72. File.Delete(asmFilePath);
  73. File.Delete(Path.ChangeExtension(asmFilePath, ".pdb"));
  74. }
  75. }
  76. }
  77. }