diff --git a/NUnitConsole.sln b/NUnitConsole.sln index f978a232f..760d8c675 100644 --- a/NUnitConsole.sln +++ b/NUnitConsole.sln @@ -110,6 +110,7 @@ EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cake", "cake", "{9BCA00E2-D072-424B-A6DF-5BECF719C1FB}" ProjectSection(SolutionItems) = preProject cake\constants.cake = cake\constants.cake + cake\dotnet.cake = cake\dotnet.cake cake\header-check.cake = cake\header-check.cake cake\package-checks.cake = cake\package-checks.cake cake\package-definitions.cake = cake\package-definitions.cake @@ -122,6 +123,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "cake", "cake", "{9BCA00E2-D EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "msi", "msi", "{0C0D20CE-70CD-4CEF-BE9B-AEB8A2DE9C8A}" ProjectSection(SolutionItems) = preProject + msi\nunit-install.sln = msi\nunit-install.sln msi\resources\nunit.bundle.addins = msi\resources\nunit.bundle.addins EndProjectSection EndProject @@ -151,6 +153,21 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "config", "config", "{C5B712 .config\dotnet-tools.json = .config\dotnet-tools.json EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nunit", "nunit", "{93E5CAF4-D5DB-4915-AF0F-908A6043E462}" + ProjectSection(SolutionItems) = preProject + msi\nunit\addin-files.wxi = msi\nunit\addin-files.wxi + msi\nunit\banner.bmp = msi\nunit\banner.bmp + msi\nunit\console-files.wxi = msi\nunit\console-files.wxi + msi\nunit\dialog.bmp = msi\nunit\dialog.bmp + msi\nunit\engine-files.wxi = msi\nunit\engine-files.wxi + msi\nunit\nunit.wixproj = msi\nunit\nunit.wixproj + msi\nunit\nunit.wxs = msi\nunit\nunit.wxs + msi\nunit\runner-directories.wxi = msi\nunit\runner-directories.wxi + msi\nunit\runner-features.wxi = msi\nunit\runner-features.wxi + msi\nunit\utility-files.wxi = msi\nunit\utility-files.wxi + msi\nunit\variables.wxi = msi\nunit\variables.wxi + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -235,6 +252,7 @@ Global {08F8160E-E691-4F07-9F57-EA31B9736429} = {25DA12FE-6209-4524-9A37-8E51F815E198} {50371E48-BEC3-4D53-BD37-F3A6149CFD0D} = {25DA12FE-6209-4524-9A37-8E51F815E198} {C5B7120C-190B-4C38-95CB-83F12799598D} = {49D441DF-39FD-4F4D-AECA-86CF8EFE23AF} + {93E5CAF4-D5DB-4915-AF0F-908A6043E462} = {0C0D20CE-70CD-4CEF-BE9B-AEB8A2DE9C8A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D8E4FC26-5422-4C51-8BBC-D1AC0A578711} diff --git a/build.cake b/build.cake index 2ec9efdc4..814abff27 100644 --- a/build.cake +++ b/build.cake @@ -3,6 +3,7 @@ static string Configuration; Configuration = GetArgument("configuration|c", "Rel static bool NoPush; NoPush = HasArgument("nopush"); #load cake/constants.cake +#load cake/dotnet.cake #load cake/header-check.cake #load cake/package-checks.cake #load cake/test-results.cake diff --git a/cake/dotnet.cake b/cake/dotnet.cake new file mode 100644 index 000000000..0fb801824 --- /dev/null +++ b/cake/dotnet.cake @@ -0,0 +1,88 @@ +public class DotnetInfo +{ + // Experimenting with finding dotnet installs for X64 vs x86 + // This code will end up moved into the engine as well. + + private ICakeContext _context; + private bool _onWindows; + + public DotnetInfo(ICakeContext context) + { + _context = context; + _onWindows = context.IsRunningOnWindows(); + + InstallPath = GetDotnetInstallDirectory(false); + X86InstallPath = GetDotnetInstallDirectory(true); + } + + // NOTES: + // * We don't need an IsInstalled property because our scripts all run under dotnet. + + public bool IsX86Installed => System.IO.Directory.Exists(X86InstallPath) && System.IO.File.Exists(X86Executable); + + public string InstallPath { get; } + public string Executable => InstallPath + "dotnet.exe"; + public List Runtimes { get; } + + public string X86InstallPath { get; } + public string X86Executable => X86InstallPath + "dotnet.exe"; + public List X86Runtimes { get; } + + public void Display() + { + _context.Information($"Install Path: {InstallPath}"); + _context.Information($"Executable: {Executable}"); + _context.Information("Runtimes:"); + foreach (string dir in System.IO.Directory.GetDirectories(System.IO.Path.Combine(InstallPath, "shared"))) + { + string runtime = System.IO.Path.GetFileName(dir); + foreach (string dir2 in System.IO.Directory.GetDirectories(dir)) + { + string version = System.IO.Path.GetFileName(dir2); + _context.Information($" {runtime} {version}"); + } + } + + if (IsX86Installed) + { + _context.Information($"\nX86 Install Path: {X86InstallPath}"); + _context.Information($"X86 Executable: {X86Executable}"); + _context.Information("Runtimes:"); + foreach (var dir in System.IO.Directory.GetDirectories(System.IO.Path.Combine(X86InstallPath, "shared"))) + { + string runtime = System.IO.Path.GetFileName(dir); + foreach (string dir2 in System.IO.Directory.GetDirectories(dir)) + { + string version = System.IO.Path.GetFileName(dir2); + _context.Information($" {runtime} {version}"); + } + } + } + else + _context.Information("\nDotnet X86 is not installed"); + } + + private string GetDotnetInstallDirectory(bool forX86 = false) + { + if (_onWindows) + { + if (forX86) + { + Microsoft.Win32.RegistryKey key = + Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\dotnet\SetUp\InstalledVersions\x86\"); + return (string)key?.GetValue("InstallLocation"); + } + else + { + Microsoft.Win32.RegistryKey key = + Microsoft.Win32.Registry.LocalMachine.OpenSubKey(@"SOFTWARE\dotnet\SetUp\InstalledVersions\x64\sharedHost\"); + return (string)key?.GetValue("Path"); + } + } + else // Assuming linux for now + return "/usr/shared/dotnet/"; + } +} + +// Use this task to verify that the script understands the dotnet environment +Task("DotnetInfo").Does(() => { new DotnetInfo(Context).Display(); }); diff --git a/cake/package-definitions.cake b/cake/package-definitions.cake index 04f431216..2d8b40008 100644 --- a/cake/package-definitions.cake +++ b/cake/package-definitions.cake @@ -28,6 +28,8 @@ public void InitializePackageDefinitions(ICakeContext context) NetCore31Test, Net50Test, Net60Test, + Net70Test, + Net80Test, Net50PlusNet60Test, Net40PlusNet60Test }; @@ -42,6 +44,24 @@ public void InitializePackageDefinitions(ICakeContext context) Net80Test, }; + // TODO: Remove the limitation to Windows + if (IsRunningOnWindows() && dotnetX86Available) + { + StandardRunnerTests.Add(Net60X86Test); + // TODO: Make these tests run on AppVeyor + if (!context.BuildSystem().IsRunningOnAppVeyor) + { + StandardRunnerTests.Add(NetCore31X86Test); + StandardRunnerTests.Add(Net50X86Test); + StandardRunnerTests.Add(Net70X86Test); + StandardRunnerTests.Add(Net80X86Test); + } + // Currently, NetCoreRunner runs tests in process. As a result, + // X86 tests will work in our environment, although uses may run + // it as a tool using the X86 architecture. + } + + AllPackages.AddRange(new PackageDefinition[] { NUnitConsoleNuGetPackage = new NuGetPackage( diff --git a/cake/package-tests.cake b/cake/package-tests.cake index 26eee6af3..2b5413ab2 100644 --- a/cake/package-tests.cake +++ b/cake/package-tests.cake @@ -48,30 +48,60 @@ static PackageTest Net80Test = new PackageTest( "net8.0/mock-assembly.dll", MockAssemblyExpectedResult(1)); +static PackageTest Net80X86Test = new PackageTest( + "Net80X86Test", + "Run mock-assembly-x86.dll under .NET 8.0", + "net8.0/mock-assembly-x86.dll", + MockAssemblyExpectedResult(1)); + static PackageTest Net70Test = new PackageTest( "Net70Test", "Run mock-assembly.dll under .NET 7.0", "net7.0/mock-assembly.dll", MockAssemblyExpectedResult(1)); +static PackageTest Net70X86Test = new PackageTest( + "Net70X86Test", + "Run mock-assembly-x86.dll under .NET 7.0", + "net7.0/mock-assembly-x86.dll", + MockAssemblyExpectedResult(1)); + static PackageTest Net60Test = new PackageTest( "Net60Test", "Run mock-assembly.dll under .NET 6.0", "net6.0/mock-assembly.dll", MockAssemblyExpectedResult(1)); +static PackageTest Net60X86Test = new PackageTest( + "Net60X86Test", + "Run mock-assembly-x86.dll under .NET 6.0", + "net6.0/mock-assembly-x86.dll --trace:Debug", + MockAssemblyExpectedResult(1)); + static PackageTest Net50Test = new PackageTest( "Net50Test", "Run mock-assembly.dll under .NET 5.0", "net5.0/mock-assembly.dll", MockAssemblyExpectedResult(1)); +static PackageTest Net50X86Test = new PackageTest( + "Net50X86Test", + "Run mock-assembly-x86.dll under .NET 5.0", + "net5.0/mock-assembly-x86.dll", + MockAssemblyExpectedResult(1)); + static PackageTest NetCore31Test = new PackageTest( "NetCore31Test", "Run mock-assembly.dll under .NET Core 3.1", "netcoreapp3.1/mock-assembly.dll", MockAssemblyExpectedResult(1)); +static PackageTest NetCore31X86Test = new PackageTest( + "NetCore31X86Test", + "Run mock-assembly-x86.dll under .NET Core 3.1", + "netcoreapp3.1/mock-assembly-x86.dll", + MockAssemblyExpectedResult(1)); + static PackageTest Net50PlusNet60Test = new PackageTest( "Net50PlusNet60Test", "Run mock-assembly under .NET 5.0 and 6.0 together", diff --git a/msi/nunit/engine-files.wxi b/msi/nunit/engine-files.wxi index 6422781b5..2b914f015 100644 --- a/msi/nunit/engine-files.wxi +++ b/msi/nunit/engine-files.wxi @@ -49,6 +49,8 @@ + + @@ -175,24 +177,94 @@ + Source="$(var.InstallImage)bin/agents/net6.0/nunit.engine.api.dll" /> + Source="$(var.InstallImage)bin/agents/net6.0/nunit.engine.api.xml" /> + Source="$(var.InstallImage)bin/agents/net6.0/nunit.engine.core.dll" /> + Source="$(var.InstallImage)bin/agents/net6.0/testcentric.engine.metadata.dll" /> + Source="$(var.InstallImage)bin/agents/net6.0/Microsoft.Extensions.DependencyModel.dll" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/msi/nunit/runner-directories.wxi b/msi/nunit/runner-directories.wxi index 1f4eab58e..906654d74 100644 --- a/msi/nunit/runner-directories.wxi +++ b/msi/nunit/runner-directories.wxi @@ -16,6 +16,8 @@ + + diff --git a/src/NUnitEngine/mock-assembly-x86/mock-assembly-x86.csproj b/src/NUnitEngine/mock-assembly-x86/mock-assembly-x86.csproj index 5abc42dff..34e36d39c 100644 --- a/src/NUnitEngine/mock-assembly-x86/mock-assembly-x86.csproj +++ b/src/NUnitEngine/mock-assembly-x86/mock-assembly-x86.csproj @@ -2,7 +2,7 @@ NUnit.Tests - net35;net40;netcoreapp2.1;netcoreapp3.1 + net35;net40;netcoreapp2.1;netcoreapp3.1;net5.0;net6.0;net7.0;net8.0 true ..\..\nunit.snk x86 diff --git a/src/NUnitEngine/nunit.engine.api/IRuntimeFrameworkService.cs b/src/NUnitEngine/nunit.engine.api/IRuntimeFrameworkService.cs index 0e48ebe6d..9f7021092 100644 --- a/src/NUnitEngine/nunit.engine.api/IRuntimeFrameworkService.cs +++ b/src/NUnitEngine/nunit.engine.api/IRuntimeFrameworkService.cs @@ -16,8 +16,9 @@ public interface IRuntimeFrameworkService /// the string passed as an argument is available. /// /// A string representing a framework, like 'net-4.0' + /// A flag indicating whether the X86 architecture is needed. Defaults to false. /// True if the framework is available, false if unavailable or nonexistent - bool IsAvailable(string framework); + bool IsAvailable(string framework, bool x86); /// /// Selects a target runtime framework for a TestPackage based on diff --git a/src/NUnitEngine/nunit.engine.core/Internal/TestAssemblyResolver.cs b/src/NUnitEngine/nunit.engine.core/Internal/TestAssemblyResolver.cs index c3cfc570a..fe9d53336 100644 --- a/src/NUnitEngine/nunit.engine.core/Internal/TestAssemblyResolver.cs +++ b/src/NUnitEngine/nunit.engine.core/Internal/TestAssemblyResolver.cs @@ -23,13 +23,17 @@ internal sealed class TestAssemblyResolver : IDisposable private readonly DependencyContext _dependencyContext; private readonly AssemblyLoadContext _loadContext; - private static readonly string INSTALL_DIR = GetDotNetInstallDirectory(); - private static readonly string WINDOWS_DESKTOP_DIR = Path.Combine(INSTALL_DIR, "shared", "Microsoft.WindowsDesktop.App"); - private static readonly string ASP_NET_CORE_DIR = Path.Combine(INSTALL_DIR, "shared", "Microsoft.AspNetCore.App"); + private static readonly string INSTALL_DIR; + private static readonly string WINDOWS_DESKTOP_DIR; + private static readonly string ASP_NET_CORE_DIR; private static readonly List AdditionalFrameworkDirectories; static TestAssemblyResolver() { + INSTALL_DIR = GetDotNetInstallDirectory(); + WINDOWS_DESKTOP_DIR = Path.Combine(INSTALL_DIR, "shared", "Microsoft.WindowsDesktop.App"); + ASP_NET_CORE_DIR = Path.Combine(INSTALL_DIR, "shared", "Microsoft.AspNetCore.App"); + AdditionalFrameworkDirectories = new List(); if (Directory.Exists(WINDOWS_DESKTOP_DIR)) AdditionalFrameworkDirectories.Add(WINDOWS_DESKTOP_DIR); @@ -169,10 +173,16 @@ private static string GetDotNetInstallDirectory() if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { // Running on Windows so use registry - RegistryKey key = Environment.Is64BitProcess - ? Registry.LocalMachine.OpenSubKey(@"Software\dotnet\SetUp\InstalledVersions\x64\sharedHost\") - : Registry.LocalMachine.OpenSubKey(@"Software\dotnet\SetUp\InstalledVersions\x86\sharedHost\"); - return (string)key?.GetValue("Path"); + if (Environment.Is64BitProcess) + { + RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\dotnet\SetUp\InstalledVersions\x64\sharedHost\"); + return (string)key?.GetValue("Path"); + } + else + { + RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\dotnet\SetUp\InstalledVersions\x86\"); + return (string)key?.GetValue("InstallLocation"); + } } else return "/usr/shared/dotnet/"; diff --git a/src/NUnitEngine/nunit.engine.tests/Services/Fakes/FakeRuntimeService.cs b/src/NUnitEngine/nunit.engine.tests/Services/Fakes/FakeRuntimeService.cs index 9b181e991..9d5558e7f 100644 --- a/src/NUnitEngine/nunit.engine.tests/Services/Fakes/FakeRuntimeService.cs +++ b/src/NUnitEngine/nunit.engine.tests/Services/Fakes/FakeRuntimeService.cs @@ -4,7 +4,7 @@ namespace NUnit.Engine.Services.Tests.Fakes { public class FakeRuntimeService : FakeService, IRuntimeFrameworkService { - bool IRuntimeFrameworkService.IsAvailable(string framework) + bool IRuntimeFrameworkService.IsAvailable(string framework, bool x86) { return true; } diff --git a/src/NUnitEngine/nunit.engine/Runners/MasterTestRunner.cs b/src/NUnitEngine/nunit.engine/Runners/MasterTestRunner.cs index 41734a93d..06e3c989d 100644 --- a/src/NUnitEngine/nunit.engine/Runners/MasterTestRunner.cs +++ b/src/NUnitEngine/nunit.engine/Runners/MasterTestRunner.cs @@ -376,8 +376,10 @@ private void ValidatePackageSettings() { // Check requested framework is actually available var runtimeService = _services.GetService(); - if (!runtimeService.IsAvailable(frameworkSetting)) - throw new NUnitEngineException(string.Format("The requested framework {0} is unknown or not available.", frameworkSetting)); + if (!runtimeService.IsAvailable(frameworkSetting, runAsX86)) + throw new NUnitEngineException(runAsX86 + ? $"The requested framework {frameworkSetting} is unknown or not available for X86." + : $"The requested framework {frameworkSetting} is unknown or not available."); // If running in process, check requested framework is compatible if (runningInProcess) diff --git a/src/NUnitEngine/nunit.engine/Services/RuntimeFrameworkService.cs b/src/NUnitEngine/nunit.engine/Services/RuntimeFrameworkService.cs index dfe8d82b5..673b76420 100644 --- a/src/NUnitEngine/nunit.engine/Services/RuntimeFrameworkService.cs +++ b/src/NUnitEngine/nunit.engine/Services/RuntimeFrameworkService.cs @@ -19,26 +19,34 @@ public class RuntimeFrameworkService : Service, IRuntimeFrameworkService, IAvail static readonly Logger log = InternalTrace.GetLogger(typeof(RuntimeFrameworkService)); private List _availableRuntimes = new List(); + private List _availableX86Runtimes = new List(); /// /// Gets a list of available runtimes. /// public IList AvailableRuntimes => _availableRuntimes.ToArray(); + /// + /// Gets a list of available runtimes. + /// + public IList AvailableX86Runtimes => _availableX86Runtimes.ToArray(); + /// /// Returns true if the runtime framework represented by /// the string passed as an argument is available. /// /// A string representing a framework, like 'net-4.0' + /// A flag indicating whether the X86 architecture is needed. Defaults to false. /// True if the framework is available, false if unavailable or nonexistent - public bool IsAvailable(string name) + public bool IsAvailable(string name, bool x86) { Guard.ArgumentNotNullOrEmpty(name, nameof(name)); if (!RuntimeFramework.TryParse(name, out RuntimeFramework requestedFramework)) throw new NUnitEngineException("Invalid or unknown framework requested: " + name); - foreach (var framework in _availableRuntimes) + var runtimes = x86 ? _availableX86Runtimes : _availableRuntimes; + foreach (var framework in runtimes) if (FrameworksMatch(requestedFramework, framework)) return true; @@ -107,6 +115,7 @@ private RuntimeFramework SelectRuntimeFrameworkInner(TestPackage package) log.Debug("Current framework is " + currentFramework); string frameworkSetting = package.GetSetting(EnginePackageSettings.RequestedRuntimeFramework, ""); + bool runAsX86 = package.GetSetting(EnginePackageSettings.RunAsX86, false); if (frameworkSetting.Length > 0) { @@ -115,7 +124,7 @@ private RuntimeFramework SelectRuntimeFrameworkInner(TestPackage package) log.Debug($"Requested framework for {package.Name} is {requestedFramework}"); - if (!IsAvailable(frameworkSetting)) + if (!IsAvailable(frameworkSetting, runAsX86)) throw new NUnitEngineException("Requested framework is not available: " + frameworkSetting); package.Settings[EnginePackageSettings.TargetRuntimeFramework] = frameworkSetting; @@ -154,12 +163,12 @@ private RuntimeFramework SelectRuntimeFrameworkInner(TestPackage package) targetVersion = frameworkName.Version; } - //if (!new RuntimeFramework(targetRuntime, targetVersion).IsAvailable) - //{ - // log.Debug("Preferred version {0} is not installed or this NUnit installation does not support it", targetVersion); - // if (targetVersion < currentFramework.FrameworkVersion) - // targetVersion = currentFramework.FrameworkVersion; - //} + if (!IsAvailable(new RuntimeFramework(targetRuntime, targetVersion).Id, runAsX86)) + { + log.Debug("Preferred version {0} is not installed or this NUnit installation does not support it", targetVersion); + if (targetVersion < currentFramework.FrameworkVersion) + targetVersion = currentFramework.FrameworkVersion; + } RuntimeFramework targetFramework = new RuntimeFramework(targetRuntime, targetVersion); package.Settings[EnginePackageSettings.TargetRuntimeFramework] = targetFramework.ToString(); @@ -206,16 +215,21 @@ public RuntimeFramework GetBestAvailableFramework(RuntimeFramework target) private void FindAvailableRuntimes() { _availableRuntimes = new List(); + _availableX86Runtimes = new List(); if (Environment.OSVersion.Platform == PlatformID.Win32NT) { var netFxRuntimes = NetFxRuntimeLocator.FindRuntimes(); _availableRuntimes.AddRange(netFxRuntimes); + _availableX86Runtimes.AddRange(netFxRuntimes); } - _availableRuntimes.AddRange(MonoRuntimeLocator.FindRuntimes()); + var monoRuntimes = MonoRuntimeLocator.FindRuntimes(); + _availableRuntimes.AddRange(monoRuntimes); + _availableX86Runtimes.AddRange(monoRuntimes); - _availableRuntimes.AddRange(NetCoreRuntimeLocator.FindRuntimes()); + _availableRuntimes.AddRange(NetCoreRuntimeLocator.FindRuntimes(x86: false)); + _availableX86Runtimes.AddRange(NetCoreRuntimeLocator.FindRuntimes(x86: true)); } /// diff --git a/src/NUnitEngine/nunit.engine/Services/RuntimeLocators/NetCoreRuntimeLocator.cs b/src/NUnitEngine/nunit.engine/Services/RuntimeLocators/NetCoreRuntimeLocator.cs index 537a14402..333e5db7b 100644 --- a/src/NUnitEngine/nunit.engine/Services/RuntimeLocators/NetCoreRuntimeLocator.cs +++ b/src/NUnitEngine/nunit.engine/Services/RuntimeLocators/NetCoreRuntimeLocator.cs @@ -11,11 +11,11 @@ namespace NUnit.Engine.Services.RuntimeLocators { public static class NetCoreRuntimeLocator { - public static IEnumerable FindRuntimes() + public static IEnumerable FindRuntimes(bool x86) { List alreadyFound = new List(); - foreach (string dirName in GetRuntimeDirectories()) + foreach (string dirName in GetRuntimeDirectories(x86)) { Version newVersion; if (TryGetVersionFromString(dirName, out newVersion) && !alreadyFound.Contains(newVersion)) @@ -36,9 +36,9 @@ public static IEnumerable FindRuntimes() } } - private static IEnumerable GetRuntimeDirectories() + private static IEnumerable GetRuntimeDirectories(bool x86) { - string installDir = GetDotNetInstallDirectory(); + string installDir = GetDotNetInstallDirectory(x86); if (installDir != null && Directory.Exists(installDir) && File.Exists(Path.Combine(installDir, "dotnet.exe"))) @@ -111,13 +111,22 @@ private static bool TryGetVersionFromString(string text, out Version newVersion) } } - internal static string GetDotNetInstallDirectory() + internal static string GetDotNetInstallDirectory(bool x86) { if (Path.DirectorySeparatorChar == '\\') { - RegistryKey key = - Registry.LocalMachine.OpenSubKey(@"Software\dotnet\SetUp\InstalledVersions\x64\sharedHost\"); - return (string)key?.GetValue("Path"); + if (x86) + { + RegistryKey key = + Registry.LocalMachine.OpenSubKey(@"SOFTWARE\WOW6432Node\dotnet\SetUp\InstalledVersions\x86\"); + return (string)key?.GetValue("InstallLocation"); + } + else + { + RegistryKey key = + Registry.LocalMachine.OpenSubKey(@"SOFTWARE\dotnet\SetUp\InstalledVersions\x64\sharedHost\"); + return (string)key?.GetValue("Path"); + } } else return "/usr/shared/dotnet/"; diff --git a/src/NUnitEngine/nunit.engine/Services/TestAgency.cs b/src/NUnitEngine/nunit.engine/Services/TestAgency.cs index 30690d025..0cfe65ede 100644 --- a/src/NUnitEngine/nunit.engine/Services/TestAgency.cs +++ b/src/NUnitEngine/nunit.engine/Services/TestAgency.cs @@ -55,15 +55,18 @@ public ITestAgent GetAgent(TestPackage package) // Target Runtime must be specified by this point string runtimeSetting = package.GetSetting(EnginePackageSettings.TargetRuntimeFramework, ""); Guard.OperationValid(runtimeSetting.Length > 0, "LaunchAgentProcess called with no runtime specified"); + bool runAsX86 = package.GetSetting(EnginePackageSettings.RunAsX86, false); // If target runtime is not available, something went wrong earlier. // We list all available frameworks to use in debugging. var targetRuntime = RuntimeFramework.Parse(runtimeSetting); - if (!_runtimeService.IsAvailable(targetRuntime.Id)) + if (!_runtimeService.IsAvailable(targetRuntime.Id, runAsX86)) { - string msg = $"The {targetRuntime} framework is not available.\r\nAvailable frameworks:"; + string msg = $"The {targetRuntime} framework is not available for X86={runAsX86}.\r\nAvailable frameworks:"; // HACK - foreach (var runtime in ((RuntimeFrameworkService)_runtimeService).AvailableRuntimes) + var service = _runtimeService as RuntimeFrameworkService; + var availableRuntimes = runAsX86 ? service.AvailableX86Runtimes : service.AvailableRuntimes; + foreach (var runtime in availableRuntimes) msg += $" {runtime}"; throw new ArgumentException(msg); }