return false;
}
- return a.version < b.version;
+ if (a.version < b.version)
+ {
+ return true;
+ }
+
+ if (a.version == b.version)
+ {
+ return a.hive_depth > b.hive_depth;
+ }
+
+ return false;
}
/*static*/ void framework_info::get_all_framework_infos(
std::vector<pal::string_t> hive_dir;
get_framework_and_sdk_locations(own_dir, &hive_dir);
+ int32_t hive_depth = 0;
+
for (pal::string_t dir : hive_dir)
{
auto fx_shared_dir = dir;
{
trace::verbose(_X("Found FX version [%s]"), ver.c_str());
- framework_info info(fx_name, fx_dir, parsed);
+ framework_info info(fx_name, fx_dir, parsed, hive_depth);
framework_infos->push_back(info);
}
}
}
}
}
+
+ hive_depth++;
}
std::sort(framework_infos->begin(), framework_infos->end(), compare_by_name_and_version);
struct framework_info
{
- framework_info(pal::string_t name, pal::string_t path, fx_ver_t version)
+ framework_info(pal::string_t name, pal::string_t path, fx_ver_t version, int32_t hive_depth)
: name(name)
, path(path)
- , version(version) { }
+ , version(version)
+ , hive_depth(hive_depth) { }
static void get_all_framework_infos(
const pal::string_t& own_dir,
pal::string_t name;
pal::string_t path;
fx_ver_t version;
+ int32_t hive_depth;
};
#endif // __FRAMEWORK_INFO_H_
#include "hostfxr.h"
#include "host_context.h"
#include "bundle/info.h"
+#include <framework_info.h>
namespace
{
}
//
+// Returns available SDKs and frameworks.
+//
+// Resolves the existing SDKs and frameworks from a dotnet root directory (if
+// any), or the global default location. If multi-level lookup is enabled and
+// the dotnet root location is different than the global location, the SDKs and
+// frameworks will be enumerated from both locations.
+//
+// The SDKs are sorted in ascending order by version, multi-level lookup
+// locations are put before private ones.
+//
+// The frameworks are sorted in ascending order by name followed by version,
+// multi-level lookup locations are put before private ones.
+//
+// Parameters:
+// dotnet_root
+// The path to a directory containing a dotnet executable.
+//
+// reserved
+// Reserved for future parameters.
+//
+// result
+// Callback invoke to return the list of SDKs and frameworks.
+// Structs and their elements are valid for the duration of the call.
+//
+// result_context
+// Additional context passed to the result callback.
+//
+// Return value:
+// 0 on success, otherwise failure.
+//
+// String encoding:
+// Windows - UTF-16 (pal::char_t is 2 byte wchar_t)
+// Unix - UTF-8 (pal::char_t is 1 byte char)
+//
+SHARED_API int32_t HOSTFXR_CALLTYPE hostfxr_get_dotnet_environment_info(
+ const pal::char_t* dotnet_root,
+ void* reserved,
+ hostfxr_get_dotnet_environment_info_result_fn result,
+ void* result_context)
+{
+ if (result == nullptr)
+ {
+ trace::error(_X("hostfxr_get_dotnet_environment_info received an invalid argument: result should not be null."));
+ return StatusCode::InvalidArgFailure;
+ }
+
+ if (reserved != nullptr)
+ {
+ trace::error(_X("hostfxr_get_dotnet_environment_info received an invalid argument: reserved should be null."));
+ return StatusCode::InvalidArgFailure;
+ }
+
+ pal::string_t dotnet_dir;
+ if (dotnet_root == nullptr)
+ {
+ if (pal::get_dotnet_self_registered_dir(&dotnet_dir) || pal::get_default_installation_dir(&dotnet_dir))
+ {
+ trace::info(_X("Using global installation location [%s]."), dotnet_dir.c_str());
+ }
+ else
+ {
+ trace::info(_X("No default dotnet installation could be obtained."));
+ }
+ }
+ else
+ {
+ dotnet_dir = dotnet_root;
+ }
+
+ std::vector<sdk_info> sdk_infos;
+ sdk_info::get_all_sdk_infos(dotnet_dir, &sdk_infos);
+
+ std::vector<hostfxr_dotnet_environment_sdk_info> environment_sdk_infos;
+ std::vector<pal::string_t> sdk_versions;
+ if (!sdk_infos.empty())
+ {
+ environment_sdk_infos.reserve(sdk_infos.size());
+ sdk_versions.reserve(sdk_infos.size());
+ for (const sdk_info& info : sdk_infos)
+ {
+ sdk_versions.push_back(info.version.as_str());
+ hostfxr_dotnet_environment_sdk_info sdk
+ {
+ sizeof(hostfxr_dotnet_environment_sdk_info),
+ sdk_versions.back().c_str(),
+ info.full_path.c_str()
+ };
+
+ environment_sdk_infos.push_back(sdk);
+ }
+ }
+
+ std::vector<framework_info> framework_infos;
+ framework_info::get_all_framework_infos(dotnet_dir, _X(""), &framework_infos);
+
+ std::vector<hostfxr_dotnet_environment_framework_info> environment_framework_infos;
+ std::vector<pal::string_t> framework_versions;
+ if (!framework_infos.empty())
+ {
+ environment_framework_infos.reserve(framework_infos.size());
+ framework_versions.reserve(framework_infos.size());
+ for (const framework_info& info : framework_infos)
+ {
+ framework_versions.push_back(info.version.as_str());
+ hostfxr_dotnet_environment_framework_info fw
+ {
+ sizeof(hostfxr_dotnet_environment_framework_info),
+ info.name.c_str(),
+ framework_versions.back().c_str(),
+ info.path.c_str()
+ };
+
+ environment_framework_infos.push_back(fw);
+ }
+ }
+
+ const hostfxr_dotnet_environment_info environment_info
+ {
+ sizeof(hostfxr_dotnet_environment_info),
+ _STRINGIFY(HOST_FXR_PKG_VER),
+ _STRINGIFY(REPO_COMMIT_HASH),
+ environment_sdk_infos.size(),
+ (environment_sdk_infos.empty()) ? nullptr : &environment_sdk_infos[0],
+ environment_framework_infos.size(),
+ (environment_framework_infos.empty()) ? nullptr : &environment_framework_infos[0]
+ };
+
+ result(&environment_info, result_context);
+ return StatusCode::Success;
+}
+
+//
// Returns the native directories of the runtime based upon
// the specified app.
//
hostfxr_resolve_sdk
hostfxr_resolve_sdk2
hostfxr_get_available_sdks
+ hostfxr_get_dotnet_environment_info
hostfxr_get_native_search_directories
hostfxr_set_error_writer
hostfxr_initialize_for_dotnet_command_line
hostfxr_resolve_sdk
hostfxr_resolve_sdk2
hostfxr_get_available_sdks
+hostfxr_get_dotnet_environment_info
hostfxr_get_native_search_directories
hostfxr_set_error_writer
hostfxr_initialize_for_dotnet_command_line
//
typedef int32_t(HOSTFXR_CALLTYPE *hostfxr_close_fn)(const hostfxr_handle host_context_handle);
+struct hostfxr_dotnet_environment_sdk_info
+{
+ size_t size;
+ const char_t* version;
+ const char_t* path;
+};
+
+typedef void(HOSTFXR_CALLTYPE* hostfxr_get_dotnet_environment_info_result_fn)(
+ const struct hostfxr_dotnet_environment_info* info,
+ void* result_context);
+
+struct hostfxr_dotnet_environment_framework_info
+{
+ size_t size;
+ const char_t* name;
+ const char_t* version;
+ const char_t* path;
+};
+
+struct hostfxr_dotnet_environment_info
+{
+ size_t size;
+
+ const char_t* hostfxr_version;
+ const char_t* hostfxr_commit_hash;
+
+ int32_t sdk_count;
+ const hostfxr_dotnet_environment_sdk_info* sdks;
+
+ int32_t framework_count;
+ const hostfxr_dotnet_environment_framework_info* frameworks;
+};
+
#endif //__HOSTFXR_H__
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Runtime.InteropServices;
namespace HostApiInvokerApp
global_json_path = 1,
}
+ [StructLayout(LayoutKind.Sequential, CharSet = Utils.OSCharSet)]
+ internal struct hostfxr_dotnet_environment_sdk_info
+ {
+ internal int size;
+ internal string version;
+ internal string path;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = Utils.OSCharSet)]
+ internal struct hostfxr_dotnet_environment_framework_info
+ {
+ internal int size;
+ internal string name;
+ internal string version;
+ internal string path;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = Utils.OSCharSet)]
+ internal struct hostfxr_dotnet_environment_info
+ {
+ internal int size;
+
+ internal string hostfxr_version;
+ internal string hostfxr_commit_hash;
+
+ internal int sdk_count;
+ internal IntPtr sdks;
+
+ internal int framework_count;
+ internal IntPtr frameworks;
+ }
+
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = Utils.OSCharSet)]
internal delegate void hostfxr_resolve_sdk2_result_fn(
hostfxr_resolve_sdk2_result_key_t key,
[DllImport(nameof(hostfxr), CharSet = Utils.OSCharSet, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
internal static extern IntPtr hostfxr_set_error_writer(
hostfxr_error_writer_fn error_writer);
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = Utils.OSCharSet)]
+ internal delegate void hostfxr_get_dotnet_environment_info_result_fn(
+ IntPtr info,
+ IntPtr result_context);
+
+ [DllImport(nameof(hostfxr), CharSet = Utils.OSCharSet, ExactSpelling = true, CallingConvention = CallingConvention.Cdecl)]
+ internal static extern int hostfxr_get_dotnet_environment_info(
+ string dotnet_root,
+ IntPtr reserved,
+ hostfxr_get_dotnet_environment_info_result_fn result,
+ IntPtr result_context);
}
/// <summary>
}
}
+ /// <summary>
+ /// Test that invokes native api hostfxr_get_dotnet_environment_info.
+ /// </summary>
+ /// <param name="args[0]">hostfxr_get_dotnet_environment_info</param>
+ /// <param name="args[1]">(Optional) Path to the directory with dotnet.exe</param>
+ static void Test_hostfxr_get_dotnet_environment_info(string[] args)
+ {
+ string dotnetExeDir = null;
+ if (args.Length >= 2)
+ dotnetExeDir = args[1];
+
+ string hostfxr_version;
+ string hostfxr_commit_hash;
+ List<hostfxr.hostfxr_dotnet_environment_sdk_info> sdks = new List<hostfxr.hostfxr_dotnet_environment_sdk_info>();
+ List<hostfxr.hostfxr_dotnet_environment_framework_info> frameworks = new List<hostfxr.hostfxr_dotnet_environment_framework_info>();
+
+ hostfxr.hostfxr_get_dotnet_environment_info_result_fn result_fn = (IntPtr info, IntPtr result_context) =>
+ {
+ hostfxr.hostfxr_dotnet_environment_info environment_info = Marshal.PtrToStructure<hostfxr.hostfxr_dotnet_environment_info>(info);
+
+ hostfxr_version = environment_info.hostfxr_version;
+ hostfxr_commit_hash = environment_info.hostfxr_commit_hash;
+
+ int env_info_size = Marshal.SizeOf(environment_info);
+ if (env_info_size != environment_info.size)
+ throw new Exception($"Size field value of hostfxr_dotnet_environment_info struct is {environment_info.size} but {env_info_size} was expected.");
+
+ for (int i = 0; i < environment_info.sdk_count; i++)
+ {
+ IntPtr pSdkInfo = new IntPtr(environment_info.sdks.ToInt64() + (i * Marshal.SizeOf<hostfxr.hostfxr_dotnet_environment_sdk_info>()));
+ sdks.Add(Marshal.PtrToStructure<hostfxr.hostfxr_dotnet_environment_sdk_info>(pSdkInfo));
+
+ if (Marshal.SizeOf(sdks[i]) != sdks[i].size)
+ throw new Exception($"Size field value of hostfxr_dotnet_environment_sdk_info struct is {sdks[i].size} but {Marshal.SizeOf(sdks[i])} was expected.");
+ }
+
+ for (int i = 0; i < environment_info.framework_count; i++)
+ {
+ IntPtr pFrameworkInfo = new IntPtr(environment_info.frameworks.ToInt64() + (i * Marshal.SizeOf<hostfxr.hostfxr_dotnet_environment_framework_info>()));
+ frameworks.Add(Marshal.PtrToStructure<hostfxr.hostfxr_dotnet_environment_framework_info>(pFrameworkInfo));
+
+ if (Marshal.SizeOf(frameworks[i]) != frameworks[i].size)
+ throw new Exception($"Size field value of hostfxr_dotnet_environment_framework_info struct is {frameworks[i].size} but {Marshal.SizeOf(frameworks[i])} was expected.");
+ }
+
+ long result_context_as_int = result_context.ToInt64();
+ if (result_context_as_int != 42)
+ throw new Exception($"Invalid result_context value: expected 42 but was {result_context_as_int}.");
+ };
+
+ if (dotnetExeDir == "test_invalid_result_ptr")
+ result_fn = null;
+
+ IntPtr reserved_ptr = IntPtr.Zero;
+ if (dotnetExeDir == "test_invalid_reserved_ptr")
+ reserved_ptr = new IntPtr(11);
+
+ int rc = hostfxr.hostfxr_get_dotnet_environment_info(
+ dotnet_root: dotnetExeDir,
+ reserved: reserved_ptr,
+ result: result_fn,
+ result_context: new IntPtr(42));
+
+ if (rc != 0)
+ {
+ Console.WriteLine($"hostfxr_get_dotnet_environment_info:Fail[{rc}]");
+ }
+
+ Console.WriteLine($"hostfxr_get_dotnet_environment_info sdk versions:[{string.Join(";", sdks.Select(s => s.version).ToList())}]");
+ Console.WriteLine($"hostfxr_get_dotnet_environment_info sdk paths:[{string.Join(";", sdks.Select(s => s.path).ToList())}]");
+
+ Console.WriteLine($"hostfxr_get_dotnet_environment_info framework names:[{string.Join(";", frameworks.Select(f => f.name).ToList())}]");
+ Console.WriteLine($"hostfxr_get_dotnet_environment_info framework versions:[{string.Join(";", frameworks.Select(f => f.version).ToList())}]");
+ Console.WriteLine($"hostfxr_get_dotnet_environment_info framework paths:[{string.Join(";", frameworks.Select(f => f.path).ToList())}]");
+
+ Console.WriteLine("hostfxr_get_dotnet_environment_info:Success");
+ }
+
public static bool RunTest(string apiToTest, string[] args)
{
switch (apiToTest)
case nameof(Test_hostfxr_set_error_writer):
Test_hostfxr_set_error_writer(args);
break;
+ case nameof(hostfxr.hostfxr_get_dotnet_environment_info):
+ Test_hostfxr_get_dotnet_environment_info(args);
+ break;
default:
return false;
}
using Microsoft.DotNet.Cli.Build;
using System;
+using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using Xunit;
public string SelfRegistered => Path.Combine(ExeDir, "sr");
public string WorkingDir => Path.Combine(_fixture.TestProject.ProjectDirectory, "wd");
public string ProgramFilesGlobalSdkDir => Path.Combine(ProgramFiles, "dotnet", "sdk");
+ public string ProgramFilesGlobalFrameworksDir => Path.Combine(ProgramFiles, "dotnet", "shared");
public string SelfRegisteredGlobalSdkDir => Path.Combine(SelfRegistered, "sdk");
public string LocalSdkDir => Path.Combine(ExeDir, "sdk");
+ public string LocalFrameworksDir => Path.Combine(ExeDir, "shared");
public string GlobalJson => Path.Combine(WorkingDir, "global.json");
public string[] ProgramFilesGlobalSdks = new[] { "4.5.6", "1.2.3", "2.3.4-preview" };
+ public List<(string fwName, string[] fwVersions)> ProgramFilesGlobalFrameworks =
+ new List<(string fwName, string[] fwVersions)>()
+ {
+ ("HostFxr.Test.A", new[] { "1.2.3", "3.0.0" }),
+ ("HostFxr.Test.B", new[] { "5.6.7-A" })
+ };
public string[] SelfRegisteredGlobalSdks = new[] { "3.0.0", "15.1.4-preview", "5.6.7" };
public string[] LocalSdks = new[] { "0.1.2", "5.6.7-preview", "1.2.3" };
+ public List<(string fwName, string[] fwVersions)> LocalFrameworks =
+ new List<(string fwName, string[] fwVersions)>()
+ {
+ ("HostFxr.Test.B", new[] { "4.0.0", "5.6.7-A" }),
+ ("HostFxr.Test.C", new[] { "3.0.0" })
+ };
public SdkResolutionFixture(SharedTestState state)
{
{
Directory.CreateDirectory(Path.Combine(LocalSdkDir, sdk));
}
- }
+
+ foreach ((string fwName, string[] fwVersions) in ProgramFilesGlobalFrameworks)
+ {
+ foreach (string fwVersion in fwVersions)
+ Directory.CreateDirectory(Path.Combine(ProgramFilesGlobalFrameworksDir, fwName, fwVersion));
+ }
+ foreach ((string fwName, string[] fwVersions) in LocalFrameworks)
+ {
+ foreach (string fwVersion in fwVersions)
+ Directory.CreateDirectory(Path.Combine(LocalFrameworksDir, fwName, fwVersion));
+ }
+ }
}
[Fact]
public void Hostfxr_get_available_sdks_with_multilevel_lookup()
{
- if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
// multilevel lookup is not supported on non-Windows
return;
}
-
+
var f = new SdkResolutionFixture(sharedTestState);
// With multi-level lookup (windows only): get local and global sdks sorted by ascending version,
}
[Fact]
+ public void Hostfxr_get_dotnet_environment_info_dotnet_root_only()
+ {
+ var f = new SdkResolutionFixture(sharedTestState);
+ string expectedSdkVersions = string.Join(";", new[]
+ {
+ "0.1.2",
+ "1.2.3",
+ "5.6.7-preview"
+ });
+
+ string expectedSdkPaths = string.Join(';', new[]
+ {
+ Path.Combine(f.LocalSdkDir, "0.1.2"),
+ Path.Combine(f.LocalSdkDir, "1.2.3"),
+ Path.Combine(f.LocalSdkDir, "5.6.7-preview"),
+ });
+
+ string expectedFrameworkNames = string.Join(';', new[]
+ {
+ "HostFxr.Test.B",
+ "HostFxr.Test.B",
+ "HostFxr.Test.C"
+ });
+
+ string expectedFrameworkVersions = string.Join(';', new[]
+ {
+ "4.0.0",
+ "5.6.7-A",
+ "3.0.0"
+ });
+
+ string expectedFrameworkPaths = string.Join(';', new[]
+ {
+ Path.Combine(f.LocalFrameworksDir, "HostFxr.Test.B"),
+ Path.Combine(f.LocalFrameworksDir, "HostFxr.Test.B"),
+ Path.Combine(f.LocalFrameworksDir, "HostFxr.Test.C")
+ });
+
+ f.Dotnet.Exec(f.AppDll, new[] { "hostfxr_get_dotnet_environment_info", f.ExeDir })
+ .CaptureStdOut()
+ .CaptureStdErr()
+ .Execute()
+ .Should().Pass()
+ .And.HaveStdOutContaining("hostfxr_get_dotnet_environment_info:Success")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info sdk versions:[{expectedSdkVersions}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info sdk paths:[{expectedSdkPaths}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework names:[{expectedFrameworkNames}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework versions:[{expectedFrameworkVersions}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework paths:[{expectedFrameworkPaths}]");
+ }
+
+ [Fact]
+ public void Hostfxr_get_dotnet_environment_info_with_multilevel_lookup_with_dotnet_root()
+ {
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ // Only Windows supports multi-level lookup.
+ return;
+ }
+
+ var f = new SdkResolutionFixture(sharedTestState);
+ string expectedSdkVersions = string.Join(';', new[]
+ {
+ "0.1.2",
+ "1.2.3",
+ "1.2.3",
+ "2.3.4-preview",
+ "3.0.0",
+ "4.5.6",
+ "5.6.7-preview",
+ "5.6.7",
+ "15.1.4-preview"
+ });
+
+ string expectedSdkPaths = string.Join(';', new[]
+ {
+ Path.Combine(f.LocalSdkDir, "0.1.2"),
+ Path.Combine(f.ProgramFilesGlobalSdkDir, "1.2.3"),
+ Path.Combine(f.LocalSdkDir, "1.2.3"),
+ Path.Combine(f.ProgramFilesGlobalSdkDir, "2.3.4-preview"),
+ Path.Combine(f.SelfRegisteredGlobalSdkDir, "3.0.0"),
+ Path.Combine(f.ProgramFilesGlobalSdkDir, "4.5.6"),
+ Path.Combine(f.LocalSdkDir, "5.6.7-preview"),
+ Path.Combine(f.SelfRegisteredGlobalSdkDir, "5.6.7"),
+ Path.Combine(f.SelfRegisteredGlobalSdkDir, "15.1.4-preview"),
+ });
+
+ string expectedFrameworkNames = string.Join(';', new[]
+ {
+ "HostFxr.Test.A",
+ "HostFxr.Test.A",
+ "HostFxr.Test.B",
+ "HostFxr.Test.B",
+ "HostFxr.Test.B",
+ "HostFxr.Test.C"
+ });
+
+ string expectedFrameworkVersions = string.Join(';', new[]
+ {
+ "1.2.3",
+ "3.0.0",
+ "4.0.0",
+ "5.6.7-A",
+ "5.6.7-A",
+ "3.0.0"
+ });
+
+ string expectedFrameworkPaths = string.Join(';', new[]
+ {
+ Path.Combine(f.ProgramFilesGlobalFrameworksDir, "HostFxr.Test.A"),
+ Path.Combine(f.ProgramFilesGlobalFrameworksDir, "HostFxr.Test.A"),
+ Path.Combine(f.LocalFrameworksDir, "HostFxr.Test.B"),
+ Path.Combine(f.ProgramFilesGlobalFrameworksDir, "HostFxr.Test.B"),
+ Path.Combine(f.LocalFrameworksDir, "HostFxr.Test.B"),
+ Path.Combine(f.LocalFrameworksDir, "HostFxr.Test.C")
+ });
+
+ using (TestOnlyProductBehavior.Enable(f.Dotnet.GreatestVersionHostFxrFilePath))
+ {
+ f.Dotnet.Exec(f.AppDll, new[] { "hostfxr_get_dotnet_environment_info", f.ExeDir })
+ .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES", f.ProgramFiles)
+ .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_SELF_REGISTERED", f.SelfRegistered)
+ .CaptureStdOut()
+ .CaptureStdErr()
+ .Execute()
+ .Should().Pass()
+ .And.HaveStdOutContaining("hostfxr_get_dotnet_environment_info:Success")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info sdk versions:[{expectedSdkVersions}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info sdk paths:[{expectedSdkPaths}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework names:[{expectedFrameworkNames}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework versions:[{expectedFrameworkVersions}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework paths:[{expectedFrameworkPaths}]");
+ }
+ }
+
+ [Fact]
+ public void Hostfxr_get_dotnet_environment_info_with_multilevel_lookup_only()
+ {
+ if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ // Only Windows supports multi-level lookup.
+ return;
+ }
+
+ var f = new SdkResolutionFixture(sharedTestState);
+ string expectedSdkVersions = string.Join(';', new[]
+ {
+ "1.2.3",
+ "2.3.4-preview",
+ "3.0.0",
+ "4.5.6",
+ "5.6.7",
+ "15.1.4-preview"
+ });
+
+ string expectedSdkPaths = string.Join(';', new[]
+ {
+ Path.Combine(f.ProgramFilesGlobalSdkDir, "1.2.3"),
+ Path.Combine(f.ProgramFilesGlobalSdkDir, "2.3.4-preview"),
+ Path.Combine(f.SelfRegisteredGlobalSdkDir, "3.0.0"),
+ Path.Combine(f.ProgramFilesGlobalSdkDir, "4.5.6"),
+ Path.Combine(f.SelfRegisteredGlobalSdkDir, "5.6.7"),
+ Path.Combine(f.SelfRegisteredGlobalSdkDir, "15.1.4-preview"),
+ });
+
+ string expectedFrameworkNames = string.Join(';', new[]
+ {
+ "HostFxr.Test.A",
+ "HostFxr.Test.A",
+ "HostFxr.Test.B",
+ });
+
+ string expectedFrameworkVersions = string.Join(';', new[]
+ {
+ "1.2.3",
+ "3.0.0",
+ "5.6.7-A",
+ });
+
+ string expectedFrameworkPaths = string.Join(';', new[]
+ {
+ Path.Combine(f.ProgramFilesGlobalFrameworksDir, "HostFxr.Test.A"),
+ Path.Combine(f.ProgramFilesGlobalFrameworksDir, "HostFxr.Test.A"),
+ Path.Combine(f.ProgramFilesGlobalFrameworksDir, "HostFxr.Test.B"),
+ });
+
+ using (TestOnlyProductBehavior.Enable(f.Dotnet.GreatestVersionHostFxrFilePath))
+ {
+ // We pass f.WorkingDir so that we don't resolve dotnet_dir to the global installation
+ // in the native side.
+ f.Dotnet.Exec(f.AppDll, new[] { "hostfxr_get_dotnet_environment_info", f.WorkingDir })
+ .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_PROGRAM_FILES", f.ProgramFiles)
+ .EnvironmentVariable("TEST_MULTILEVEL_LOOKUP_SELF_REGISTERED", f.SelfRegistered)
+ .CaptureStdOut()
+ .CaptureStdErr()
+ .Execute()
+ .Should().Pass()
+ .And.HaveStdOutContaining("hostfxr_get_dotnet_environment_info:Success")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info sdk versions:[{expectedSdkVersions}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info sdk paths:[{expectedSdkPaths}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework names:[{expectedFrameworkNames}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework versions:[{expectedFrameworkVersions}]")
+ .And.HaveStdOutContaining($"hostfxr_get_dotnet_environment_info framework paths:[{expectedFrameworkPaths}]");
+ }
+ }
+
+ [Fact]
+ public void Hostfxr_get_dotnet_environment_info_global_install_path()
+ {
+ var f = new SdkResolutionFixture(sharedTestState);
+
+ f.Dotnet.Exec(f.AppDll, new[] { "hostfxr_get_dotnet_environment_info" })
+ .CaptureStdOut()
+ .CaptureStdErr()
+ .Execute()
+ .Should().Pass()
+ .And.HaveStdOutContaining("hostfxr_get_dotnet_environment_info:Success");
+ }
+
+ [Fact]
+ public void Hostfxr_get_dotnet_environment_info_result_is_nullptr_fails()
+ {
+ var f = new SdkResolutionFixture(sharedTestState);
+
+ f.Dotnet.Exec(f.AppDll, new[] { "hostfxr_get_dotnet_environment_info", "test_invalid_result_ptr" })
+ .EnvironmentVariable("COREHOST_TRACE", "1")
+ .CaptureStdOut()
+ .CaptureStdErr()
+ .Execute()
+ .Should().Pass()
+ // 0x80008081 (InvalidArgFailure)
+ .And.HaveStdOutContaining("hostfxr_get_dotnet_environment_info:Fail[-2147450751]")
+ .And.HaveStdErrContaining("hostfxr_get_dotnet_environment_info received an invalid argument: result should not be null.");
+ }
+
+ [Fact]
+ public void Hostfxr_get_dotnet_environment_info_reserved_is_not_nullptr_fails()
+ {
+ var f = new SdkResolutionFixture(sharedTestState);
+
+ f.Dotnet.Exec(f.AppDll, new[] { "hostfxr_get_dotnet_environment_info", "test_invalid_reserved_ptr" })
+ .EnvironmentVariable("COREHOST_TRACE", "1")
+ .CaptureStdOut()
+ .CaptureStdErr()
+ .Execute()
+ .Should().Pass()
+ // 0x80008081 (InvalidArgFailure)
+ .And.HaveStdOutContaining("hostfxr_get_dotnet_environment_info:Fail[-2147450751]")
+ .And.HaveStdErrContaining("hostfxr_get_dotnet_environment_info received an invalid argument: reserved should be null.");
+ }
+
+ [Fact]
public void Hostpolicy_corehost_set_error_writer_test()
{
var fixture = sharedTestState.HostApiInvokerAppFixture.Copy();
RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostfxr"));
FileUtils.CopyIntoDirectory(
- hostfxr,
+ hostfxr,
Path.GetDirectoryName(fixture.TestProject.AppDll));
}
}