diff --git a/ICSharpCode.Decompiler.TestRunner/ICSharpCode.Decompiler.TestRunner.csproj b/ICSharpCode.Decompiler.TestRunner/ICSharpCode.Decompiler.TestRunner.csproj new file mode 100644 index 000000000..cfc349461 --- /dev/null +++ b/ICSharpCode.Decompiler.TestRunner/ICSharpCode.Decompiler.TestRunner.csproj @@ -0,0 +1,12 @@ + + + + Exe + net6.0-windows + enable + x64 + false + ..\ICSharpCode.Decompiler.Tests\bin\$(Configuration)\$(TargetFramework)\win-x64\ + + + diff --git a/ICSharpCode.Decompiler.TestRunner/Program.cs b/ICSharpCode.Decompiler.TestRunner/Program.cs new file mode 100644 index 000000000..50b04adbd --- /dev/null +++ b/ICSharpCode.Decompiler.TestRunner/Program.cs @@ -0,0 +1,43 @@ +using System; +using System.Reflection; +using System.Runtime.Loader; + +namespace ICSharpCode.Decompiler.TestRunner; + +public static class Program +{ + static int Main(string[] args) + { + AssemblyLoadContext context = new("TestRunner", isCollectible: true); + context.Resolving += ContextResolving; + + try + { + var mainAssembly = context.LoadFromAssemblyPath(args[0]); + int paramCount = mainAssembly.EntryPoint!.GetParameters().Length; + object? result = mainAssembly.EntryPoint!.Invoke(null, paramCount == 0 ? new object[0] : new object[1] { new string[0] }); + return result is int i ? i : 0; + } + catch (Exception ex) + { + Console.Error.WriteLine("TestRunner crashed:"); + Console.Error.WriteLine(ex.ToString()); + return -1; + } + finally + { + context.Unload(); + context.Resolving -= ContextResolving; + } + } + + private static Assembly? ContextResolving(AssemblyLoadContext context, AssemblyName name) + { + return null; + } +} + + + + + diff --git a/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs b/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs index d3a2a22ad..2c69b1a2e 100644 --- a/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs @@ -21,6 +21,7 @@ using System.CodeDom.Compiler; using System.IO; using System.Linq; using System.Runtime.CompilerServices; +using System.Threading.Tasks; using ICSharpCode.Decompiler.Tests.Helpers; @@ -110,19 +111,19 @@ namespace ICSharpCode.Decompiler.Tests }; [Test] - public void Comparisons([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task Comparisons([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void Conversions([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task Conversions([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void FloatingPointArithmetic([ValueSource(nameof(noMonoOptions))] CompilerOptions options, [Values(32, 64)] int bits) + public async Task FloatingPointArithmetic([ValueSource(nameof(noMonoOptions))] CompilerOptions options, [Values(32, 64)] int bits) { // The behavior of the #1794 incorrect `(float)(double)val` cast only causes test failures // for some runtime+compiler combinations. @@ -130,125 +131,125 @@ namespace ICSharpCode.Decompiler.Tests options |= CompilerOptions.Force32Bit; // Mono is excluded because we never use it for the second pass, so the test ends up failing // due to some Mono vs. Roslyn compiler differences. - RunCS(options: options); + await RunCS(options: options); } [Test] - public void HelloWorld([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task HelloWorld([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void ControlFlow([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task ControlFlow([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void CompoundAssignment([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task CompoundAssignment([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void PropertiesAndEvents([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task PropertiesAndEvents([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void Switch([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task Switch([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void Using([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task Using([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void Loops([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task Loops([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void NullableTests([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task NullableTests([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void Generics([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task Generics([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void ValueTypeCall([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task ValueTypeCall([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void InitializerTests([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task InitializerTests([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void DecimalFields([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task DecimalFields([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void UndocumentedExpressions([ValueSource(nameof(noMonoOptions))] CompilerOptions options) + public async Task UndocumentedExpressions([ValueSource(nameof(noMonoOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void Uninit([ValueSource(nameof(noMonoOptions))] CompilerOptions options) + public async Task Uninit([ValueSource(nameof(noMonoOptions))] CompilerOptions options) { - RunVB(options: options); + await RunVB(options: options); } [Test] - public void MemberLookup([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task MemberLookup([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void OverloadResolution([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task OverloadResolution([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void ExpressionTrees([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task ExpressionTrees([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void NullPropagation([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions options) + public async Task NullPropagation([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void DeconstructionTests([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions options) + public async Task DeconstructionTests([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void BitNot([Values(false, true)] bool force32Bit) + public async Task BitNot([Values(false, true)] bool force32Bit) { CompilerOptions compiler = CompilerOptions.UseDebug; AssemblerOptions asm = AssemblerOptions.None; @@ -257,23 +258,23 @@ namespace ICSharpCode.Decompiler.Tests compiler |= CompilerOptions.Force32Bit; asm |= AssemblerOptions.Force32Bit; } - RunIL("BitNot.il", compiler, asm); + await RunIL("BitNot.il", compiler, asm); } [Test] - public void Jmp() + public async Task Jmp() { - RunIL("Jmp.il"); + await RunIL("Jmp.il"); } [Test] - public void StackTests() + public async Task StackTests() { - RunIL("StackTests.il"); + await RunIL("StackTests.il"); } [Test] - public void StackTypes([Values(false, true)] bool force32Bit) + public async Task StackTypes([Values(false, true)] bool force32Bit) { CompilerOptions compiler = CompilerOptions.UseRoslynLatest | CompilerOptions.UseDebug; AssemblerOptions asm = AssemblerOptions.None; @@ -282,92 +283,94 @@ namespace ICSharpCode.Decompiler.Tests compiler |= CompilerOptions.Force32Bit; asm |= AssemblerOptions.Force32Bit; } - RunIL("StackTypes.il", compiler, asm); + await RunIL("StackTypes.il", compiler, asm); } [Test] - public void UnsafeCode([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task UnsafeCode([ValueSource(nameof(defaultOptions))] CompilerOptions options) { if (options.HasFlag(CompilerOptions.UseMcs2_6_4)) { Assert.Ignore("Decompiler bug with mono!"); } - RunCS(options: options); + await RunCS(options: options); } [Test] - public void ConditionalAttr([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task ConditionalAttr([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void TrickyTypes([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task TrickyTypes([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void Capturing([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task Capturing([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void YieldReturn([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task YieldReturn([ValueSource(nameof(defaultOptions))] CompilerOptions options) { if ((options & CompilerOptions.UseMcsMask) != 0) { Assert.Ignore("Decompiler bug with mono!"); } - RunCS(options: options); + await RunCS(options: options); } [Test] - public void Async([ValueSource(nameof(noMonoOptions))] CompilerOptions options) + public async Task Async([ValueSource(nameof(noMonoOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void LINQRaytracer([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task LINQRaytracer([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void StringConcat([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task StringConcat([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void DynamicTests([ValueSource(nameof(noMonoOptions))] CompilerOptions options) + public async Task DynamicTests([ValueSource(nameof(noMonoOptions))] CompilerOptions options) { - RunCS(options: options); + await RunCS(options: options); } [Test] - public void MiniJSON([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task MiniJSON([ValueSource(nameof(defaultOptions))] CompilerOptions options) { if (options.HasFlag(CompilerOptions.UseMcs2_6_4)) { Assert.Ignore("Decompiler bug with mono!"); } - RunCS(options: options); + await RunCS(options: options); } - void RunCS([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug) + async Task RunCS([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug) { + if ((options & CompilerOptions.UseRoslynMask) != 0) + options |= CompilerOptions.UseTestRunner; string testFileName = testName + ".cs"; string testOutputFileName = testName + Tester.GetSuffix(options) + ".exe"; CompilerResults outputFile = null, decompiledOutputFile = null; try { - outputFile = Tester.CompileCSharp(Path.Combine(TestCasePath, testFileName), options, - outputFileName: Path.Combine(TestCasePath, testOutputFileName)); - string decompiledCodeFile = Tester.DecompileCSharp(outputFile.PathToAssembly, Tester.GetSettings(options)); + 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. @@ -375,17 +378,11 @@ namespace ICSharpCode.Decompiler.Tests // 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", @" - - - - -"); + options |= CompilerOptions.UseTestRunner; } - decompiledOutputFile = Tester.CompileCSharp(decompiledCodeFile, options); + decompiledOutputFile = await Tester.CompileCSharp(decompiledCodeFile, options).ConfigureAwait(false); - Tester.RunAndCompareOutput(testFileName, outputFile.PathToAssembly, decompiledOutputFile.PathToAssembly, decompiledCodeFile); + 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)); @@ -399,21 +396,23 @@ namespace ICSharpCode.Decompiler.Tests } } - void RunVB([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug) + 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 = Tester.CompileVB(Path.Combine(TestCasePath, testFileName), options, - outputFileName: Path.Combine(TestCasePath, testOutputFileName)); - string decompiledCodeFile = Tester.DecompileCSharp(outputFile.PathToAssembly, Tester.GetSettings(options)); - decompiledOutputFile = Tester.CompileCSharp(decompiledCodeFile, options); + 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); - Tester.RunAndCompareOutput(testFileName, outputFile.PathToAssembly, decompiledOutputFile.PathToAssembly, decompiledCodeFile); + 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)); @@ -427,18 +426,19 @@ namespace ICSharpCode.Decompiler.Tests } } - void RunIL(string testFileName, CompilerOptions options = CompilerOptions.UseDebug, AssemblerOptions asmOptions = AssemblerOptions.None) + async Task RunIL(string testFileName, CompilerOptions options = CompilerOptions.UseDebug, AssemblerOptions asmOptions = AssemblerOptions.None) { string outputFile = null; CompilerResults decompiledOutputFile = null; try { - outputFile = Tester.AssembleIL(Path.Combine(TestCasePath, testFileName), asmOptions); - string decompiledCodeFile = Tester.DecompileCSharp(outputFile, Tester.GetSettings(options)); - decompiledOutputFile = Tester.CompileCSharp(decompiledCodeFile, options); + 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); - Tester.RunAndCompareOutput(testFileName, outputFile, decompiledOutputFile.PathToAssembly, decompiledCodeFile); + 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)); diff --git a/ICSharpCode.Decompiler.Tests/DisassemblerPrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/DisassemblerPrettyTestRunner.cs index bc7010982..8cec9947b 100644 --- a/ICSharpCode.Decompiler.Tests/DisassemblerPrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/DisassemblerPrettyTestRunner.cs @@ -53,18 +53,18 @@ namespace ICSharpCode.Decompiler.Tests } [Test] - public void SecurityDeclarations() + public async Task SecurityDeclarations() { - Run(); + await Run(); } - void Run([CallerMemberName] string testName = null) + async Task Run([CallerMemberName] string testName = null) { var ilExpectedFile = Path.Combine(TestCasePath, testName + ".il"); var ilResultFile = Path.Combine(TestCasePath, testName + ".result.il"); - var executable = Tester.AssembleIL(ilExpectedFile, AssemblerOptions.Library); - var disassembled = Tester.Disassemble(executable, ilResultFile, AssemblerOptions.UseOwnDisassembler); + var executable = await Tester.AssembleIL(ilExpectedFile, AssemblerOptions.Library).ConfigureAwait(false); + var disassembled = await Tester.Disassemble(executable, ilResultFile, AssemblerOptions.UseOwnDisassembler).ConfigureAwait(false); CodeAssert.FilesAreEqual(ilExpectedFile, ilResultFile); } diff --git a/ICSharpCode.Decompiler.Tests/Helpers/RoslynToolset.cs b/ICSharpCode.Decompiler.Tests/Helpers/RoslynToolset.cs index ebfbab79d..7c6de5b4e 100644 --- a/ICSharpCode.Decompiler.Tests/Helpers/RoslynToolset.cs +++ b/ICSharpCode.Decompiler.Tests/Helpers/RoslynToolset.cs @@ -18,12 +18,13 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; +using ICSharpCode.Decompiler.Util; + using NuGet.Common; using NuGet.Packaging; using NuGet.Protocol; @@ -32,63 +33,29 @@ using NuGet.Versioning; namespace ICSharpCode.Decompiler.Tests.Helpers { - class RoslynToolset + abstract class AbstractToolset { readonly SourceCacheContext cache; readonly SourceRepository repository; readonly FindPackageByIdResource resource; - readonly string nugetDir; - readonly Dictionary installedCompilers = new Dictionary { - { "legacy", Environment.ExpandEnvironmentVariables(@"%WINDIR%\Microsoft.NET\Framework\v4.0.30319") } - }; - readonly object syncObj = new object(); + protected readonly string baseDir; - public RoslynToolset() + public AbstractToolset(string baseDir) { this.cache = new SourceCacheContext(); this.repository = Repository.Factory.GetCoreV3("https://api.nuget.org/v3/index.json"); this.resource = repository.GetResource(); - this.nugetDir = Path.Combine(Path.GetDirectoryName(typeof(RoslynToolset).Assembly.Location), "roslyn"); - } - - public string GetCSharpCompiler(string version) - { - return GetCompiler("csc.exe", version); - } - - public string GetVBCompiler(string version) - { - return GetCompiler("vbc.exe", version); - } - - string GetCompiler(string compiler, string version) - { - lock (syncObj) - { - if (installedCompilers.TryGetValue(version, out var path)) - return Path.Combine(path, compiler); - - string outputPath = Path.Combine(nugetDir, version); - path = Path.Combine(outputPath, "tools"); - - if (!Directory.Exists(path)) - { - FetchPackage(version, outputPath).GetAwaiter().GetResult(); - } - - installedCompilers.Add(version, path); - return Path.Combine(path, compiler); - } + this.baseDir = baseDir; } - async Task FetchPackage(string version, string outputPath) + protected async Task FetchPackage(string packageName, string version, string outputPath) { ILogger logger = NullLogger.Instance; CancellationToken cancellationToken = CancellationToken.None; using MemoryStream packageStream = new MemoryStream(); await resource.CopyNupkgToStreamAsync( - "Microsoft.Net.Compilers", + packageName, NuGetVersion.Parse(version), packageStream, cache, @@ -96,9 +63,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers cancellationToken); using PackageArchiveReader packageReader = new PackageArchiveReader(packageStream); - NuspecReader nuspecReader = await packageReader.GetNuspecReaderAsync(cancellationToken); + NuspecReader nuspecReader = await packageReader.GetNuspecReaderAsync(cancellationToken).ConfigureAwait(false); - var files = await packageReader.GetFilesAsync(cancellationToken); + var files = await packageReader.GetFilesAsync(cancellationToken).ConfigureAwait(false); files = files.Where(f => f.StartsWith("tools", StringComparison.OrdinalIgnoreCase)); await packageReader.CopyFilesAsync(outputPath, files, (sourceFile, targetPath, fileStream) => { @@ -108,4 +75,66 @@ namespace ICSharpCode.Decompiler.Tests.Helpers logger, cancellationToken); } } + + class RoslynToolset : AbstractToolset + { + readonly Dictionary installedCompilers = new Dictionary { + { "legacy", Environment.ExpandEnvironmentVariables(@"%WINDIR%\Microsoft.NET\Framework\v4.0.30319") } + }; + + public RoslynToolset() + : base(Path.Combine(AppContext.BaseDirectory, "roslyn")) + { + } + + public async Task Fetch(string version) + { + string path = Path.Combine(baseDir, version, "tools"); + if (!Directory.Exists(path)) + { + await FetchPackage("Microsoft.Net.Compilers", version, Path.Combine(baseDir, version)); + } + + installedCompilers.Add(version, path); + } + + public string GetCSharpCompiler(string version) + { + return GetCompiler("csc.exe", version); + } + + public string GetVBCompiler(string version) + { + return GetCompiler("vbc.exe", version); + } + + string GetCompiler(string compiler, string version) + { + if (installedCompilers.TryGetValue(version, out var path)) + return Path.Combine(path, compiler); + throw new NotSupportedException($"Cannot find {compiler} {version}, please add it to the initialization."); + } + } + + class VsWhereToolset : AbstractToolset + { + string vswherePath; + + public VsWhereToolset() + : base(Path.Combine(AppContext.BaseDirectory, "vswhere")) + { + } + + public async Task Fetch() + { + string path = Path.Combine(baseDir, "tools"); + if (!Directory.Exists(path)) + { + await FetchPackage("vswhere", "2.8.4", baseDir); + } + vswherePath = Path.Combine(path, "vswhere.exe"); + } + + public string GetVsWhere() => vswherePath; + } } diff --git a/ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs b/ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs index 338320d52..883590ccf 100644 --- a/ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs +++ b/ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs @@ -21,16 +21,19 @@ using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; +using CliWrap; + using NUnit.Framework; namespace ICSharpCode.Decompiler.Tests.Helpers { partial class Tester { - public static CompilerResults CompileVB(string sourceFileName, CompilerOptions flags = CompilerOptions.UseDebug, string outputFileName = null) + public static async Task CompileVB(string sourceFileName, CompilerOptions flags = CompilerOptions.UseDebug, string outputFileName = null) { List sourceFileNames = new List { sourceFileName }; foreach (Match match in Regex.Matches(File.ReadAllText(sourceFileName), @"#include ""([\w\d./]+)""")) @@ -50,7 +53,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers CompilerOptions.UseRoslyn1_3_2 => ("1.3.2", "14"), CompilerOptions.UseRoslyn2_10_0 => ("2.10.0", "latest"), CompilerOptions.UseRoslyn3_11_0 => ("3.11.0", "latest"), - _ => (RoslynLatestVersion, flags.HasFlag(CompilerOptions.Preview) ? "preview" : "latest") + _ => (roslynLatestVersion, flags.HasFlag(CompilerOptions.Preview) ? "preview" : "latest") }; var vbcPath = roslynToolset.GetVBCompiler(roslynVersion); @@ -58,29 +61,15 @@ namespace ICSharpCode.Decompiler.Tests.Helpers IEnumerable references; if ((flags & CompilerOptions.UseRoslynMask) != 0) { - if (flags.HasFlag(CompilerOptions.ReferenceCore)) - { - references = coreDefaultReferences.Value.Select(r => "-r:\"" + r + "\""); - } - else - { - references = roslynDefaultReferences.Value.Select(r => "-r:\"" + r + "\""); - } + references = coreDefaultReferences.Select(r => "-r:\"" + r + "\""); } else { - references = defaultReferences.Value.Select(r => "-r:\"" + r + "\""); + references = defaultReferences.Select(r => "-r:\"" + r + "\""); } if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic)) { - if ((flags & CompilerOptions.UseRoslynMask) != 0) - { - references = references.Concat(visualBasic.Value.Select(r => "-r:\"" + r + "\"")); - } - else - { - references = references.Concat(new[] { "-r:\"Microsoft.VisualBasic.dll\"" }); - } + references = references.Concat(new[] { "-r:\"Microsoft.VisualBasic.dll\"" }); } string otherOptions = $"-noconfig " + "-optioninfer+ -optionexplicit+ " + @@ -125,25 +114,22 @@ namespace ICSharpCode.Decompiler.Tests.Helpers otherOptions += " \"-d:" + string.Join(",", preprocessorSymbols.Select(kv => kv.Key + "=" + kv.Value)) + "\" "; } - ProcessStartInfo info = new ProcessStartInfo(vbcPath); - info.Arguments = $"{otherOptions}{string.Join(" ", references)} -out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}"; - info.RedirectStandardError = true; - info.RedirectStandardOutput = true; - info.UseShellExecute = false; - - Console.WriteLine($"\"{info.FileName}\" {info.Arguments}"); + StringBuilder stderr = new(); + StringBuilder stdout = new(); - Process process = Process.Start(info); + var command = Cli.Wrap(vbcPath) + .WithArguments($"{otherOptions}{string.Join(" ", references)} -out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}") + .WithStandardErrorPipe(PipeTarget.ToStringBuilder(stderr)) + .WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdout)) + .WithValidation(CommandResultValidation.None); + Console.WriteLine($"\"{command.TargetFilePath}\" {command.Arguments}"); - var outputTask = process.StandardOutput.ReadToEndAsync(); - var errorTask = process.StandardError.ReadToEndAsync(); + var result = await command.ExecuteAsync().ConfigureAwait(false); - Task.WaitAll(outputTask, errorTask); - process.WaitForExit(); + Console.WriteLine("output: " + stdout); + Console.WriteLine("errors: " + stderr); + Assert.AreEqual(0, result.ExitCode, "vbc failed"); - Console.WriteLine("output: " + outputTask.Result); - Console.WriteLine("errors: " + errorTask.Result); - Assert.AreEqual(0, process.ExitCode, "vbc failed"); return results; } else diff --git a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs index 1a1fd4c49..68d64d887 100644 --- a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs +++ b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs @@ -17,7 +17,6 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.CodeDom.Compiler; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -30,6 +29,8 @@ using System.Threading.Tasks; using System.Xml.Linq; using System.Xml.XPath; +using CliWrap; + using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp.OutputVisitor; using ICSharpCode.Decompiler.CSharp.Transforms; @@ -57,13 +58,15 @@ namespace ICSharpCode.Decompiler.Tests.Helpers UseRoslyn1_3_2 = 0x10, UseMcs2_6_4 = 0x20, ReferenceVisualBasic = 0x40, - ReferenceCore = 0x80, + //ReferenceCore = 0x80, GeneratePdb = 0x100, Preview = 0x200, UseRoslyn2_10_0 = 0x400, UseRoslyn3_11_0 = 0x800, UseRoslynLatest = 0x1000, UseMcs5_23 = 0x2000, + UseTestRunner = 0x4000, + NullableEnable = 0x8000, UseMcsMask = UseMcs2_6_4 | UseMcs5_23, UseRoslynMask = UseRoslyn1_3_2 | UseRoslyn2_10_0 | UseRoslyn3_11_0 | UseRoslynLatest } @@ -83,18 +86,35 @@ namespace ICSharpCode.Decompiler.Tests.Helpers public static partial class Tester { - public static readonly string TestCasePath = Path.Combine( - Path.GetDirectoryName(typeof(Tester).Assembly.Location), - "../../../TestCases"); + public static readonly string TesterPath; + public static readonly string TestCasePath; - static readonly string PackagesPropsFile = Path.Combine( - Path.GetDirectoryName(typeof(Tester).Assembly.Location), - "../../../../packages.props"); + static readonly string packagesPropsFile; + static readonly string roslynLatestVersion; + static readonly RoslynToolset roslynToolset; + static readonly VsWhereToolset vswhereToolset; - static readonly string RoslynLatestVersion = XDocument.Load(PackagesPropsFile) - .XPathSelectElement("//RoslynVersion").Value; + static Tester() + { + TesterPath = Path.GetDirectoryName(typeof(Tester).Assembly.Location); + TestCasePath = Path.Combine(TesterPath, "../../../../TestCases"); + packagesPropsFile = Path.Combine(TesterPath, "../../../../../packages.props"); + roslynLatestVersion = XDocument.Load(packagesPropsFile).XPathSelectElement("//RoslynVersion").Value; + roslynToolset = new RoslynToolset(); + vswhereToolset = new VsWhereToolset(); + } - public static string AssembleIL(string sourceFileName, AssemblerOptions options = AssemblerOptions.UseDebug) + internal static async Task Initialize() + { + await roslynToolset.Fetch("1.3.2"); + await roslynToolset.Fetch("2.10.0"); + await roslynToolset.Fetch("3.11.0"); + await roslynToolset.Fetch(roslynLatestVersion); + + await vswhereToolset.Fetch(); + } + + public static async Task AssembleIL(string sourceFileName, AssemblerOptions options = AssemblerOptions.UseDebug) { string ilasmPath; if (options.HasFlag(AssemblerOptions.UseLegacyAssembler)) @@ -131,28 +151,25 @@ namespace ICSharpCode.Decompiler.Tests.Helpers otherOptions += "/debug "; } - ProcessStartInfo info = new ProcessStartInfo(ilasmPath); - info.Arguments = $"/nologo {otherOptions}/output=\"{outputFile}\" \"{sourceFileName}\""; - info.RedirectStandardError = true; - info.RedirectStandardOutput = true; - info.UseShellExecute = false; + StringBuilder stderr = new(); + StringBuilder stdout = new(); - Process process = Process.Start(info); + var command = Cli.Wrap(ilasmPath) + .WithArguments($"/nologo {otherOptions}/output=\"{outputFile}\" \"{sourceFileName}\"") + .WithStandardErrorPipe(PipeTarget.ToStringBuilder(stderr)) + .WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdout)) + .WithValidation(CommandResultValidation.None); - var outputTask = process.StandardOutput.ReadToEndAsync(); - var errorTask = process.StandardError.ReadToEndAsync(); + var result = await command.ExecuteAsync().ConfigureAwait(false); - Task.WaitAll(outputTask, errorTask); - process.WaitForExit(); - - Console.WriteLine("output: " + outputTask.Result); - Console.WriteLine("errors: " + errorTask.Result); - Assert.AreEqual(0, process.ExitCode, "ilasm failed"); + Console.WriteLine("output: " + stdout); + Console.WriteLine("errors: " + stderr); + Assert.AreEqual(0, result.ExitCode, "ilasm failed"); return outputFile; } - public static string Disassemble(string sourceFileName, string outputFile, AssemblerOptions asmOptions) + public static async Task Disassemble(string sourceFileName, string outputFile, AssemblerOptions asmOptions) { if (asmOptions.HasFlag(AssemblerOptions.UseOwnDisassembler)) { @@ -180,22 +197,20 @@ namespace ICSharpCode.Decompiler.Tests.Helpers string ildasmPath = SdkUtility.GetSdkPath("ildasm.exe"); - ProcessStartInfo info = new ProcessStartInfo(ildasmPath); - info.Arguments = $"/nobar /utf8 /out=\"{outputFile}\" \"{sourceFileName}\""; - info.RedirectStandardError = true; - info.RedirectStandardOutput = true; - info.UseShellExecute = false; - - Process process = Process.Start(info); + StringBuilder stderr = new(); + StringBuilder stdout = new(); - var outputTask = process.StandardOutput.ReadToEndAsync(); - var errorTask = process.StandardError.ReadToEndAsync(); + var command = Cli.Wrap(ildasmPath) + .WithArguments($"/nobar /utf8 /out=\"{outputFile}\" \"{sourceFileName}\"") + .WithStandardErrorPipe(PipeTarget.ToStringBuilder(stderr)) + .WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdout)) + .WithValidation(CommandResultValidation.None); - Task.WaitAll(outputTask, errorTask); - process.WaitForExit(); + var result = await command.ExecuteAsync().ConfigureAwait(false); - Console.WriteLine("output: " + outputTask.Result); - Console.WriteLine("errors: " + errorTask.Result); + Console.WriteLine("output: " + stdout); + Console.WriteLine("errors: " + stderr); + Assert.AreEqual(0, result.ExitCode, "ildasm failed"); // Unlike the .imagebase directive (which is a fixed value when compiling with /deterministic), // the image base comment still varies... ildasm putting a random number here? @@ -220,8 +235,6 @@ namespace ICSharpCode.Decompiler.Tests.Helpers return Regex.Replace(il, @"'\{[0-9A-F-]+\}'", "''"); } - static readonly RoslynToolset roslynToolset = new RoslynToolset(); - static readonly string coreRefAsmPath = new DotNetCorePathFinder(TargetFrameworkIdentifier.NET, new Version(6, 0), "Microsoft.NETCore.App") .GetReferenceAssemblyPath(".NETCoreApp,Version=v6.0"); @@ -229,33 +242,35 @@ namespace ICSharpCode.Decompiler.Tests.Helpers static readonly string refAsmPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), @"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2"); - static readonly Lazy> defaultReferences = new Lazy>(delegate { - return new[] + static readonly string[] defaultReferences = new[] { + "System.dll", + "System.Core.dll", + "System.Xml.dll", + "Microsoft.CSharp.dll" + }; + + static readonly string[] coreDefaultReferences = new[] { + "netstandard.dll", + "mscorlib.dll", "System.dll", + "System.Collections.dll", + "System.Console.dll", "System.Core.dll", + "System.Linq.dll", + "System.Linq.Expressions.dll", + "System.Linq.Queryable.dll", + "System.IO.FileSystem.Watcher.dll", + "System.Threading.dll", + "System.Threading.Thread.dll", + "System.Runtime.dll", + "System.Runtime.InteropServices.dll", "System.Xml.dll", - "Microsoft.CSharp.dll" - }; - }); - - static readonly Lazy> roslynDefaultReferences = new Lazy>(delegate { - return new[] - { - Path.Combine(refAsmPath, "Facades\\netstandard.dll"), - Path.Combine(refAsmPath, "mscorlib.dll"), - Path.Combine(refAsmPath, "System.dll"), - Path.Combine(refAsmPath, "System.Core.dll"), - Path.Combine(refAsmPath, @"Facades\System.Runtime.dll"), - Path.Combine(refAsmPath, "System.Xml.dll"), - Path.Combine(refAsmPath, "Microsoft.CSharp.dll"), - typeof(ValueTuple).Assembly.Location, - typeof(ValueTask).Assembly.Location, - typeof(Span<>).Assembly.Location, + "System.Xml.ReaderWriter.dll", + "System.ValueTuple.dll", + "Microsoft.CSharp.dll", + "Microsoft.VisualBasic.dll", }; - }); - - static readonly Lazy> coreDefaultReferences = new Lazy>(GetDefaultReferences); const string targetFrameworkAttributeSnippet = @" @@ -272,20 +287,6 @@ namespace ICSharpCode.Decompiler.Tests.Helpers return tempFile; } - static IEnumerable GetDefaultReferences() - { - foreach (var reference in Directory.EnumerateFiles(coreRefAsmPath, "*.dll")) - { - yield return reference; - } - } - - static readonly Lazy> visualBasic = new Lazy>(delegate { - return new[] { - Path.Combine(refAsmPath, "Microsoft.VisualBasic.dll") - }; - }); - public static List GetPreprocessorSymbols(CompilerOptions flags) { var preprocessorSymbols = new List(); @@ -297,12 +298,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers { preprocessorSymbols.Add("OPT"); } - if (flags.HasFlag(CompilerOptions.ReferenceCore)) - { - preprocessorSymbols.Add("NETCORE"); - } if ((flags & CompilerOptions.UseRoslynMask) != 0) { + preprocessorSymbols.Add("NETCORE"); preprocessorSymbols.Add("ROSLYN"); preprocessorSymbols.Add("CS60"); preprocessorSymbols.Add("VB11"); @@ -356,14 +354,14 @@ namespace ICSharpCode.Decompiler.Tests.Helpers return preprocessorSymbols; } - public static CompilerResults CompileCSharp(string sourceFileName, CompilerOptions flags = CompilerOptions.UseDebug, string outputFileName = null) + public static async Task CompileCSharp(string sourceFileName, CompilerOptions flags = CompilerOptions.UseDebug, string outputFileName = null) { List sourceFileNames = new List { sourceFileName }; foreach (Match match in Regex.Matches(File.ReadAllText(sourceFileName), @"#include ""([\w\d./]+)""")) { sourceFileNames.Add(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(sourceFileName), match.Groups[1].Value))); } - if (flags.HasFlag(CompilerOptions.ReferenceCore)) + if ((flags & CompilerOptions.UseRoslynMask) != 0) { sourceFileNames.Add(targetFrameworkAttributeSnippetFile.Value); } @@ -380,37 +378,26 @@ namespace ICSharpCode.Decompiler.Tests.Helpers CompilerOptions.UseRoslyn1_3_2 => ("1.3.2", "6"), CompilerOptions.UseRoslyn2_10_0 => ("2.10.0", "latest"), CompilerOptions.UseRoslyn3_11_0 => ("3.11.0", "latest"), - _ => (RoslynLatestVersion, flags.HasFlag(CompilerOptions.Preview) ? "preview" : "latest") + _ => (roslynLatestVersion, flags.HasFlag(CompilerOptions.Preview) ? "preview" : "latest") }; var cscPath = roslynToolset.GetCSharpCompiler(roslynVersion); + string libPath; IEnumerable references; if ((flags & CompilerOptions.UseRoslynMask) != 0) { - if (flags.HasFlag(CompilerOptions.ReferenceCore)) - { - references = coreDefaultReferences.Value.Select(r => "-r:\"" + r + "\""); - } - else - { - references = roslynDefaultReferences.Value.Select(r => "-r:\"" + r + "\""); - } + libPath = "\"" + coreRefAsmPath + "\""; + references = coreDefaultReferences.Select(r => "-r:\"" + Path.Combine(coreRefAsmPath, r) + "\""); } else { - references = defaultReferences.Value.Select(r => "-r:\"" + r + "\""); + libPath = "\"" + refAsmPath + "\",\"" + Path.Combine(refAsmPath, "Facades") + "\""; + references = defaultReferences.Select(r => "-r:\"" + Path.Combine(refAsmPath, r) + "\""); } if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic)) { - if ((flags & CompilerOptions.UseRoslynMask) != 0) - { - references = references.Concat(visualBasic.Value.Select(r => "-r:\"" + r + "\"")); - } - else - { - references = references.Concat(new[] { "-r:\"Microsoft.VisualBasic.dll\"" }); - } + references = references.Concat(new[] { "-r:\"Microsoft.VisualBasic.dll\"" }); } string otherOptions = $"-noconfig " + $"-langversion:{languageVersion} " + @@ -421,6 +408,13 @@ namespace ICSharpCode.Decompiler.Tests.Helpers if (roslynVersion != "legacy") { otherOptions += "/shared "; + if (Version.Parse(roslynVersion).Major > 2) + { + if (flags.HasFlag(CompilerOptions.NullableEnable)) + otherOptions += "/nullable+ "; + else + otherOptions += "/nullable- "; + } } if (flags.HasFlag(CompilerOptions.Library)) @@ -454,25 +448,22 @@ namespace ICSharpCode.Decompiler.Tests.Helpers otherOptions += " \"-d:" + string.Join(";", preprocessorSymbols) + "\" "; } - ProcessStartInfo info = new ProcessStartInfo(cscPath); - info.Arguments = $"{otherOptions}{string.Join(" ", references)} -out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}"; - info.RedirectStandardError = true; - info.RedirectStandardOutput = true; - info.UseShellExecute = false; - - Console.WriteLine($"\"{info.FileName}\" {info.Arguments}"); + StringBuilder stderr = new(); + StringBuilder stdout = new(); - Process process = Process.Start(info); + var command = Cli.Wrap(cscPath) + .WithArguments($"{otherOptions} -lib:{libPath} {string.Join(" ", references)} -out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}") + .WithStandardErrorPipe(PipeTarget.ToStringBuilder(stderr)) + .WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdout)) + .WithValidation(CommandResultValidation.None); + Console.WriteLine($"\"{command.TargetFilePath}\" {command.Arguments}"); - var outputTask = process.StandardOutput.ReadToEndAsync(); - var errorTask = process.StandardError.ReadToEndAsync(); + var result = await command.ExecuteAsync().ConfigureAwait(false); - Task.WaitAll(outputTask, errorTask); - process.WaitForExit(); + Console.WriteLine("output: " + stdout); + Console.WriteLine("errors: " + stderr); + Assert.AreEqual(0, result.ExitCode, "csc failed"); - Console.WriteLine("output: " + outputTask.Result); - Console.WriteLine("errors: " + errorTask.Result); - Assert.AreEqual(0, process.ExitCode, "csc failed"); return results; } else @@ -518,25 +509,22 @@ namespace ICSharpCode.Decompiler.Tests.Helpers otherOptions += " \"-d:" + string.Join(";", preprocessorSymbols) + "\" "; } - ProcessStartInfo info = new ProcessStartInfo(mcsPath); - info.Arguments = $"{otherOptions}-out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}"; - info.RedirectStandardError = true; - info.RedirectStandardOutput = true; - info.UseShellExecute = false; + StringBuilder stderr = new(); + StringBuilder stdout = new(); - Console.WriteLine($"\"{info.FileName}\" {info.Arguments}"); + var command = Cli.Wrap(mcsPath) + .WithArguments($"{otherOptions}-out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}") + .WithStandardErrorPipe(PipeTarget.ToStringBuilder(stderr)) + .WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdout)) + .WithValidation(CommandResultValidation.None); + Console.WriteLine($"\"{command.TargetFilePath}\" {command.Arguments}"); - Process process = Process.Start(info); + var result = await command.ExecuteAsync().ConfigureAwait(false); - var outputTask = process.StandardOutput.ReadToEndAsync(); - var errorTask = process.StandardError.ReadToEndAsync(); + Console.WriteLine("output: " + stdout); + Console.WriteLine("errors: " + stderr); + Assert.AreEqual(0, result.ExitCode, "mcs failed"); - Task.WaitAll(outputTask, errorTask); - process.WaitForExit(); - - Console.WriteLine("output: " + outputTask.Result); - Console.WriteLine("errors: " + errorTask.Result); - Assert.AreEqual(0, process.ExitCode, "mcs failed"); return results; } } @@ -551,10 +539,15 @@ namespace ICSharpCode.Decompiler.Tests.Helpers CompilerOptions.UseRoslyn3_11_0 => CSharp.LanguageVersion.CSharp9_0, _ => cscOptions.HasFlag(CompilerOptions.Preview) ? CSharp.LanguageVersion.Latest : CSharp.LanguageVersion.CSharp10_0, }; - return new DecompilerSettings(langVersion) { + DecompilerSettings settings = new(langVersion) { // Never use file-scoped namespaces FileScopedNamespaces = false }; + if (!cscOptions.HasFlag(CompilerOptions.NullableEnable)) + { + settings.NullableReferenceTypes = false; + } + return settings; } else { @@ -583,7 +576,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers } var compilation = CSharpCompilation.Create(Path.GetFileNameWithoutExtension(assemblyName), - syntaxTrees, roslynDefaultReferences.Value.Select(r => MetadataReference.CreateFromFile(r)), + syntaxTrees, coreDefaultReferences.Select(r => MetadataReference.CreateFromFile(Path.Combine(coreRefAsmPath, r))), new CSharpCompilationOptions( OutputKind.DynamicallyLinkedLibrary, platform: Platform.AnyCpu, @@ -631,37 +624,101 @@ namespace ICSharpCode.Decompiler.Tests.Helpers return suffix; } - public static int Run(string assemblyFileName, out string output, out string error) + public static async Task<(int ExitCode, string Output, string Error)> Run(string assemblyFileName) { - ProcessStartInfo info = new ProcessStartInfo(assemblyFileName); - info.RedirectStandardError = true; - info.RedirectStandardOutput = true; - info.UseShellExecute = false; + StringBuilder stderr = new(); + StringBuilder stdout = new(); + + var command = Cli.Wrap(assemblyFileName) + .WithStandardErrorPipe(PipeTarget.ToStringBuilder(stderr)) + .WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdout)) + .WithValidation(CommandResultValidation.None); + + var result = await command.ExecuteAsync().ConfigureAwait(false); - Process process = Process.Start(info); + return (result.ExitCode, stdout.ToString(), stderr.ToString()); + } - var outputTask = process.StandardOutput.ReadToEndAsync(); - var errorTask = process.StandardError.ReadToEndAsync(); + public static async Task<(int ExitCode, string Output, string Error)> RunWithTestRunner(string assemblyFileName, bool force32Bit) + { + StringBuilder stderr = new(); + StringBuilder stdout = new(); - Task.WaitAll(outputTask, errorTask); - process.WaitForExit(); + string pathToRunner = force32Bit + ? Path.Combine(TesterPath, "ICSharpCode.Decompiler.TestRunner32.exe") + : Path.Combine(TesterPath, "ICSharpCode.Decompiler.TestRunner.exe"); + var command = Cli.Wrap(pathToRunner) + .WithArguments(assemblyFileName) + .WithStandardErrorPipe(PipeTarget.ToStringBuilder(stderr)) + .WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdout)) + .WithValidation(CommandResultValidation.None); - output = outputTask.Result; - error = errorTask.Result; + var result = await command.ExecuteAsync().ConfigureAwait(false); - return process.ExitCode; + return (result.ExitCode, stdout.ToString(), stderr.ToString()); } + /* + public static int RunInContainer(string assemblyFileName, out string output, out string error) + { + AssemblyLoadContext context = new("RunInContainer", isCollectible: true); + context.Resolving += ContextResolving; + var (oldOut, newOut) = WrapOut(); + var (oldError, newError) = WrapError(); + + int result; + + try + { + var mainAssembly = context.LoadFromAssemblyPath(assemblyFileName); + var tmp = mainAssembly.EntryPoint!.Invoke(null, Array.Empty()); + result = tmp is int i ? i : 0; + } + finally + { + context.Unload(); + context.Resolving -= ContextResolving; + Console.SetOut(oldOut); + Console.SetError(oldError); + } + + output = newOut.ToString(); + error = newError.ToString(); + + return result; - public static string DecompileCSharp(string assemblyFileName, DecompilerSettings settings = null) + static Assembly ContextResolving(AssemblyLoadContext context, AssemblyName name) + { + return null; + } + + static (TextWriter oldWriter, StringBuilder newOutput) WrapOut() + { + var oldWriter = Console.Out; + var newOutput = new StringBuilder(); + Console.SetOut(new StringWriter(newOutput)); + return (oldWriter, newOutput); + } + + static (TextWriter oldWriter, StringBuilder newOutput) WrapError() + { + var oldWriter = Console.Error; + var newOutput = new StringBuilder(); + Console.SetError(new StringWriter(newOutput)); + return (oldWriter, newOutput); + } + } + */ + public static Task DecompileCSharp(string assemblyFileName, DecompilerSettings settings = null) { if (settings == null) settings = new DecompilerSettings(); using (var file = new FileStream(assemblyFileName, FileMode.Open, FileAccess.Read)) { var module = new PEFile(assemblyFileName, file, PEStreamOptions.PrefetchEntireImage); + string targetFramework = module.Reader.DetectTargetFrameworkId(); var resolver = new UniversalAssemblyResolver(assemblyFileName, false, - module.Reader.DetectTargetFrameworkId(), null, PEStreamOptions.PrefetchMetadata); - resolver.AddSearchDirectory(Path.GetDirectoryName(typeof(Span<>).Assembly.Location)); + targetFramework, null, PEStreamOptions.PrefetchMetadata); + resolver.AddSearchDirectory(targetFramework.Contains(".NETFramework") ? refAsmPath : coreRefAsmPath); var typeSystem = new DecompilerTypeSystem(module, resolver, settings); CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, settings); decompiler.AstTransforms.Insert(0, new RemoveEmbeddedAttributes()); @@ -681,7 +738,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers string fileName = Path.GetTempFileName(); File.WriteAllText(fileName, output.ToString()); - return fileName; + return Task.FromResult(fileName); } } @@ -696,11 +753,21 @@ namespace ICSharpCode.Decompiler.Tests.Helpers return formattingPolicy; } - public static void RunAndCompareOutput(string testFileName, string outputFile, string decompiledOutputFile, string decompiledCodeFile = null) + public static async Task RunAndCompareOutput(string testFileName, string outputFile, string decompiledOutputFile, string decompiledCodeFile = null, bool useTestRunner = false, bool force32Bit = false) { string output1, output2, error1, error2; - int result1 = Tester.Run(outputFile, out output1, out error1); - int result2 = Tester.Run(decompiledOutputFile, out output2, out error2); + int result1, result2; + + if (useTestRunner) + { + (result1, output1, error1) = await RunWithTestRunner(outputFile, force32Bit).ConfigureAwait(false); + (result2, output2, error2) = await RunWithTestRunner(decompiledOutputFile, force32Bit).ConfigureAwait(false); + } + else + { + (result1, output1, error1) = await Run(outputFile).ConfigureAwait(false); + (result2, output2, error2) = await Run(decompiledOutputFile).ConfigureAwait(false); + } Assert.AreEqual(0, result1, "Exit code != 0; did the test case crash?" + Environment.NewLine + error1); Assert.AreEqual(0, result2, "Exit code != 0; did the decompiled code crash?" + Environment.NewLine + error2); @@ -780,26 +847,38 @@ namespace ICSharpCode.Decompiler.Tests.Helpers action(); } - public static void SignAssembly(string assemblyPath, string keyFilePath) + public static async Task SignAssembly(string assemblyPath, string keyFilePath) { string snPath = SdkUtility.GetSdkPath("sn.exe"); - ProcessStartInfo info = new ProcessStartInfo(snPath); - info.Arguments = $"-R \"{assemblyPath}\" \"{keyFilePath}\""; - info.RedirectStandardError = true; - info.RedirectStandardOutput = true; - info.UseShellExecute = false; + StringBuilder stderr = new(); + StringBuilder stdout = new(); - Process process = Process.Start(info); + var command = Cli.Wrap(snPath) + .WithArguments($"-R \"{assemblyPath}\" \"{keyFilePath}\"") + .WithStandardErrorPipe(PipeTarget.ToStringBuilder(stderr)) + .WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdout)) + .WithValidation(CommandResultValidation.None); - var outputTask = process.StandardOutput.ReadToEndAsync(); - var errorTask = process.StandardError.ReadToEndAsync(); + var result = await command.ExecuteAsync().ConfigureAwait(false); + Assert.AreEqual(0, result.ExitCode, "sn failed"); - Task.WaitAll(outputTask, errorTask); - process.WaitForExit(); + Console.WriteLine("output: " + stdout); + Console.WriteLine("errors: " + stderr); + } - Console.WriteLine("output: " + outputTask.Result); - Console.WriteLine("errors: " + errorTask.Result); + public static async Task FindMSBuild() + { + string path = vswhereToolset.GetVsWhere(); + StringBuilder stdout = new(); + var result = await Cli.Wrap(path) + .WithArguments(@"-latest -requires Microsoft.Component.MSBuild -find MSBuild\**\Bin\MSBuild.exe") + .WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdout)) + .WithValidation(CommandResultValidation.None) + .ExecuteAsync().ConfigureAwait(false); + if (result.ExitCode != 0) + throw new InvalidOperationException("Could not find MSBuild"); + return stdout.ToString().TrimEnd(); } } diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj index e370a9d59..12a03df02 100644 --- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj @@ -42,7 +42,7 @@ - + @@ -224,7 +224,7 @@ - + diff --git a/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs index b6f3bb72f..b406cc5cc 100644 --- a/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs @@ -20,6 +20,7 @@ using System; using System.IO; using System.Linq; using System.Runtime.CompilerServices; +using System.Threading.Tasks; using ICSharpCode.Decompiler.Tests.Helpers; @@ -51,212 +52,212 @@ namespace ICSharpCode.Decompiler.Tests } [Test, Ignore("Need to decide how to represent virtual methods without 'newslot' flag")] - public void Issue379() + public async Task Issue379() { - Run(); + await Run(); } [Test] - public void Issue646() + public async Task Issue646() { - Run(); + await Run(); } [Test] - public void Issue684() + public async Task Issue684() { - Run(); + await Run(); } [Test] - public void Issue959() + public async Task Issue959() { - Run(); + await Run(); } [Test] - public void Issue982() + public async Task Issue982() { - Run(); + await Run(); } [Test] - public void Issue1038() + public async Task Issue1038() { - Run(); + await Run(); } [Test] - public void Issue1047() + public async Task Issue1047() { - Run(); + await Run(); } [Test] - public void Issue1389() + public async Task Issue1389() { - Run(); + await Run(); } [Test] - public void Issue1918() + public async Task Issue1918() { - Run(); + await Run(); } [Test] - public void Issue1922() + public async Task Issue1922() { - Run(); + await Run(); } [Test] - public void FSharpUsing_Debug() + public async Task FSharpUsing_Debug() { - Run(settings: new DecompilerSettings { RemoveDeadStores = true, UseEnhancedUsing = false, FileScopedNamespaces = false }); + await Run(settings: new DecompilerSettings { RemoveDeadStores = true, UseEnhancedUsing = false, FileScopedNamespaces = false }); } [Test] - public void FSharpUsing_Release() + public async Task FSharpUsing_Release() { - Run(settings: new DecompilerSettings { RemoveDeadStores = true, UseEnhancedUsing = false, FileScopedNamespaces = false }); + await Run(settings: new DecompilerSettings { RemoveDeadStores = true, UseEnhancedUsing = false, FileScopedNamespaces = false }); } [Test] - public void DirectCallToExplicitInterfaceImpl() + public async Task DirectCallToExplicitInterfaceImpl() { - Run(); + await Run(); } [Test] - public void EvalOrder() + public async Task EvalOrder() { - Run(); + await Run(); } [Test] - public void CS1xSwitch_Debug() + public async Task CS1xSwitch_Debug() { - Run(settings: new DecompilerSettings { SwitchExpressions = false, FileScopedNamespaces = false }); + await Run(settings: new DecompilerSettings { SwitchExpressions = false, FileScopedNamespaces = false }); } [Test] - public void CS1xSwitch_Release() + public async Task CS1xSwitch_Release() { - Run(settings: new DecompilerSettings { SwitchExpressions = false, FileScopedNamespaces = false }); + await Run(settings: new DecompilerSettings { SwitchExpressions = false, FileScopedNamespaces = false }); } [Test] - public void UnknownTypes() + public async Task UnknownTypes() { - Run(); + await Run(); } [Test] - public void Issue1145() + public async Task Issue1145() { - Run(); + await Run(); } [Test] - public void Issue1157() + public async Task Issue1157() { - Run(); + await Run(); } [Test] - public void Issue1256() + public async Task Issue1256() { - Run(); + await Run(); } [Test] - public void Issue1323() + public async Task Issue1323() { - Run(); + await Run(); } [Test] - public void Issue1325() + public async Task Issue1325() { - Run(); + await Run(); } [Test] - public void Issue1681() + public async Task Issue1681() { - Run(); + await Run(); } [Test] - public void Issue1454() + public async Task Issue1454() { - Run(); + await Run(); } [Test] - public void Issue2104() + public async Task Issue2104() { - Run(); + await Run(); } [Test] - public void Issue2443() + public async Task Issue2443() { - Run(); + await Run(); } [Test] - public void Issue2260SwitchString() + public async Task Issue2260SwitchString() { - Run(); + await Run(); } [Test] - public void ConstantBlobs() + public async Task ConstantBlobs() { - Run(); + await Run(); } [Test] - public void SequenceOfNestedIfs() + public async Task SequenceOfNestedIfs() { - Run(); + await Run(); } [Test] - public void Unsafe() + public async Task Unsafe() { - Run(assemblerOptions: AssemblerOptions.Library | AssemblerOptions.UseLegacyAssembler); + await Run(assemblerOptions: AssemblerOptions.Library | AssemblerOptions.UseLegacyAssembler); } [Test] - public void CallIndirect() + public async Task CallIndirect() { - Run(); + await Run(); } [Test] - public void FSharpLoops_Debug() + public async Task FSharpLoops_Debug() { CopyFSharpCoreDll(); - Run(settings: new DecompilerSettings { RemoveDeadStores = true, FileScopedNamespaces = false }); + await Run(settings: new DecompilerSettings { RemoveDeadStores = true, FileScopedNamespaces = false }); } [Test] - public void FSharpLoops_Release() + public async Task FSharpLoops_Release() { CopyFSharpCoreDll(); - Run(settings: new DecompilerSettings { RemoveDeadStores = true, FileScopedNamespaces = false }); + await Run(settings: new DecompilerSettings { RemoveDeadStores = true, FileScopedNamespaces = false }); } [Test] - public void WeirdEnums() + public async Task WeirdEnums() { - Run(); + await Run(); } - void Run([CallerMemberName] string testName = null, DecompilerSettings settings = null, + async Task Run([CallerMemberName] string testName = null, DecompilerSettings settings = null, AssemblerOptions assemblerOptions = AssemblerOptions.Library) { if (settings == null) @@ -267,8 +268,8 @@ namespace ICSharpCode.Decompiler.Tests var ilFile = Path.Combine(TestCasePath, testName + ".il"); var csFile = Path.Combine(TestCasePath, testName + ".cs"); - var executable = Tester.AssembleIL(ilFile, assemblerOptions); - var decompiled = Tester.DecompileCSharp(executable, settings); + var executable = await Tester.AssembleIL(ilFile, assemblerOptions).ConfigureAwait(false); + var decompiled = await Tester.DecompileCSharp(executable, settings).ConfigureAwait(false); CodeAssert.FilesAreEqual(csFile, decompiled); } diff --git a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs index 02c443819..13f3b49ea 100644 --- a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs @@ -21,6 +21,7 @@ using System.CodeDom.Compiler; using System.IO; using System.Linq; using System.Runtime.CompilerServices; +using System.Threading.Tasks; using ICSharpCode.Decompiler.Tests.Helpers; @@ -93,14 +94,6 @@ namespace ICSharpCode.Decompiler.Tests CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest, }; - static readonly CompilerOptions[] dotnetCoreOnlyOptions = - { - CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.ReferenceCore, - CompilerOptions.Optimize | CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.ReferenceCore, - CompilerOptions.UseRoslynLatest | CompilerOptions.ReferenceCore, - CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest | CompilerOptions.ReferenceCore, - }; - static readonly CompilerOptions[] defaultOptions = { CompilerOptions.None, @@ -134,50 +127,50 @@ namespace ICSharpCode.Decompiler.Tests }; [Test] - public void HelloWorld() + public async Task HelloWorld() { - RunForLibrary(); - RunForLibrary(asmOptions: AssemblerOptions.UseDebug); + await RunForLibrary(); + await RunForLibrary(asmOptions: AssemblerOptions.UseDebug); } [Test] - public void IndexRangeTest([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions) + public async Task IndexRangeTest([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions) { if (cscOptions.HasFlag(CompilerOptions.UseRoslynLatest)) { Assert.Ignore("See https://github.com/icsharpcode/ILSpy/issues/2540"); } - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void InlineAssignmentTest([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task InlineAssignmentTest([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void CompoundAssignmentTest([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task CompoundAssignmentTest([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void ShortCircuit([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task ShortCircuit([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void CustomShortCircuitOperators([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task CustomShortCircuitOperators([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void ExceptionHandling([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task ExceptionHandling([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings { + await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings { NullPropagation = false, // legacy csc generates a dead store in debug builds RemoveDeadStores = (cscOptions == CompilerOptions.None), @@ -186,9 +179,9 @@ namespace ICSharpCode.Decompiler.Tests } [Test] - public void Switch([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task Switch([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings { + await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings { // legacy csc generates a dead store in debug builds RemoveDeadStores = (cscOptions == CompilerOptions.None), SwitchExpressions = false, @@ -197,45 +190,45 @@ namespace ICSharpCode.Decompiler.Tests } [Test] - public void SwitchExpressions([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions) + public async Task SwitchExpressions([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void ReduceNesting([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task ReduceNesting([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void DelegateConstruction([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) + public async Task DelegateConstruction([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); + await RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); } [Test] - public void AnonymousTypes([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) + public async Task AnonymousTypes([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void Async([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task Async([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void Lock([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) + public async Task Lock([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void Using([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task Using([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary( + await RunForLibrary( cscOptions: cscOptions, decompilerSettings: new DecompilerSettings { UseEnhancedUsing = false, @@ -245,27 +238,27 @@ namespace ICSharpCode.Decompiler.Tests } [Test] - public void UsingVariables([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions) + public async Task UsingVariables([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void LiftedOperators([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task LiftedOperators([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void Generics([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task Generics([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void Loops([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) + public async Task Loops([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings { + await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings { // legacy csc generates a dead store in debug builds RemoveDeadStores = (cscOptions == CompilerOptions.None), UseExpressionBodyForCalculatedGetterOnlyProperties = false, @@ -274,371 +267,383 @@ namespace ICSharpCode.Decompiler.Tests } [Test] - public void LocalFunctions([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) + public async Task LocalFunctions([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); + await RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); } [Test] - public void PropertiesAndEvents([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task PropertiesAndEvents([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions | CompilerOptions.NullableEnable); } [Test] - public void AutoProperties([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) + public async Task AutoProperties([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void QueryExpressions([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task QueryExpressions([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void TypeAnalysisTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task TypeAnalysisTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void CheckedUnchecked([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task CheckedUnchecked([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void UnsafeCode([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task UnsafeCode([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void ConstructorInitializers([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) + public async Task ConstructorInitializers([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void PInvoke([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task PInvoke([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { // This tests needs our own disassembler; ildasm has a bug with marshalinfo. - RunForLibrary(cscOptions: cscOptions, asmOptions: AssemblerOptions.UseOwnDisassembler); + await RunForLibrary(cscOptions: cscOptions, asmOptions: AssemblerOptions.UseOwnDisassembler); } [Test] - public void OutVariables([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) + public async Task OutVariables([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void PatternMatching([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) + public async Task PatternMatching([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void InitializerTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task InitializerTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions | CompilerOptions.NullableEnable); } [Test] - public void DynamicTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task DynamicTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void ExpressionTrees([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task ExpressionTrees([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void FixProxyCalls([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task FixProxyCalls([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void ValueTypes([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) + public async Task ValueTypes([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void VariableNaming([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task VariableNaming([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions | CompilerOptions.GeneratePdb); + await RunForLibrary(cscOptions: cscOptions | CompilerOptions.GeneratePdb); } [Test] - public void VariableNamingWithoutSymbols([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task VariableNamingWithoutSymbols([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { var settings = Tester.GetSettings(cscOptions); settings.UseDebugSymbols = false; - RunForLibrary(cscOptions: cscOptions, decompilerSettings: settings); + await RunForLibrary(cscOptions: cscOptions, decompilerSettings: settings); } [Test] - public void CS72_PrivateProtected([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) + public async Task CS72_PrivateProtected([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void AsyncForeach([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions) + public async Task AsyncForeach([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void AsyncMain([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) + public async Task AsyncMain([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) { - Run(cscOptions: cscOptions); + await Run(cscOptions: cscOptions); } [Test] - public void AsyncStreams([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions) + public async Task AsyncStreams([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void AsyncUsing([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions) + public async Task AsyncUsing([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary( + await RunForLibrary( cscOptions: cscOptions, decompilerSettings: new DecompilerSettings { UseEnhancedUsing = false, FileScopedNamespaces = false } ); } [Test] - public void CustomTaskType([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) + public async Task CustomTaskType([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void NullableRefTypes([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions) + public async Task NullableRefTypes([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions | CompilerOptions.NullableEnable); } [Test] - public void NativeInts([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions) + public async Task NativeInts([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); + await RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); } [Test] - public void FileScopedNamespaces([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions) + public async Task FileScopedNamespaces([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings()); + await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings()); } [Test] - public void Structs([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) + public async Task Structs([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void FunctionPointers([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions) + public async Task FunctionPointers([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); + await RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); } [Test] - public void Records([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions) + public async Task Records([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); + await RunForLibrary(cscOptions: cscOptions | CompilerOptions.NullableEnable); } [Test] - public void NullPropagation([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) + public async Task NullPropagation([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void CS6_StringInterpolation([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) + public async Task StringInterpolation([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) { - Run(cscOptions: cscOptions); + if (cscOptions.HasFlag(CompilerOptions.UseRoslynLatest)) + { + Assert.Ignore("DefaultInterpolatedStringHandler is not yet supported!"); + return; + } + + await Run(cscOptions: cscOptions); } [Test] - public void CS73_StackAllocInitializers([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions) + public async Task CS73_StackAllocInitializers([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void RefLocalsAndReturns([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) + public async Task RefLocalsAndReturns([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void ThrowExpressions([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) + public async Task ThrowExpressions([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void WellKnownConstants([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task WellKnownConstants([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void QualifierTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task QualifierTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void TupleTests([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) + public async Task TupleTests([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + if (cscOptions.HasFlag(CompilerOptions.UseRoslynLatest)) + { + Assert.Ignore("DefaultInterpolatedStringHandler is not yet supported!"); + return; + } + + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void NamedArguments([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task NamedArguments([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void OptionalArguments([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task OptionalArguments([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); + await RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); } [Test] - public void ConstantsTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task ConstantsTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void Issue1080([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) + public async Task Issue1080([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp6)); + await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp6)); } [Test] - public void AssemblyCustomAttributes([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task AssemblyCustomAttributes([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void CustomAttributes([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task CustomAttributes([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void CustomAttributes2([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task CustomAttributes2([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void CustomAttributeConflicts([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task CustomAttributeConflicts([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void CustomAttributeSamples([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task CustomAttributeSamples([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void MemberTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task MemberTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void MultidimensionalArray([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task MultidimensionalArray([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void EnumTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task EnumTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void InterfaceTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task InterfaceTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions | CompilerOptions.ReferenceCore); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void TypeMemberTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task TypeMemberTests([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void YieldReturn([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) + public async Task YieldReturn([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void UserDefinedConversions([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task UserDefinedConversions([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void Discards([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) + public async Task Discards([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void DeconstructionTests([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) + public async Task DeconstructionTests([ValueSource(nameof(roslyn2OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions); + await RunForLibrary(cscOptions: cscOptions); } [Test] - public void CS9_ExtensionGetEnumerator([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions) + public async Task CS9_ExtensionGetEnumerator([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); + await RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); } [Test] - public void CovariantReturns([ValueSource(nameof(dotnetCoreOnlyOptions))] CompilerOptions cscOptions) + public async Task CovariantReturns([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); + await RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); } [Test] - public void StaticAbstractInterfaceMembers([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions) + public async Task StaticAbstractInterfaceMembers([ValueSource(nameof(roslynLatestOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview | CompilerOptions.ReferenceCore); + await RunForLibrary(cscOptions: cscOptions | CompilerOptions.Preview); } - void RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) + async Task RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) { - Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, decompilerSettings); + await Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, decompilerSettings); } - void Run([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) + 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"; @@ -651,7 +656,7 @@ namespace ICSharpCode.Decompiler.Tests CompilerResults output = null; try { - output = Tester.CompileCSharp(csFile, cscOptions, exeFile); + output = await Tester.CompileCSharp(csFile, cscOptions, exeFile).ConfigureAwait(false); } finally { @@ -660,7 +665,7 @@ namespace ICSharpCode.Decompiler.Tests } // 2. Decompile - var decompiled = Tester.DecompileCSharp(exeFile, decompilerSettings ?? Tester.GetSettings(cscOptions)); + var decompiled = await Tester.DecompileCSharp(exeFile, decompilerSettings ?? Tester.GetSettings(cscOptions)).ConfigureAwait(false); // 3. Compile CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(cscOptions).ToArray()); diff --git a/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs b/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs index 33f8d08b0..f4b0037f9 100644 --- a/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs +++ b/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs @@ -19,18 +19,18 @@ using System; using System.Diagnostics; using System.IO; -using System.Linq; using System.Reflection.PortableExecutable; using System.Text.RegularExpressions; using System.Threading; +using System.Threading.Tasks; + +using CliWrap; using ICSharpCode.Decompiler.CSharp; using ICSharpCode.Decompiler.CSharp.ProjectDecompiler; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Tests.Helpers; -using Microsoft.Build.Locator; - using NUnit.Framework; namespace ICSharpCode.Decompiler.Tests @@ -42,23 +42,23 @@ namespace ICSharpCode.Decompiler.Tests static readonly string nunit = Path.Combine(TestDir, "nunit", "nunit3-console.exe"); [Test] - public void Cecil_net45() + public async Task Cecil_net45() { - RunWithTest("Mono.Cecil-net45", "Mono.Cecil.dll", "Mono.Cecil.Tests.dll"); + await RunWithTest("Mono.Cecil-net45", "Mono.Cecil.dll", "Mono.Cecil.Tests.dll"); } [Test] - public void NewtonsoftJson_net45() + public async Task NewtonsoftJson_net45() { - RunWithTest("Newtonsoft.Json-net45", "Newtonsoft.Json.dll", "Newtonsoft.Json.Tests.dll"); + await RunWithTest("Newtonsoft.Json-net45", "Newtonsoft.Json.dll", "Newtonsoft.Json.Tests.dll"); } [Test] - public void NewtonsoftJson_pcl_debug() + public async Task NewtonsoftJson_pcl_debug() { try { - RunWithTest("Newtonsoft.Json-pcl-debug", "Newtonsoft.Json.dll", "Newtonsoft.Json.Tests.dll", useOldProjectFormat: true); + await RunWithTest("Newtonsoft.Json-pcl-debug", "Newtonsoft.Json.dll", "Newtonsoft.Json.Tests.dll", useOldProjectFormat: true); } catch (CompilationFailedException) { @@ -67,89 +67,89 @@ namespace ICSharpCode.Decompiler.Tests } [Test] - public void NRefactory_CSharp() + public async Task NRefactory_CSharp() { - RunWithTest("NRefactory", "ICSharpCode.NRefactory.CSharp.dll", "ICSharpCode.NRefactory.Tests.dll"); + await RunWithTest("NRefactory", "ICSharpCode.NRefactory.CSharp.dll", "ICSharpCode.NRefactory.Tests.dll"); } [Test] - public void ICSharpCode_Decompiler() + public async Task ICSharpCode_Decompiler() { - RunOnly("ICSharpCode.Decompiler", "ICSharpCode.Decompiler.dll"); + await RunOnly("ICSharpCode.Decompiler", "ICSharpCode.Decompiler.dll"); } [Test] - public void ImplicitConversions() + public async Task ImplicitConversions() { - RunWithOutput("Random Tests\\TestCases", "ImplicitConversions.exe"); + await RunWithOutput("Random Tests\\TestCases", "ImplicitConversions.exe"); } [Test] - public void ImplicitConversions_32() + public async Task ImplicitConversions_32() { - RunWithOutput("Random Tests\\TestCases", "ImplicitConversions_32.exe"); + await RunWithOutput("Random Tests\\TestCases", "ImplicitConversions_32.exe"); } [Test] - public void ExplicitConversions() + public async Task ExplicitConversions() { - RunWithOutput("Random Tests\\TestCases", "ExplicitConversions.exe", LanguageVersion.CSharp8_0); + await RunWithOutput("Random Tests\\TestCases", "ExplicitConversions.exe", LanguageVersion.CSharp8_0); } [Test] - public void ExplicitConversions_32() + public async Task ExplicitConversions_32() { - RunWithOutput("Random Tests\\TestCases", "ExplicitConversions_32.exe", LanguageVersion.CSharp8_0); + await RunWithOutput("Random Tests\\TestCases", "ExplicitConversions_32.exe", LanguageVersion.CSharp8_0); } [Test] - public void ExplicitConversions_With_NativeInts() + public async Task ExplicitConversions_With_NativeInts() { - RunWithOutput("Random Tests\\TestCases", "ExplicitConversions.exe", LanguageVersion.CSharp9_0); + await RunWithOutput("Random Tests\\TestCases", "ExplicitConversions.exe", LanguageVersion.CSharp9_0); } [Test] - public void ExplicitConversions_32_With_NativeInts() + public async Task ExplicitConversions_32_With_NativeInts() { - RunWithOutput("Random Tests\\TestCases", "ExplicitConversions_32.exe", LanguageVersion.CSharp9_0); + await RunWithOutput("Random Tests\\TestCases", "ExplicitConversions_32.exe", LanguageVersion.CSharp9_0); } [Test] - public void Random_TestCase_1() + public async Task Random_TestCase_1() { - RunWithOutput("Random Tests\\TestCases", "TestCase-1.exe", LanguageVersion.CSharp8_0); + await RunWithOutput("Random Tests\\TestCases", "TestCase-1.exe", LanguageVersion.CSharp8_0); } [Test] [Ignore("See https://github.com/icsharpcode/ILSpy/issues/2541 - Waiting for https://github.com/dotnet/roslyn/issues/45929")] - public void Random_TestCase_1_With_NativeInts() + public async Task Random_TestCase_1_With_NativeInts() { - RunWithOutput("Random Tests\\TestCases", "TestCase-1.exe", LanguageVersion.CSharp9_0); + await RunWithOutput("Random Tests\\TestCases", "TestCase-1.exe", LanguageVersion.CSharp9_0); } // Let's limit the roundtrip tests to C# 8.0 for now; because 9.0 is still in preview // and the generated project doesn't build as-is. const LanguageVersion defaultLanguageVersion = LanguageVersion.CSharp8_0; - void RunWithTest(string dir, string fileToRoundtrip, string fileToTest, LanguageVersion languageVersion = defaultLanguageVersion, string keyFile = null, bool useOldProjectFormat = false) + async Task RunWithTest(string dir, string fileToRoundtrip, string fileToTest, LanguageVersion languageVersion = defaultLanguageVersion, string keyFile = null, bool useOldProjectFormat = false) { - RunInternal(dir, fileToRoundtrip, outputDir => RunTest(outputDir, fileToTest), languageVersion, snkFilePath: keyFile, useOldProjectFormat: useOldProjectFormat); + await RunInternal(dir, fileToRoundtrip, outputDir => RunTest(outputDir, fileToTest).GetAwaiter().GetResult(), languageVersion, snkFilePath: keyFile, useOldProjectFormat: useOldProjectFormat); } - void RunWithOutput(string dir, string fileToRoundtrip, LanguageVersion languageVersion = defaultLanguageVersion) + async Task RunWithOutput(string dir, string fileToRoundtrip, LanguageVersion languageVersion = defaultLanguageVersion) { string inputDir = Path.Combine(TestDir, dir); - RunInternal(dir, fileToRoundtrip, - outputDir => Tester.RunAndCompareOutput(fileToRoundtrip, Path.Combine(inputDir, fileToRoundtrip), Path.Combine(outputDir, fileToRoundtrip)), + await RunInternal(dir, fileToRoundtrip, + outputDir => Tester.RunAndCompareOutput(fileToRoundtrip, Path.Combine(inputDir, fileToRoundtrip), Path.Combine(outputDir, fileToRoundtrip)).GetAwaiter().GetResult(), languageVersion); } - void RunOnly(string dir, string fileToRoundtrip, LanguageVersion languageVersion = defaultLanguageVersion) + async Task RunOnly(string dir, string fileToRoundtrip, LanguageVersion languageVersion = defaultLanguageVersion) { - RunInternal(dir, fileToRoundtrip, outputDir => { }, languageVersion); + await RunInternal(dir, fileToRoundtrip, outputDir => { }, languageVersion); } - void RunInternal(string dir, string fileToRoundtrip, Action testAction, LanguageVersion languageVersion, string snkFilePath = null, bool useOldProjectFormat = false) + async Task RunInternal(string dir, string fileToRoundtrip, Action testAction, LanguageVersion languageVersion, string snkFilePath = null, bool useOldProjectFormat = false) { if (!Directory.Exists(TestDir)) { @@ -214,7 +214,7 @@ namespace ICSharpCode.Decompiler.Tests } Assert.IsNotNull(projectFile, $"Could not find {fileToRoundtrip}"); - Compile(projectFile, outputDir); + await Compile(projectFile, outputDir); testAction(outputDir); } @@ -244,73 +244,47 @@ namespace ICSharpCode.Decompiler.Tests } } - static string FindMSBuild() - { - string vsPath = MSBuildLocator.QueryVisualStudioInstances(new VisualStudioInstanceQueryOptions { DiscoveryTypes = DiscoveryType.VisualStudioSetup }) - .OrderByDescending(i => i.Version) - .FirstOrDefault() - ?.MSBuildPath; - if (vsPath == null) - throw new InvalidOperationException("Could not find MSBuild"); - return Path.Combine(vsPath, "msbuild.exe"); - } - - static void Compile(string projectFile, string outputDir) + static async Task Compile(string projectFile, string outputDir) { - var info = new ProcessStartInfo(FindMSBuild()); - info.Arguments = $"/nologo /v:minimal /restore /p:OutputPath=\"{outputDir}\" \"{projectFile}\""; - info.CreateNoWindow = true; - info.UseShellExecute = false; - info.RedirectStandardOutput = true; - // Don't let environment variables (e.g. set by AppVeyor) influence the build. - info.EnvironmentVariables.Remove("Configuration"); - info.EnvironmentVariables.Remove("Platform"); - Console.WriteLine($"\"{info.FileName}\" {info.Arguments}"); - using (var p = Process.Start(info)) + Regex errorRegex = new Regex(@"^[\w\d.\\-]+\(\d+,\d+\):"); + string suffix = $" [{projectFile}]"; + + var command = Cli.Wrap(await Tester.FindMSBuild()) + .WithArguments($"/nologo /v:minimal /restore /p:OutputPath=\"{outputDir}\" \"{projectFile}\"") + .WithValidation(CommandResultValidation.None) + .WithStandardOutputPipe(PipeTarget.ToDelegate(PrintLine)); + Console.WriteLine($"\"{command.TargetFilePath}\" {command.Arguments}"); + var result = await command.ExecuteAsync().ConfigureAwait(false); + if (result.ExitCode != 0) + throw new CompilationFailedException($"Compilation of {Path.GetFileName(projectFile)} failed"); + + void PrintLine(string line) { - Regex errorRegex = new Regex(@"^[\w\d.\\-]+\(\d+,\d+\):"); - string suffix = $" [{projectFile}]"; - string line; - while ((line = p.StandardOutput.ReadLine()) != null) + if (line.EndsWith(suffix, StringComparison.OrdinalIgnoreCase)) { - if (line.EndsWith(suffix, StringComparison.OrdinalIgnoreCase)) - { - line = line.Substring(0, line.Length - suffix.Length); - } - Match m = errorRegex.Match(line); - if (m.Success) - { - // Make path absolute so that it gets hyperlinked - line = Path.GetDirectoryName(projectFile) + Path.DirectorySeparatorChar + line; - } - Console.WriteLine(line); + line = line.Substring(0, line.Length - suffix.Length); + } + Match m = errorRegex.Match(line); + if (m.Success) + { + // Make path absolute so that it gets hyperlinked + line = Path.GetDirectoryName(projectFile) + Path.DirectorySeparatorChar + line; } - p.WaitForExit(); - if (p.ExitCode != 0) - throw new CompilationFailedException($"Compilation of {Path.GetFileName(projectFile)} failed"); + Console.WriteLine(line); } } - static void RunTest(string outputDir, string fileToTest) + static async Task RunTest(string outputDir, string fileToTest) { - var info = new ProcessStartInfo(nunit); - info.WorkingDirectory = outputDir; - info.Arguments = $"\"{fileToTest}\""; - info.CreateNoWindow = true; - info.UseShellExecute = false; - info.RedirectStandardOutput = true; - Console.WriteLine($"\"{info.FileName}\" {info.Arguments}"); - using (var p = Process.Start(info)) - { - string line; - while ((line = p.StandardOutput.ReadLine()) != null) - { - Console.WriteLine(line); - } - p.WaitForExit(); - if (p.ExitCode != 0) - throw new TestRunFailedException($"Test execution of {Path.GetFileName(fileToTest)} failed"); - } + var command = Cli.Wrap(nunit) + .WithWorkingDirectory(outputDir) + .WithArguments($"\"{fileToTest}\"") + .WithValidation(CommandResultValidation.None) + .WithStandardOutputPipe(PipeTarget.ToDelegate(Console.WriteLine)); + Console.WriteLine($"\"{command.TargetFilePath}\" {command.Arguments}"); + var result = await command.ExecuteAsync().ConfigureAwait(false); + if (result.ExitCode != 0) + throw new TestRunFailedException($"Test execution of {Path.GetFileName(fileToTest)} failed"); } class TestProjectDecompiler : WholeProjectDecompiler diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DeconstructionTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DeconstructionTests.cs index 512a1b192..79bdbfee8 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DeconstructionTests.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DeconstructionTests.cs @@ -22,15 +22,6 @@ using System.Runtime.InteropServices; namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { - public static class DeconstructionExt - { - public static void Deconstruct(this KeyValuePair pair, out K key, out V value) - { - key = pair.Key; - value = pair.Value; - } - } - internal class DeconstructionTests { [StructLayout(LayoutKind.Sequential, Size = 1)] diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.cs index 591fe4fc3..fd306db7d 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/QueryExpressions.cs @@ -20,6 +20,9 @@ using System; using System.Collections.Generic; using System.Linq; using System.Reflection; +#if ROSLYN4 +using System.Runtime.CompilerServices; +#endif namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS6_StringInterpolation.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/StringInterpolation.cs similarity index 99% rename from ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS6_StringInterpolation.cs rename to ICSharpCode.Decompiler.Tests/TestCases/Pretty/StringInterpolation.cs index 049e5677e..41f57d523 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/CS6_StringInterpolation.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/StringInterpolation.cs @@ -2,7 +2,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { - internal class CS6_StringInterpolation + internal class StringInterpolation { public static void Main(string[] args) { diff --git a/ICSharpCode.Decompiler.Tests/TestTraceListener.cs b/ICSharpCode.Decompiler.Tests/TestTraceListener.cs index 19c4bbd83..c7a28605b 100644 --- a/ICSharpCode.Decompiler.Tests/TestTraceListener.cs +++ b/ICSharpCode.Decompiler.Tests/TestTraceListener.cs @@ -17,6 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System.Diagnostics; +using System.Threading.Tasks; + +using ICSharpCode.Decompiler.Tests.Helpers; using NUnit.Framework; @@ -42,4 +45,14 @@ namespace ICSharpCode.Decompiler.Tests Assert.Fail(message + " " + detailMessage); } } + + [SetUpFixture] + public class ToolsetSetup + { + [OneTimeSetUp] + public async Task RunBeforeAnyTests() + { + await Tester.Initialize(); + } + } } diff --git a/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs b/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs index 11dbeeba7..5c09c093d 100644 --- a/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs @@ -21,6 +21,7 @@ using System.CodeDom.Compiler; using System.IO; using System.Linq; using System.Runtime.CompilerServices; +using System.Threading.Tasks; using ICSharpCode.Decompiler.Tests.Helpers; @@ -72,67 +73,67 @@ namespace ICSharpCode.Decompiler.Tests }; [Test] - public void NoArrayInitializers([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) + public async Task NoArrayInitializers([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp1) { + await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp1) { ArrayInitializers = false }); } [Test] - public void NoDecimalConstants([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) + public async Task NoDecimalConstants([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp1) { + await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp1) { DecimalConstants = false }); } [Test] - public void NoExtensionMethods([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) + public async Task NoExtensionMethods([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp9_0) { + await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp9_0) { ExtensionMethods = false }); } [Test] - public void NoForEachStatement([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task NoForEachStatement([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp1) { + await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp1) { ForEachStatement = false, UseEnhancedUsing = false, }); } [Test] - public void NoLocalFunctions([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) + public async Task NoLocalFunctions([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp1)); + await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp1)); } [Test] - public void NoPropertiesAndEvents([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) + public async Task NoPropertiesAndEvents([ValueSource(nameof(defaultOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp1) { + await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp1) { AutomaticEvents = false, AutomaticProperties = false, }); } [Test] - public void AggressiveScalarReplacementOfAggregates([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) + public async Task AggressiveScalarReplacementOfAggregates([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) { - RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp3) { + await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings(CSharp.LanguageVersion.CSharp3) { AggressiveScalarReplacementOfAggregates = true }); } - void RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) + async Task RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) { - Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, decompilerSettings); + await Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, decompilerSettings); } - void Run([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) + 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"); @@ -144,8 +145,8 @@ namespace ICSharpCode.Decompiler.Tests CompilerResults output = null; try { - output = Tester.CompileCSharp(csFile, cscOptions); - Tester.Disassemble(output.PathToAssembly, ilFile, asmOptions); + output = await Tester.CompileCSharp(csFile, cscOptions).ConfigureAwait(false); + await Tester.Disassemble(output.PathToAssembly, ilFile, asmOptions).ConfigureAwait(false); } finally { @@ -154,8 +155,8 @@ namespace ICSharpCode.Decompiler.Tests } } - var executable = Tester.AssembleIL(ilFile, asmOptions); - var decompiled = Tester.DecompileCSharp(executable, decompilerSettings); + 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()); } diff --git a/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs index a0559a39c..30a456759 100644 --- a/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs @@ -20,6 +20,7 @@ using System; using System.IO; using System.Linq; using System.Runtime.CompilerServices; +using System.Threading.Tasks; using ICSharpCode.Decompiler.Tests.Helpers; @@ -73,42 +74,42 @@ namespace ICSharpCode.Decompiler.Tests }; [Test, Ignore("Implement VB async/await")] - public void Async([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task Async([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - Run(options: options); + await Run(options: options); } [Test] // TODO: legacy VB compound assign - public void VBCompoundAssign([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions options) + public async Task VBCompoundAssign([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions options) { - Run(options: options | CompilerOptions.Library); + await Run(options: options | CompilerOptions.Library); } [Test] - public void Select([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task Select([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - Run(options: options | CompilerOptions.Library); + await Run(options: options | CompilerOptions.Library); } [Test] - public void Issue1906([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task Issue1906([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - Run(options: options | CompilerOptions.Library); + await Run(options: options | CompilerOptions.Library); } [Test] - public void Issue2192([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task Issue2192([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - Run(options: options | CompilerOptions.Library); + await Run(options: options | CompilerOptions.Library); } [Test] - public void VBPropertiesTest([ValueSource(nameof(defaultOptions))] CompilerOptions options) + public async Task VBPropertiesTest([ValueSource(nameof(defaultOptions))] CompilerOptions options) { - Run(options: options | CompilerOptions.Library); + await Run(options: options | CompilerOptions.Library); } - void Run([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug, DecompilerSettings settings = null) + async Task Run([CallerMemberName] string testName = null, CompilerOptions options = CompilerOptions.UseDebug, DecompilerSettings settings = null) { var vbFile = Path.Combine(TestCasePath, testName + ".vb"); var csFile = Path.Combine(TestCasePath, testName + ".cs"); @@ -118,8 +119,8 @@ namespace ICSharpCode.Decompiler.Tests exeFile = Path.ChangeExtension(exeFile, ".dll"); } - var executable = Tester.CompileVB(vbFile, options | CompilerOptions.ReferenceVisualBasic, exeFile); - var decompiled = Tester.DecompileCSharp(executable.PathToAssembly, settings); + var executable = await Tester.CompileVB(vbFile, options | CompilerOptions.ReferenceVisualBasic, exeFile).ConfigureAwait(false); + var decompiled = await Tester.DecompileCSharp(executable.PathToAssembly, settings).ConfigureAwait(false); CodeAssert.FilesAreEqual(csFile, decompiled, Tester.GetPreprocessorSymbols(options).ToArray()); } diff --git a/ILSpy.sln b/ILSpy.sln index 682e4b8c8..24ffba062 100644 --- a/ILSpy.sln +++ b/ILSpy.sln @@ -20,6 +20,9 @@ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.Decompiler", "ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj", "{984CC812-9470-4A13-AFF9-CC44068D666C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.Decompiler.Tests", "ICSharpCode.Decompiler.Tests\ICSharpCode.Decompiler.Tests.csproj", "{FEC0DA52-C4A6-4710-BE36-B484A20C5E22}" + ProjectSection(ProjectDependencies) = postProject + {4FBB470F-69EB-4C8B-8961-8B4DF4EBB999} = {4FBB470F-69EB-4C8B-8961-8B4DF4EBB999} + EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestPlugin", "TestPlugin\TestPlugin.csproj", "{F32EBCC8-0E53-4421-867E-05B3D6E10C70}" EndProject @@ -58,6 +61,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ILSpy.Installer", "ILSpy.In {1E85EFF9-E370-4683-83E4-8A3D063FF791} = {1E85EFF9-E370-4683-83E4-8A3D063FF791} EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ICSharpCode.Decompiler.TestRunner", "ICSharpCode.Decompiler.TestRunner\ICSharpCode.Decompiler.TestRunner.csproj", "{4FBB470F-69EB-4C8B-8961-8B4DF4EBB999}" +EndProject Global GlobalSection(SharedMSBuildProjectFiles) = preSolution ILSpy.AddIn.Shared\ILSpy.AddIn.Shared.projitems*{09a03980-d14a-4705-a38c-741ad7166dee}*SharedItemsImports = 5 @@ -129,6 +134,10 @@ Global {A4BA0771-DA4A-4A94-A5EC-5BA10B52816F}.Debug|Any CPU.Build.0 = Debug|Any CPU {A4BA0771-DA4A-4A94-A5EC-5BA10B52816F}.Release|Any CPU.ActiveCfg = Release|Any CPU {A4BA0771-DA4A-4A94-A5EC-5BA10B52816F}.Release|Any CPU.Build.0 = Release|Any CPU + {4FBB470F-69EB-4C8B-8961-8B4DF4EBB999}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4FBB470F-69EB-4C8B-8961-8B4DF4EBB999}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4FBB470F-69EB-4C8B-8961-8B4DF4EBB999}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4FBB470F-69EB-4C8B-8961-8B4DF4EBB999}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE