diff --git a/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs b/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs index 5c8366b70..b091121d3 100644 --- a/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs @@ -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 } } - static readonly CompilerOptions[] noMonoOptions = + static readonly CompilerOptions[] noMonoOptions = Tester.SupportedOnCurrentPlatform(new[] { CompilerOptions.None, CompilerOptions.Optimize, @@ -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 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 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 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 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 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 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 } [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 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 } [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 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); diff --git a/ICSharpCode.Decompiler.Tests/Helpers/RoslynToolset.cs b/ICSharpCode.Decompiler.Tests/Helpers/RoslynToolset.cs index 21abefe72..3a75f331a 100644 --- a/ICSharpCode.Decompiler.Tests/Helpers/RoslynToolset.cs +++ b/ICSharpCode.Decompiler.Tests/Helpers/RoslynToolset.cs @@ -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) diff --git a/ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs b/ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs index 73801bdfc..0536e43d3 100644 --- a/ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs +++ b/ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs @@ -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 $"-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 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}"); diff --git a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs index 86849a323..420b4a06e 100644 --- a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs +++ b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs @@ -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); } } + /// + /// 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 is set + /// (correctness-style fixtures), configurations targeting .NET Framework 4.0 are removed + /// as well, because their output executables only run on Windows. + /// + 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(); + } + + /// + /// 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. + /// + 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 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 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 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 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 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); diff --git a/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs index 1d6c29e16..6ec521e54 100644 --- a/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs @@ -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); diff --git a/ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs b/ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs index b22dcad56..e2661e557 100644 --- a/ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/PdbGenerationTestRunner.cs @@ -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); diff --git a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs index 69300d285..fc4a4f2b4 100644 --- a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs @@ -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 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 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 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 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 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 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 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 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 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(); diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Async.cs b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Async.cs index 619c741c0..c78387815 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Async.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/Async.cs @@ -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); diff --git a/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs b/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs index ccea015be..5cff88e43 100644 --- a/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs @@ -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 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 CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest | CompilerOptions.TargetNet40, CompilerOptions.UseRoslynLatest, CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest, - }; + }); [Test] public async Task NoArrayInitializers([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) diff --git a/ICSharpCode.Decompiler.Tests/Util/FileUtilityTests.cs b/ICSharpCode.Decompiler.Tests/Util/FileUtilityTests.cs index abd9fbea0..982f16b55 100644 --- a/ICSharpCode.Decompiler.Tests/Util/FileUtilityTests.cs +++ b/ICSharpCode.Decompiler.Tests/Util/FileUtilityTests.cs @@ -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 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 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 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 [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")); } diff --git a/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs index fbd94a6bf..08c556392 100644 --- a/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/VBPrettyTestRunner.cs @@ -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 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 CompilerOptions.Optimize | CompilerOptions.UseRoslyn4_14_0, CompilerOptions.UseRoslynLatest, CompilerOptions.Optimize | CompilerOptions.UseRoslynLatest, - }; + }); [Test] public async Task Async([ValueSource(nameof(defaultOptions))] CompilerOptions options)