Browse Source

Run the decompiler test suite on Linux

Compilation uses the .NET builds of the Roslyn toolsets (tasks/netcore*,
bincore csc.dll/vbc.dll launched through the dotnet host). ilasm/ildasm
options use the '-' prefix, which all platforms accept. The dotnet-hosted
compilers have no implicit references or SDK path: net40 compiles pass
mscorlib explicitly, and vbc gets -sdkpath, _MYTYPE=Empty and
-vbruntime:Microsoft.VisualBasic.Core.dll (the facade in the ref packs is
not followed for runtime helpers). The TestRunner gets a self-contained
build for the host platform.

Configurations depending on Windows-only tools or runtimes (legacy
csc/vbc, Roslyn 1.x/2.x, mcs, Force32Bit, executing net40 binaries) are
filtered from the matrix off-Windows via Tester.SupportedOnCurrentPlatform
or gated with [Platform("Win")]. PdbGen comparisons normalize document
name separators, and Correctness/Async uses Console.IsInputRedirected
instead of the Windows-only Console.CapsLock.

Assisted-by: Claude:claude-fable-5:Claude Code
pull/3773/head
Siegfried Pammer 4 weeks ago committed by Siegfried Pammer
parent
commit
0f9de78f02
  1. 41
      ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
  2. 6
      ICSharpCode.Decompiler.Tests/Helpers/RoslynToolset.cs
  3. 27
      ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs
  4. 102
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  5. 2
      ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
  6. 7
      ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs
  7. 50
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  8. 4
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/Async.cs
  9. 12
      ICSharpCode.Decompiler.Tests/UglyTestRunner.cs
  10. 13
      ICSharpCode.Decompiler.Tests/Util/FileUtilityTests.cs
  11. 8
      ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs

41
ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs

@ -16,6 +16,7 @@ @@ -16,6 +16,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
@ -48,7 +49,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -48,7 +49,7 @@ namespace ICSharpCode.Decompiler.Tests
}
}
static readonly CompilerOptions[] noMonoOptions =
static readonly CompilerOptions[] noMonoOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.None,
CompilerOptions.Optimize,
@ -72,9 +73,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -72,9 +73,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
}, executesCompiledOutput: true);
static readonly CompilerOptions[] net40OnlyOptions =
static readonly CompilerOptions[] net40OnlyOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.None,
CompilerOptions.Optimize,
@ -88,9 +89,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -88,9 +89,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslynLatest | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest | CompilerOptions.TargetNet40,
};
}, executesCompiledOutput: true);
static readonly CompilerOptions[] defaultOptions =
static readonly CompilerOptions[] defaultOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.None,
CompilerOptions.Optimize,
@ -118,9 +119,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -118,9 +119,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseMcs2_6_4,
CompilerOptions.UseMcs5_23,
CompilerOptions.Optimize | CompilerOptions.UseMcs5_23
};
}, executesCompiledOutput: true);
static readonly CompilerOptions[] roslynOnlyOptions =
static readonly CompilerOptions[] roslynOnlyOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
@ -142,9 +143,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -142,9 +143,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
}, executesCompiledOutput: true);
static readonly CompilerOptions[] roslyn2OrNewerOptions =
static readonly CompilerOptions[] roslyn2OrNewerOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
@ -162,7 +163,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -162,7 +163,7 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
}, executesCompiledOutput: true);
[Test]
public async Task Comparisons([ValueSource(nameof(defaultOptions))] CompilerOptions options)
@ -176,8 +177,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -176,8 +177,12 @@ namespace ICSharpCode.Decompiler.Tests
await RunCS(options: options);
}
// 32-bit execution requires a 32-bit runtime, which only exists on Windows.
static readonly int[] supportedBitness = OperatingSystem.IsWindows() ? new[] { 32, 64 } : new[] { 64 };
static readonly bool[] supportedForce32Bit = OperatingSystem.IsWindows() ? new[] { false, true } : new[] { false };
[Test]
public async Task FloatingPointArithmetic([ValueSource(nameof(noMonoOptions))] CompilerOptions options, [Values(32, 64)] int bits)
public async Task FloatingPointArithmetic([ValueSource(nameof(noMonoOptions))] CompilerOptions options, [ValueSource(nameof(supportedBitness))] int bits)
{
// The behavior of the #1794 incorrect `(float)(double)val` cast only causes test failures
// for some runtime+compiler combinations.
@ -260,7 +265,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -260,7 +265,7 @@ namespace ICSharpCode.Decompiler.Tests
await RunCS(options: options);
}
[Test]
[Test, Platform("Win")] // uses __arglist; CoreCLR only supports the vararg calling convention on Windows
public async Task UndocumentedExpressions([ValueSource(nameof(noMonoOptions))] CompilerOptions options)
{
await RunCS(options: options);
@ -303,7 +308,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -303,7 +308,7 @@ namespace ICSharpCode.Decompiler.Tests
}
[Test]
public async Task BitNot([Values(false, true)] bool force32Bit)
public async Task BitNot([ValueSource(nameof(supportedForce32Bit))] bool force32Bit)
{
CompilerOptions compiler = CompilerOptions.UseDebug;
AssemblerOptions asm = AssemblerOptions.None;
@ -327,7 +332,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -327,7 +332,7 @@ namespace ICSharpCode.Decompiler.Tests
await RunIL("NonGenericConstrainedCallVirt.il", CompilerOptions.UseRoslynLatest);
}
[Test]
[Test, Platform("Win")] // 32BITREQUIRED needs the Windows 32-bit runtime
public async Task StackTests()
{
// IL contains .corflags = 32BITREQUIRED
@ -335,7 +340,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -335,7 +340,7 @@ namespace ICSharpCode.Decompiler.Tests
}
[Test]
public async Task StackTypes([Values(false, true)] bool force32Bit)
public async Task StackTypes([ValueSource(nameof(supportedForce32Bit))] bool force32Bit)
{
CompilerOptions compiler = CompilerOptions.UseRoslynLatest | CompilerOptions.UseDebug;
AssemblerOptions asm = AssemblerOptions.None;
@ -501,6 +506,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -501,6 +506,12 @@ namespace ICSharpCode.Decompiler.Tests
try
{
options |= CompilerOptions.UseTestRunner;
if (!OperatingSystem.IsWindows() && (options & CompilerOptions.UseRoslynMask) == 0)
{
// The default (legacy csc) recompilation of the decompiled output is only
// available on Windows; elsewhere use the current Roslyn instead.
options |= CompilerOptions.UseRoslynLatest;
}
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);

6
ICSharpCode.Decompiler.Tests/Helpers/RoslynToolset.cs

@ -147,14 +147,16 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -147,14 +147,16 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
installedCompilers.Add(SanitizeVersion(version), path);
}
// In the .NET ("netcore") build of the compiler toolset the executables live in a
// "bincore" subfolder of the tasks directory, as .dlls launched through the dotnet host.
public string GetCSharpCompiler(string version)
{
return GetCompiler("csc.exe", version);
return GetCompiler(OperatingSystem.IsWindows() ? "csc.exe" : "bincore/csc.dll", version);
}
public string GetVBCompiler(string version)
{
return GetCompiler("vbc.exe", version);
return GetCompiler(OperatingSystem.IsWindows() ? "vbc.exe" : "bincore/vbc.dll", version);
}
string GetCompiler(string compiler, string version)

27
ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs

@ -69,6 +69,12 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -69,6 +69,12 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
else
{
references = defaultReferences.Select(r => "-r:\"" + r + "\"");
if (!OperatingSystem.IsWindows())
{
// The dotnet-hosted compiler has no implicit mscorlib reference
// (see CompileCSharp); vbc resolves the bare name via -libpath.
references = references.Prepend("-r:\"mscorlib.dll\"");
}
libPath = RefAssembliesToolset.GetPath("legacy");
}
if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic))
@ -80,6 +86,24 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -80,6 +86,24 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
$"-langversion:{languageVersion} " +
$"/optimize{(flags.HasFlag(CompilerOptions.Optimize) ? "+ " : "- ")}";
if (!OperatingSystem.IsWindows())
{
// The dotnet-hosted vbc has no implicit SDK path for resolving the standard
// libraries and the VB runtime. The My templates are disabled because they
// need ApplicationServices types missing from the .NET build of
// Microsoft.VisualBasic (the .NET SDK sets _MYTYPE=Empty for the same
// reason); the decompile comparison strips the My namespace anyway.
otherOptions += $"-sdkpath:\"{libPath}\" ";
otherOptions += "-define:_MYTYPE=\\\"Empty\\\" ";
if ((flags & CompilerOptions.UseRoslynMask) != 0 && targetFramework != null)
{
// In the .NET reference packs Microsoft.VisualBasic.dll is a
// type-forwarding facade, and vbc does not follow forwards when binding
// its runtime helpers (e.g. ProjectData); point it at the implementation.
otherOptions += $"-vbruntime:\"{Path.Combine(libPath, "Microsoft.VisualBasic.Core.dll")}\" ";
}
}
// note: the /shared switch is undocumented. It allows us to use the VBCSCompiler.exe compiler
// server to speed up testing
if (roslynVersion != "legacy")
@ -118,8 +142,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -118,8 +142,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
otherOptions += " \"-d:" + string.Join(",", preprocessorSymbols.Select(kv => kv.Key + "=" + kv.Value)) + "\" ";
}
var command = Cli.Wrap(vbcPath)
.WithArguments($"{otherOptions}-libpath:\"{libPath}\" {string.Join(" ", references)} -out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}")
var command = WrapCompiler(vbcPath, $"{otherOptions}-libpath:\"{libPath}\" {string.Join(" ", references)} -out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}")
.WithValidation(CommandResultValidation.None);
//Console.WriteLine($"\"{command.TargetFilePath}\" {command.Arguments}");

102
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -145,29 +145,67 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -145,29 +145,67 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
{
await roslynToolset.Fetch("1.3.2", "Microsoft.Net.Compilers", "tools").ConfigureAwait(false);
await roslynToolset.Fetch("2.10.0", "Microsoft.Net.Compilers", "tools").ConfigureAwait(false);
await roslynToolset.Fetch("3.11.0").ConfigureAwait(false);
await roslynToolset.Fetch("4.14.0").ConfigureAwait(false);
await roslynToolset.Fetch(roslynLatestVersion).ConfigureAwait(false);
// On non-Windows hosts the net472 compiler binaries cannot be executed; use the
// .NET build of each toolset instead. Its tasks folder is named "netcoreapp3.1"
// up to Roslyn 3.x and "netcore" from Roslyn 4.x on.
await roslynToolset.Fetch("3.11.0", sourcePath: OperatingSystem.IsWindows() ? "tasks/net472" : "tasks/netcoreapp3.1").ConfigureAwait(false);
await roslynToolset.Fetch("4.14.0", sourcePath: OperatingSystem.IsWindows() ? "tasks/net472" : "tasks/netcore").ConfigureAwait(false);
await roslynToolset.Fetch(roslynLatestVersion, sourcePath: OperatingSystem.IsWindows() ? "tasks/net472" : "tasks/netcore").ConfigureAwait(false);
await vswhereToolset.Fetch().ConfigureAwait(false);
await RefAssembliesToolset.Fetch("5.0.0", sourcePath: "ref/net5.0").ConfigureAwait(false);
await RefAssembliesToolset.Fetch("9.0.0", sourcePath: "ref/net9.0").ConfigureAwait(false);
await RefAssembliesToolset.Fetch(CurrentNetCoreRefAsmVersion, sourcePath: $"ref/net{CurrentNetCoreVersion}").ConfigureAwait(false);
// The self-contained TestRunner builds only target Windows RIDs; the fixtures that
// consume them (UseTestRunner) are themselves gated to Windows at runtime.
if (OperatingSystem.IsWindows())
{
#if DEBUG
await BuildTestRunner("win-x86", "Debug").ConfigureAwait(false);
await BuildTestRunner("win-x64", "Debug").ConfigureAwait(false);
const string testRunnerConfig = "Debug";
#else
await BuildTestRunner("win-x86", "Release").ConfigureAwait(false);
await BuildTestRunner("win-x64", "Release").ConfigureAwait(false);
const string testRunnerConfig = "Release";
#endif
if (OperatingSystem.IsWindows())
{
await BuildTestRunner("win-x86", testRunnerConfig).ConfigureAwait(false);
await BuildTestRunner("win-x64", testRunnerConfig).ConfigureAwait(false);
}
else
{
// Self-contained build for the host platform. The RID must be one of the
// RuntimeIdentifiers pinned in ICSharpCode.Decompiler.TestRunner.csproj.
await BuildTestRunner(OperatingSystem.IsMacOS() ? "osx-arm64" : "linux-x64", testRunnerConfig).ConfigureAwait(false);
}
}
/// <summary>
/// Reduces a compiler-configuration matrix to the entries usable on the current platform.
/// On Windows every configuration is supported. On other platforms, configurations that
/// depend on Windows-only tools or runtimes are removed: the legacy (pre-Roslyn) csc/vbc,
/// Roslyn 1.x/2.x (their packages only ship .NET Framework binaries), mcs, and Force32Bit
/// (requires a 32-bit runtime). When <paramref name="executesCompiledOutput"/> is set
/// (correctness-style fixtures), configurations targeting .NET Framework 4.0 are removed
/// as well, because their output executables only run on Windows.
/// </summary>
public static CompilerOptions[] SupportedOnCurrentPlatform(CompilerOptions[] configurations, bool executesCompiledOutput = false)
{
if (OperatingSystem.IsWindows())
return configurations;
const CompilerOptions dotnetHostedCompilers = CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.UseRoslyn4_14_0 | CompilerOptions.UseRoslynLatest;
return configurations.Where(c => (c & dotnetHostedCompilers) != 0
&& !c.HasFlag(CompilerOptions.Force32Bit)
&& !(executesCompiledOutput && c.HasFlag(CompilerOptions.TargetNet40))).ToArray();
}
/// <summary>
/// Wraps an external compiler invocation. The .NET Framework builds of the Roslyn
/// compilers (csc.exe/vbc.exe) are directly executable; the .NET builds ship as a
/// .dll that must be launched through the 'dotnet' host.
/// </summary>
static Command WrapCompiler(string compilerPath, string arguments)
{
if (compilerPath.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
return Cli.Wrap("dotnet").WithArguments($"\"{compilerPath}\" {arguments}");
return Cli.Wrap(compilerPath).WithArguments(arguments);
}
static async Task BuildTestRunner(string runtime, string config)
{
await Cli.Wrap("dotnet")
@ -189,30 +227,32 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -189,30 +227,32 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
ilasmPath = ResolveToolPath("ilasm");
}
string outputFile = Path.Combine(Path.GetDirectoryName(sourceFileName), Path.GetFileNameWithoutExtension(sourceFileName));
// Options use the '-' prefix because on Unix the ilasm option parser treats
// '/option' as a file path; the Windows builds accept both prefixes.
string otherOptions = " ";
if (options.HasFlag(AssemblerOptions.Force32Bit))
{
outputFile += ".32";
otherOptions += "/32BitPreferred ";
otherOptions += "-32BitPreferred ";
}
if (options.HasFlag(AssemblerOptions.Library))
{
outputFile += ".dll";
otherOptions += "/dll ";
otherOptions += "-dll ";
}
else
{
outputFile += ".exe";
otherOptions += "/exe ";
otherOptions += "-exe ";
}
if (options.HasFlag(AssemblerOptions.UseDebug))
{
otherOptions += "/debug ";
otherOptions += "-debug ";
}
var command = Cli.Wrap(ilasmPath)
.WithArguments($"/quiet {otherOptions}/output=\"{outputFile}\" \"{sourceFileName}\"")
.WithArguments($"-quiet {otherOptions}-output=\"{outputFile}\" \"{sourceFileName}\"")
.WithValidation(CommandResultValidation.None);
var result = await command.ExecuteBufferedAsync().ConfigureAwait(false);
@ -262,8 +302,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -262,8 +302,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
string ildasmPath = ResolveToolPath("ildasm");
// '-' option prefix: see AssembleIL.
var command = Cli.Wrap(ildasmPath)
.WithArguments($"/utf8 /out=\"{outputFile}\" \"{sourceFileName}\"")
.WithArguments($"-utf8 -out=\"{outputFile}\" \"{sourceFileName}\"")
.WithValidation(CommandResultValidation.None);
var result = await command.ExecuteBufferedAsync().ConfigureAwait(false);
@ -594,6 +635,13 @@ namespace System.Runtime.CompilerServices @@ -594,6 +635,13 @@ namespace System.Runtime.CompilerServices
refAsmPath = RefAssembliesToolset.GetPath("legacy");
libPath = "\"" + refAsmPath + "\"";
references = defaultReferences;
if (!OperatingSystem.IsWindows())
{
// The .NET Framework csc.exe implicitly references the mscorlib of its
// runtime directory; the dotnet-hosted compiler has no implicit
// references, so the target framework's mscorlib must be passed explicitly.
references = references.Prepend("mscorlib.dll");
}
if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic))
{
references = references.Append("Microsoft.VisualBasic.dll");
@ -688,8 +736,7 @@ namespace System.Runtime.CompilerServices @@ -688,8 +736,7 @@ namespace System.Runtime.CompilerServices
otherOptions += " -nowarn:" + string.Join(",", noWarn);
}
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) + '"'))}")
var command = WrapCompiler(cscPath, $"{otherOptions} -lib:{libPath} {string.Join(" ", references)} -out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}")
.WithValidation(CommandResultValidation.None);
//Console.WriteLine($"\"{command.TargetFilePath}\" {command.Arguments}");
@ -881,9 +928,20 @@ namespace System.Runtime.CompilerServices @@ -881,9 +928,20 @@ namespace System.Runtime.CompilerServices
public static async Task<(int ExitCode, string Output, string Error)> RunWithTestRunner(string assemblyFileName, bool force32Bit)
{
if (!OperatingSystem.IsWindows())
Assert.Ignore("RunWithTestRunner uses a self-contained Windows test-runner build (win-x86/win-x64); not available on this platform.");
string testRunner = Path.Combine(testRunnerBasePath, force32Bit ? "win-x86" : "win-x64", "ICSharpCode.Decompiler.TestRunner.exe");
string runnerRid;
if (OperatingSystem.IsWindows())
{
runnerRid = force32Bit ? "win-x86" : "win-x64";
}
else
{
// Safety net: 32-bit runs need a 32-bit runtime, which only exists on Windows.
// Configurations using Force32Bit are not enumerated on non-Windows platforms.
if (force32Bit)
Assert.Ignore("Force32Bit requires a 32-bit .NET runtime, which is only available on Windows.");
runnerRid = OperatingSystem.IsMacOS() ? "osx-arm64" : "linux-x64";
}
string testRunner = Path.Combine(testRunnerBasePath, runnerRid, "ICSharpCode.Decompiler.TestRunner" + ExecutableExtension);
var command = Cli.Wrap(testRunner)
.WithArguments(assemblyFileName)
.WithValidation(CommandResultValidation.None);

2
ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs

@ -273,7 +273,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -273,7 +273,7 @@ namespace ICSharpCode.Decompiler.Tests
await Run();
}
[Test]
[Test, Platform("Win")] // UseLegacyAssembler requires the .NET Framework ilasm
public async Task Unsafe()
{
await Run(assemblerOptions: AssemblerOptions.Library | AssemblerOptions.UseLegacyAssembler);

7
ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs

@ -252,6 +252,13 @@ namespace ICSharpCode.Decompiler.Tests @@ -252,6 +252,13 @@ namespace ICSharpCode.Decompiler.Tests
{
file.Attribute("checksum").Remove();
file.Attribute("embeddedSourceLength")?.Remove();
var name = file.Attribute("name");
if (name != null)
{
// Generated document names use the platform's directory separator;
// the expected files were produced on Windows.
name.Value = name.Value.Replace('/', '\\');
}
file.ReplaceNodes(new XCData(file.Value.Replace("\uFEFF", "")));
}
document.Save(fileName, SaveOptions.None);

50
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -51,13 +51,13 @@ namespace ICSharpCode.Decompiler.Tests @@ -51,13 +51,13 @@ namespace ICSharpCode.Decompiler.Tests
}
}
static readonly CompilerOptions[] noRoslynOptions =
static readonly CompilerOptions[] noRoslynOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.None,
CompilerOptions.Optimize
};
});
static readonly CompilerOptions[] roslynOnlyWithNet40Options =
static readonly CompilerOptions[] roslynOnlyWithNet40Options = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
@ -77,9 +77,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -77,9 +77,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
static readonly CompilerOptions[] roslynOnlyOptions =
static readonly CompilerOptions[] roslynOnlyOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslyn1_3_2,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn1_3_2,
@ -91,9 +91,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -91,9 +91,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
static readonly CompilerOptions[] roslyn2OrNewerWithNet40Options =
static readonly CompilerOptions[] roslyn2OrNewerWithNet40Options = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
@ -111,9 +111,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -111,9 +111,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
static readonly CompilerOptions[] roslyn2OrNewerOptions =
static readonly CompilerOptions[] roslyn2OrNewerOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslyn2_10_0,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0,
@ -123,9 +123,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -123,9 +123,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
static readonly CompilerOptions[] roslyn3OrNewerWithNet40Options =
static readonly CompilerOptions[] roslyn3OrNewerWithNet40Options = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.TargetNet40,
@ -139,9 +139,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -139,9 +139,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
static readonly CompilerOptions[] roslyn3OrNewerOptions =
static readonly CompilerOptions[] roslyn3OrNewerOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslyn3_11_0,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn3_11_0,
@ -149,9 +149,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -149,9 +149,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
static readonly CompilerOptions[] roslyn4OrNewerWithNet40Options =
static readonly CompilerOptions[] roslyn4OrNewerWithNet40Options = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslyn4_14_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0 | CompilerOptions.TargetNet40,
@ -161,23 +161,23 @@ namespace ICSharpCode.Decompiler.Tests @@ -161,23 +161,23 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
static readonly CompilerOptions[] roslyn4OrNewerOptions =
static readonly CompilerOptions[] roslyn4OrNewerOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
static readonly CompilerOptions[] roslyn5OrNewerOptions =
static readonly CompilerOptions[] roslyn5OrNewerOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
static readonly CompilerOptions[] defaultOptions =
static readonly CompilerOptions[] defaultOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.None,
CompilerOptions.Optimize,
@ -199,9 +199,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -199,9 +199,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
static readonly CompilerOptions[] defaultOptionsWithMcs =
static readonly CompilerOptions[] defaultOptionsWithMcs = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.None,
CompilerOptions.Optimize,
@ -227,9 +227,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -227,9 +227,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseMcs2_6_4,
CompilerOptions.UseMcs5_23,
CompilerOptions.Optimize | CompilerOptions.UseMcs5_23
};
});
[Test]
[Test, Platform("Win")] // uses the legacy (pre-Roslyn) csc, which only exists on Windows
public async Task HelloWorld()
{
await RunForLibrary();

4
ICSharpCode.Decompiler.Tests/TestCases/Correctness/Async.cs

@ -291,7 +291,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -291,7 +291,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
{
Console.WriteLine("d");
int i = 0;
if (Console.CapsLock)
// An opaque condition the compiler cannot evaluate; Console.IsInputRedirected
// (unlike Console.CapsLock) is supported on all platforms.
if (Console.IsInputRedirected)
{
i++;
await Task.Delay(i);

12
ICSharpCode.Decompiler.Tests/UglyTestRunner.cs

@ -51,13 +51,13 @@ namespace ICSharpCode.Decompiler.Tests @@ -51,13 +51,13 @@ namespace ICSharpCode.Decompiler.Tests
}
}
static readonly CompilerOptions[] noRoslynOptions =
static readonly CompilerOptions[] noRoslynOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.None,
CompilerOptions.Optimize
};
});
static readonly CompilerOptions[] roslynOnlyOptions =
static readonly CompilerOptions[] roslynOnlyOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslyn4_14_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0 | CompilerOptions.TargetNet40,
@ -67,9 +67,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -67,9 +67,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
static readonly CompilerOptions[] defaultOptions =
static readonly CompilerOptions[] defaultOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.None,
CompilerOptions.Optimize,
@ -77,7 +77,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -77,7 +77,7 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
[Test]
public async Task NoArrayInitializers([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions)

13
ICSharpCode.Decompiler.Tests/Util/FileUtilityTests.cs

@ -82,7 +82,9 @@ namespace ICSharpCode.Decompiler.Tests.Util @@ -82,7 +82,9 @@ namespace ICSharpCode.Decompiler.Tests.Util
}
#endregion
[Test]
// IsBaseDirectory/GetRelativePath compare path segments with the platform's
// case sensitivity and separator; these expectations encode the Windows behavior.
[Test, Platform("Win")]
public void TestIsBaseDirectory()
{
Assert.That(FileUtility.IsBaseDirectory(@"C:\a", @"C:\A\b\hello"));
@ -106,7 +108,7 @@ namespace ICSharpCode.Decompiler.Tests.Util @@ -106,7 +108,7 @@ namespace ICSharpCode.Decompiler.Tests.Util
Assert.That(!FileUtility.IsBaseDirectory(@"C:\", @"D:\a\b\hello"));
}
[Test]
[Test, Platform("Win")] // see TestIsBaseDirectory
public void TestIsBaseDirectoryRelative()
{
Assert.That(FileUtility.IsBaseDirectory(@".", @"a\b"));
@ -131,7 +133,7 @@ namespace ICSharpCode.Decompiler.Tests.Util @@ -131,7 +133,7 @@ namespace ICSharpCode.Decompiler.Tests.Util
Assert.That(!FileUtility.IsBaseDirectory(@"\\server2\share", @"\\server\share\dir\subdir"));
}
[Test]
[Test, Platform("Win")] // see TestIsBaseDirectory
public void TestGetRelativePath()
{
Assert.That(FileUtility.GetRelativePath(@"C:\hello\.\..\a", @"C:\.\a\blub"), Is.EqualTo(@"blub"));
@ -149,7 +151,7 @@ namespace ICSharpCode.Decompiler.Tests.Util @@ -149,7 +151,7 @@ namespace ICSharpCode.Decompiler.Tests.Util
Assert.That(FileUtility.GetRelativePath(@"C:\.\.\.\.\heLLo\A\..", @"C:\.\blub\.\..\.\a\.\blub"), Is.EqualTo(@"..\a\blub"));
}
[Test]
[Test, Platform("Win")] // see TestIsBaseDirectory
public void RelativeGetRelativePath()
{
// Relative path
@ -166,8 +168,9 @@ namespace ICSharpCode.Decompiler.Tests.Util @@ -166,8 +168,9 @@ namespace ICSharpCode.Decompiler.Tests.Util
[Test]
public void GetRelativePath_Unix()
{
// The result is joined with the platform's directory separator.
Assert.That(FileUtility.GetRelativePath("/", "/a"), Is.EqualTo(@"a"));
Assert.That(FileUtility.GetRelativePath("/", "/a/b"), Is.EqualTo(@"a\b"));
Assert.That(FileUtility.GetRelativePath("/", "/a/b"), Is.EqualTo($"a{System.IO.Path.DirectorySeparatorChar}b"));
Assert.That(FileUtility.GetRelativePath("/a", "/a/b"), Is.EqualTo(@"b"));
}

8
ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs

@ -51,7 +51,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -51,7 +51,7 @@ namespace ICSharpCode.Decompiler.Tests
}
}
static readonly CompilerOptions[] defaultOptions =
static readonly CompilerOptions[] defaultOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.None,
CompilerOptions.Optimize,
@ -75,9 +75,9 @@ namespace ICSharpCode.Decompiler.Tests @@ -75,9 +75,9 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
static readonly CompilerOptions[] roslynOnlyOptions =
static readonly CompilerOptions[] roslynOnlyOptions = Tester.SupportedOnCurrentPlatform(new[]
{
CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
@ -99,7 +99,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -99,7 +99,7 @@ namespace ICSharpCode.Decompiler.Tests
CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0,
CompilerOptions.UseRoslynLatest,
CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest,
};
});
[Test]
public async Task Async([ValueSource(nameof(defaultOptions))] CompilerOptions options)

Loading…
Cancel
Save