async Task Run([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) { var csFile = Path.Combine(TestCasePath, testName + ".cs"); var exeFile = Path.Combine(TestCasePath, testName) + Tester.GetSuffix(cscOptions) + ".exe"; if (cscOptions.HasFlag(CompilerOptions.Library)) { exeFile = Path.ChangeExtension(exeFile, ".dll"); } // 1. Compile CompilerResults output = null; try { output = await Tester.CompileCSharp(csFile, cscOptions, exeFile).ConfigureAwait(false); } finally { if (output != null) { output.DeleteTempFiles(); } } // 2. Decompile var decompiled = await Tester.DecompileCSharp(exeFile, decompilerSettings ?? Tester.GetSettings(cscOptions)).ConfigureAwait(false); // 3. Compile CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(cscOptions).ToArray()); }
async Task Run([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) { var ilFile = Path.Combine(TestCasePath, testName) + Tester.GetSuffix(cscOptions) + ".il"; var csFile = Path.Combine(TestCasePath, testName + ".cs"); var expectedFile = Path.Combine(TestCasePath, testName + ".Expected.cs"); if (!File.Exists(ilFile)) { // re-create .il file if necessary CompilerResults output = null; try { output = await Tester.CompileCSharp(csFile, cscOptions).ConfigureAwait(false); await Tester.Disassemble(output.PathToAssembly, ilFile, asmOptions).ConfigureAwait(false); } finally { if (output != null) { output.DeleteTempFiles(); } } } var executable = await Tester.AssembleIL(ilFile, asmOptions).ConfigureAwait(false); var decompiled = await Tester.DecompileCSharp(executable, decompilerSettings).ConfigureAwait(false); CodeAssert.FilesAreEqual(expectedFile, decompiled, Tester.GetPreprocessorSymbols(cscOptions).ToArray()); }
async Task RunIL(string testFileName, CompilerOptions options = CompilerOptions.UseDebug, AssemblerOptions asmOptions = AssemblerOptions.None) { string outputFile = null; CompilerResults decompiledOutputFile = null; try { options |= CompilerOptions.UseTestRunner; outputFile = await Tester.AssembleIL(Path.Combine(TestCasePath, testFileName), asmOptions).ConfigureAwait(false); string decompiledCodeFile = await Tester.DecompileCSharp(outputFile, Tester.GetSettings(options)).ConfigureAwait(false); decompiledOutputFile = await Tester.CompileCSharp(decompiledCodeFile, options).ConfigureAwait(false); await Tester.RunAndCompareOutput(testFileName, outputFile, decompiledOutputFile.PathToAssembly, decompiledCodeFile, (options & CompilerOptions.UseTestRunner) != 0, (options & CompilerOptions.Force32Bit) != 0).ConfigureAwait(false); Tester.RepeatOnIOError(() => File.Delete(decompiledCodeFile)); Tester.RepeatOnIOError(() => File.Delete(decompiledOutputFile.PathToAssembly)); } finally { if (decompiledOutputFile != null) { decompiledOutputFile.DeleteTempFiles(); } } }
async Task RunCS([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug) { if ((options & CompilerOptions.UseRoslynMask) != 0 && (options & CompilerOptions.TargetNet40) == 0) { options |= CompilerOptions.UseTestRunner; } string testFileName = testName + ".cs"; string testOutputFileName = testName + Tester.GetSuffix(options) + ".exe"; CompilerResults outputFile = null, decompiledOutputFile = null; try { outputFile = await Tester.CompileCSharp(Path.Combine(TestCasePath, testFileName), options, outputFileName : Path.Combine(TestCasePath, testOutputFileName)).ConfigureAwait(false); string decompiledCodeFile = await Tester.DecompileCSharp(outputFile.PathToAssembly, Tester.GetSettings(options)).ConfigureAwait(false); if ((options & CompilerOptions.UseMcsMask) != 0) { // For second pass, use roslyn instead of mcs. // mcs has some compiler bugs that cause it to not accept ILSpy-generated code, // for example when there's unreachable code due to other compiler bugs in the first mcs run. options &= ~CompilerOptions.UseMcsMask; options |= CompilerOptions.UseRoslynLatest; // Also, add an .exe.config so that we consistently use the .NET 4.x runtime. File.WriteAllText(outputFile.PathToAssembly + ".config", @"<?xml version=""1.0"" encoding=""utf-8""?> <configuration> <startup> <supportedRuntime version=""v4.0"" sku="".NETFramework,Version=v4.0,Profile=Client"" /> </startup> </configuration>"); options |= CompilerOptions.TargetNet40; } decompiledOutputFile = await Tester.CompileCSharp(decompiledCodeFile, options).ConfigureAwait(false); await Tester.RunAndCompareOutput(testFileName, outputFile.PathToAssembly, decompiledOutputFile.PathToAssembly, decompiledCodeFile, (options & CompilerOptions.UseTestRunner) != 0, (options & CompilerOptions.Force32Bit) != 0); Tester.RepeatOnIOError(() => File.Delete(decompiledCodeFile)); Tester.RepeatOnIOError(() => File.Delete(decompiledOutputFile.PathToAssembly)); } finally { if (outputFile != null) { outputFile.DeleteTempFiles(); } if (decompiledOutputFile != null) { decompiledOutputFile.DeleteTempFiles(); } } }
async Task RunVB([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug) { options |= CompilerOptions.ReferenceVisualBasic; if ((options & CompilerOptions.UseRoslynMask) != 0) { options |= CompilerOptions.UseTestRunner; } string testFileName = testName + ".vb"; string testOutputFileName = testName + Tester.GetSuffix(options) + ".exe"; CompilerResults outputFile = null, decompiledOutputFile = null; try { outputFile = await Tester.CompileVB(Path.Combine(TestCasePath, testFileName), options, outputFileName : Path.Combine(TestCasePath, testOutputFileName)).ConfigureAwait(false); string decompiledCodeFile = await Tester.DecompileCSharp(outputFile.PathToAssembly, Tester.GetSettings(options)).ConfigureAwait(false); decompiledOutputFile = await Tester.CompileCSharp(decompiledCodeFile, options).ConfigureAwait(false); await Tester.RunAndCompareOutput(testFileName, outputFile.PathToAssembly, decompiledOutputFile.PathToAssembly, decompiledCodeFile, (options & CompilerOptions.UseTestRunner) != 0, (options & CompilerOptions.Force32Bit) != 0); Tester.RepeatOnIOError(() => File.Delete(decompiledCodeFile)); Tester.RepeatOnIOError(() => File.Delete(decompiledOutputFile.PathToAssembly)); } finally { if (outputFile != null) { outputFile.DeleteTempFiles(); } if (decompiledOutputFile != null) { decompiledOutputFile.DeleteTempFiles(); } } }