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.

119 lines
4.1 KiB

4 years ago
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Reflection.PortableExecutable;
  6. using System.Runtime.CompilerServices;
  7. using System.Text;
  8. using System.Xml.Linq;
  9. using ICSharpCode.Decompiler.CSharp;
  10. using ICSharpCode.Decompiler.CSharp.OutputVisitor;
  11. using ICSharpCode.Decompiler.DebugInfo;
  12. using ICSharpCode.Decompiler.Metadata;
  13. using ICSharpCode.Decompiler.Tests.Helpers;
  14. using ICSharpCode.Decompiler.TypeSystem;
  15. using Microsoft.CodeAnalysis.CSharp;
  16. using Microsoft.DiaSymReader.Tools;
  17. using NUnit.Framework;
  18. namespace ICSharpCode.Decompiler.Tests
  19. {
  20. [TestFixture, Parallelizable(ParallelScope.All)]
  21. public class PdbGenerationTestRunner
  22. {
  23. static readonly string TestCasePath = Tester.TestCasePath + "/PdbGen";
  24. [Test]
  25. public void HelloWorld()
  26. {
  27. TestGeneratePdb();
  28. }
  29. [Test]
  30. [Ignore("Missing nested local scopes for loops, differences in IL ranges")]
  31. public void ForLoopTests()
  32. {
  33. TestGeneratePdb();
  34. }
  35. [Test]
  36. [Ignore("Differences in IL ranges")]
  37. public void LambdaCapturing()
  38. {
  39. TestGeneratePdb();
  40. }
  41. private void TestGeneratePdb([CallerMemberName] string testName = null)
  42. {
  43. const PdbToXmlOptions options = PdbToXmlOptions.IncludeEmbeddedSources | PdbToXmlOptions.ThrowOnError | PdbToXmlOptions.IncludeTokens | PdbToXmlOptions.ResolveTokens | PdbToXmlOptions.IncludeMethodSpans;
  44. string xmlFile = Path.Combine(TestCasePath, testName + ".xml");
  45. string xmlContent = File.ReadAllText(xmlFile);
  46. XDocument document = XDocument.Parse(xmlContent);
  47. var files = document.Descendants("file").ToDictionary(f => f.Attribute("name").Value, f => f.Value);
  48. Tester.CompileCSharpWithPdb(Path.Combine(TestCasePath, testName + ".expected"), files);
  49. string peFileName = Path.Combine(TestCasePath, testName + ".expected.dll");
  50. string pdbFileName = Path.Combine(TestCasePath, testName + ".expected.pdb");
  51. var moduleDefinition = new PEFile(peFileName);
  52. var resolver = new UniversalAssemblyResolver(peFileName, false, moduleDefinition.Reader.DetectTargetFrameworkId(), null, PEStreamOptions.PrefetchEntireImage);
  53. var decompiler = new CSharpDecompiler(moduleDefinition, resolver, new DecompilerSettings());
  54. using (FileStream pdbStream = File.Open(Path.Combine(TestCasePath, testName + ".pdb"), FileMode.OpenOrCreate, FileAccess.ReadWrite))
  55. {
  56. pdbStream.SetLength(0);
  57. PortablePdbWriter.WritePdb(moduleDefinition, decompiler, new DecompilerSettings(), pdbStream, noLogo: true);
  58. pdbStream.Position = 0;
  59. using (Stream peStream = File.OpenRead(peFileName))
  60. using (Stream expectedPdbStream = File.OpenRead(pdbFileName))
  61. {
  62. using (StreamWriter writer = new StreamWriter(Path.ChangeExtension(pdbFileName, ".xml"), false, Encoding.UTF8))
  63. {
  64. PdbToXmlConverter.ToXml(writer, expectedPdbStream, peStream, options);
  65. }
  66. peStream.Position = 0;
  67. using (StreamWriter writer = new StreamWriter(Path.ChangeExtension(xmlFile, ".generated.xml"), false, Encoding.UTF8))
  68. {
  69. PdbToXmlConverter.ToXml(writer, pdbStream, peStream, options);
  70. }
  71. }
  72. }
  73. string expectedFileName = Path.ChangeExtension(xmlFile, ".expected.xml");
  74. ProcessXmlFile(expectedFileName);
  75. string generatedFileName = Path.ChangeExtension(xmlFile, ".generated.xml");
  76. ProcessXmlFile(generatedFileName);
  77. Assert.AreEqual(Normalize(expectedFileName), Normalize(generatedFileName));
  78. }
  79. private void ProcessXmlFile(string fileName)
  80. {
  81. var document = XDocument.Load(fileName);
  82. foreach (var file in document.Descendants("file"))
  83. {
  84. file.Attribute("checksum").Remove();
  85. file.Attribute("embeddedSourceLength")?.Remove();
  86. file.ReplaceNodes(new XCData(file.Value.Replace("\uFEFF", "")));
  87. }
  88. document.Save(fileName, SaveOptions.None);
  89. }
  90. private string Normalize(string inputFileName)
  91. {
  92. return File.ReadAllText(inputFileName).Replace("\r\n", "\n").Replace("\r", "\n");
  93. }
  94. }
  95. class StringWriterWithEncoding : StringWriter
  96. {
  97. readonly Encoding encoding;
  98. public StringWriterWithEncoding(Encoding encoding)
  99. {
  100. this.encoding = encoding ?? throw new ArgumentNullException("encoding");
  101. }
  102. public override Encoding Encoding => encoding;
  103. }
  104. }