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