--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.DotNet.Cli.Build.Framework;
+
+namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
+{
+ public static class CommandExtensions
+ {
+ public static Command EnableHostTracing(this Command command)
+ {
+ return command.EnvironmentVariable(Constants.HostTracing.TraceLevelEnvironmentVariable, "1");
+ }
+
+ public static Command EnableTracingAndCaptureOutputs(this Command command)
+ {
+ return command
+ .EnableHostTracing()
+ .CaptureStdOut()
+ .CaptureStdErr();
+ }
+
+ public static Command RuntimeId(this Command command, string rid)
+ {
+ return command.EnvironmentVariable(Constants.RuntimeId.EnvironmentVariable, rid);
+ }
+ }
+}
public const string GloballyRegisteredPath = "_DOTNET_TEST_GLOBALLY_REGISTERED_PATH";
public const string InstallLocationFilePath = "_DOTNET_TEST_INSTALL_LOCATION_FILE_PATH";
}
+
+ public static class RuntimeId
+ {
+ public const string EnvironmentVariable = "DOTNET_RUNTIME_ID";
+ }
+
+ public static class MultilevelLookup
+ {
+ public const string EnvironmentVariable = "DOTNET_MULTILEVEL_LOOKUP";
+ }
+
+ public static class HostTracing
+ {
+ public const string TraceLevelEnvironmentVariable = "COREHOST_TRACE";
+ public const string TraceFileEnvironmentVariable = "COREHOST_TRACEFILE";
+ }
}
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.IO;
+
+namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.DependencyResolution
+{
+ public abstract class DependencyResolutionBase
+ {
+ protected const string MicrosoftNETCoreApp = "Microsoft.NETCore.App";
+
+ public abstract class SharedTestStateBase : TestArtifact
+ {
+ private readonly string _builtDotnet;
+
+ private static string GetBaseDir(string name)
+ {
+ string baseDir = Path.Combine(TestArtifactsPath, name);
+ return SharedFramework.CalculateUniqueTestDirectory(baseDir);
+ }
+
+ public SharedTestStateBase(string name)
+ : base(GetBaseDir(name), name)
+ {
+ _builtDotnet = Path.Combine(TestArtifactsPath, "sharedFrameworkPublish");
+ }
+
+ public DotNetBuilder DotNet(string name)
+ {
+ return new DotNetBuilder(Location, _builtDotnet, name);
+ }
+
+ public TestApp CreateFrameworkReferenceApp(string fxName, string fxVersion)
+ {
+ // Prepare the app mock - we're not going to run anything really, so we just need the basic files
+ string testAppDir = Path.Combine(Location, "FrameworkReferenceApp");
+ Directory.CreateDirectory(testAppDir);
+
+ TestApp testApp = new TestApp(testAppDir);
+ RuntimeConfig.Path(testApp.RuntimeConfigJson)
+ .WithFramework(fxName, fxVersion)
+ .Save();
+
+ return testApp;
+ }
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using FluentAssertions;
+using FluentAssertions.Execution;
+using System;
+using System.IO;
+
+namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.DependencyResolution
+{
+ public static class DependencyResolutionCommandResultExtensions
+ {
+ public const string TRUSTED_PLATFORM_ASSEMBLIES = "TRUSTED_PLATFORM_ASSEMBLIES";
+ public const string NATIVE_DLL_SEARCH_DIRECTORIES = "NATIVE_DLL_SEARCH_DIRECTORIES";
+
+ public static AndConstraint<CommandResultAssertions> HaveRuntimePropertyContaining(this CommandResultAssertions assertion, string propertyName, string value)
+ {
+ string propertyValue = GetMockPropertyValue(assertion, propertyName);
+
+ Execute.Assertion.ForCondition(propertyValue != null && propertyValue.Contains(value))
+ .FailWith("The property {0} doesn't contain expected value: {1}{2}{3}", propertyName, value, propertyValue, assertion.GetDiagnosticsInfo());
+ return new AndConstraint<CommandResultAssertions>(assertion);
+ }
+
+ public static AndConstraint<CommandResultAssertions> NotHaveRuntimePropertyContaining(this CommandResultAssertions assertion, string propertyName, string value)
+ {
+ string propertyValue = GetMockPropertyValue(assertion, propertyName);
+
+ Execute.Assertion.ForCondition(propertyValue != null && !propertyValue.Contains(value))
+ .FailWith("The property {0} contains unexpected value: {1}{2}{3}", propertyName, value, propertyValue, assertion.GetDiagnosticsInfo());
+ return new AndConstraint<CommandResultAssertions>(assertion);
+ }
+
+ public static AndConstraint<CommandResultAssertions> HaveResolvedAssembly(this CommandResultAssertions assertion, string assemblyPath, TestApp app = null)
+ {
+ return assertion.HaveRuntimePropertyContaining(TRUSTED_PLATFORM_ASSEMBLIES, RelativePathToAbsoluteAppPath(assemblyPath, app));
+ }
+
+ public static AndConstraint<CommandResultAssertions> NotHaveResolvedAssembly(this CommandResultAssertions assertion, string assemblyPath, TestApp app = null)
+ {
+ return assertion.NotHaveRuntimePropertyContaining(TRUSTED_PLATFORM_ASSEMBLIES, RelativePathToAbsoluteAppPath(assemblyPath, app));
+ }
+
+ public static AndConstraint<CommandResultAssertions> HaveResolvedNativeLibraryPath(this CommandResultAssertions assertion, string path, TestApp app = null)
+ {
+ return assertion.HaveRuntimePropertyContaining(NATIVE_DLL_SEARCH_DIRECTORIES, RelativePathToAbsoluteAppPath(path, app));
+ }
+
+ public static AndConstraint<CommandResultAssertions> NotHaveResolvedNativeLibraryPath(this CommandResultAssertions assertion, string path, TestApp app = null)
+ {
+ return assertion.NotHaveRuntimePropertyContaining(NATIVE_DLL_SEARCH_DIRECTORIES, RelativePathToAbsoluteAppPath(path, app));
+ }
+
+ private static string GetMockPropertyValue(CommandResultAssertions assertion, string propertyName)
+ {
+ string propertyHeader = $"mock property[{propertyName}] = ";
+ string stdout = assertion.Result.StdOut;
+ int i = stdout.IndexOf(propertyHeader);
+ if (i >= 0)
+ {
+ i += propertyHeader.Length;
+ int end = assertion.Result.StdOut.IndexOf(Environment.NewLine, i);
+ if (end >= i)
+ {
+ return stdout.Substring(i, end - i);
+ }
+ }
+
+ return null;
+ }
+
+ private static string RelativePathToAbsoluteAppPath(string relativePath, TestApp app)
+ {
+ string path = relativePath.Replace('/', Path.DirectorySeparatorChar);
+ if (app != null)
+ {
+ path = Path.Combine(app.Location, path);
+ }
+
+ return path;
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.DotNet.Cli.Build;
+using Xunit;
+
+namespace Microsoft.DotNet.CoreSetup.Test.HostActivation.DependencyResolution
+{
+ public class PortableAppRidAssetResolution :
+ DependencyResolutionBase,
+ IClassFixture<PortableAppRidAssetResolution.SharedTestState>
+ {
+ private SharedTestState SharedState { get; }
+
+ public PortableAppRidAssetResolution(SharedTestState sharedState)
+ {
+ SharedState = sharedState;
+ }
+
+ [Theory]
+ [InlineData("win", "win/WindowsAssembly.dll", "linux/LinuxAssembly.dll")]
+ [InlineData("win10-x64", "win/WindowsAssembly.dll", "linux/LinuxAssembly.dll")]
+ [InlineData("linux", "linux/LinuxAssembly.dll", "win/WindowsAssembly.dll")]
+ public void RidSpecificAssembly(string rid, string includedPath, string excludedPath)
+ {
+ using (TestApp app = NetCoreAppBuilder.PortableForNETCoreApp(SharedState.FrameworkReferenceApp)
+ .WithProject(p => p
+ .WithAssemblyGroup(null, g => g.WithMainAssembly())
+ .WithAssemblyGroup("win", g => g.WithAsset("win/WindowsAssembly.dll"))
+ .WithAssemblyGroup("linux", g => g.WithAsset("linux/LinuxAssembly.dll")))
+ .Build())
+ {
+ SharedState.DotNetWithNetCoreApp.Exec(app.AppDll)
+ .EnableTracingAndCaptureOutputs()
+ .RuntimeId(rid)
+ .Execute()
+ .Should().Pass()
+ .And.HaveResolvedAssembly(includedPath, app)
+ .And.NotHaveResolvedAssembly(excludedPath, app);
+ }
+ }
+
+ [Theory]
+ [InlineData("win", "win", "linux")]
+ [InlineData("win10-x64", "win", "linux")]
+ [InlineData("linux", "linux", "win")]
+ public void RidSpecificNativeLibrary(string rid, string includedPath, string excludedPath)
+ {
+ using (TestApp app = NetCoreAppBuilder.PortableForNETCoreApp(SharedState.FrameworkReferenceApp)
+ .WithProject(p => p
+ .WithAssemblyGroup(null, g => g.WithMainAssembly())
+ .WithNativeLibraryGroup("win", g => g.WithAsset("win/WindowsNativeLibrary.dll"))
+ .WithNativeLibraryGroup("linux", g => g.WithAsset("linux/LinuxNativeLibrary.so")))
+ .Build())
+ {
+ SharedState.DotNetWithNetCoreApp.Exec(app.AppDll)
+ .EnableTracingAndCaptureOutputs()
+ .RuntimeId(rid)
+ .Execute()
+ .Should().Pass()
+ .And.HaveResolvedNativeLibraryPath(includedPath, app)
+ .And.NotHaveResolvedNativeLibraryPath(excludedPath, app);
+ }
+ }
+
+ [Theory]
+ [InlineData("win10-x64", "win-x64/ManagedWin64.dll")]
+ [InlineData("win10-x86", "win/ManagedWin.dll")]
+ [InlineData("linux", "any/ManagedAny.dll")]
+ public void MostSpecificRidAssemblySelected(string rid, string expectedPath)
+ {
+ using (TestApp app = NetCoreAppBuilder.PortableForNETCoreApp(SharedState.FrameworkReferenceApp)
+ .WithProject(p => p
+ .WithAssemblyGroup(null, g => g.WithMainAssembly())
+ .WithAssemblyGroup("any", g => g.WithAsset("any/ManagedAny.dll"))
+ .WithAssemblyGroup("win", g => g.WithAsset("win/ManagedWin.dll"))
+ .WithAssemblyGroup("win-x64", g => g.WithAsset("win-x64/ManagedWin64.dll")))
+ .Build())
+ {
+ SharedState.DotNetWithNetCoreApp.Exec(app.AppDll)
+ .EnableTracingAndCaptureOutputs()
+ .RuntimeId(rid)
+ .Execute()
+ .Should().Pass()
+ .And.HaveResolvedAssembly(expectedPath, app);
+ }
+ }
+
+ [Theory]
+ [InlineData("win10-x64", "win-x64")]
+ [InlineData("win10-x86", "win")]
+ [InlineData("linux", "any")]
+ public void MostSpecificRidNativeLibrarySelected(string rid, string expectedPath)
+ {
+ using (TestApp app = NetCoreAppBuilder.PortableForNETCoreApp(SharedState.FrameworkReferenceApp)
+ .WithProject(p => p
+ .WithAssemblyGroup(null, g => g.WithMainAssembly())
+ .WithNativeLibraryGroup("any", g => g.WithAsset("any/NativeAny.dll"))
+ .WithNativeLibraryGroup("win", g => g.WithAsset("win/NativeWin.dll"))
+ .WithNativeLibraryGroup("win-x64", g => g.WithAsset("win-x64/NativeWin64.dll")))
+ .Build())
+ {
+ SharedState.DotNetWithNetCoreApp.Exec(app.AppDll)
+ .EnableTracingAndCaptureOutputs()
+ .RuntimeId(rid)
+ .Execute()
+ .Should().Pass()
+ .And.HaveResolvedNativeLibraryPath(expectedPath, app);
+ }
+ }
+
+ public class SharedTestState : SharedTestStateBase
+ {
+ public TestApp FrameworkReferenceApp { get; }
+
+ public DotNetCli DotNetWithNetCoreApp { get; }
+
+ public SharedTestState() : base("DependencyResolution")
+ {
+ DotNetWithNetCoreApp = DotNet("WithNetCoreApp")
+ .AddMicrosoftNETCoreAppFrameworkMockCoreClr("4.0.0")
+ .Build();
+
+ FrameworkReferenceApp = CreateFrameworkReferenceApp(MicrosoftNETCoreApp, "4.0.0");
+ }
+ }
+ }
+}
string netCoreAppPath = Path.Combine(_path, "shared", "Microsoft.NETCore.App", version);
Directory.CreateDirectory(netCoreAppPath);
- // ./shared/Microsoft.NETCore.App/<version>/hostpolicy.dll - this is the real component and will load CoreClr library
string hostPolicyFileName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("hostpolicy");
- File.Copy(
- Path.Combine(_repoDirectories.Artifacts, "corehost", hostPolicyFileName),
- Path.Combine(netCoreAppPath, hostPolicyFileName),
- true);
-
- // ./shared/Microsoft.NETCore.App/<version>/coreclr.dll - this is a mock, will not actually run CoreClr
string coreclrFileName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("coreclr");
string mockCoreclrFileName = RuntimeInformationExtensions.GetSharedLibraryFileNameForCurrentPlatform("mockcoreclr");
- File.Copy(
- Path.Combine(_repoDirectories.Artifacts, "corehost_test", mockCoreclrFileName),
- Path.Combine(netCoreAppPath, coreclrFileName),
- true);
string netCoreAppPathDepsJson = Path.Combine(netCoreAppPath, "Microsoft.NETCore.App.deps.json");
string currentRid = _repoDirectories.TargetRID;
- string depsJsonBody = $@"{{
- ""runtimeTarget"": "".NETCoreApp"",
- ""targets"": {{
- "".NETCoreApp"": {{
- ""Microsoft.NETCore.App/{version}"": {{
- ""native"": {{
- ""runtimes/{currentRid}/native/{coreclrFileName}"": {{ }}
- }}
- }},
- ""runtime.{currentRid}.Microsoft.NETCore.DotNetHostPolicy/{version}"": {{
- ""native"": {{
- ""runtimes/{currentRid}/native/{hostPolicyFileName}"": {{}}
- }}
- }}
- }}
- }},
- ""libraries"": {{
- ""Microsoft.NETCore.App/{version}"": {{
- ""type"": ""package"",
- ""serviceable"": true,
- ""sha512"": """"
- }}
- }}
- }}";
-
- File.WriteAllText(netCoreAppPathDepsJson, depsJsonBody);
+ NetCoreAppBuilder.ForNETCoreApp("Microsoft.NETCore.App", currentRid)
+ .WithStandardRuntimeFallbacks()
+ .WithProject("Microsoft.NETCore.App", version, p => p
+ .WithNativeLibraryGroup(null, g => g
+ // ./shared/Microsoft.NETCore.App/<version>/coreclr.dll - this is a mock, will not actually run CoreClr
+ .WithAsset((new NetCoreAppBuilder.RuntimeFileBuilder($"runtimes/{currentRid}/native/{coreclrFileName}"))
+ .CopyFromFile(Path.Combine(_repoDirectories.Artifacts, "corehost_test", mockCoreclrFileName))
+ .WithFileOnDiskPath(coreclrFileName))))
+ .WithPackage($"runtime.{currentRid}.Microsoft.NETCore.DotNetHostPolicy", version, p => p
+ .WithNativeLibraryGroup(null, g => g
+ // ./shared/Microsoft.NETCore.App/<version>/hostpolicy.dll - this is the real component and will load CoreClr library
+ .WithAsset((new NetCoreAppBuilder.RuntimeFileBuilder($"runtimes/{currentRid}/native/{hostPolicyFileName}"))
+ .CopyFromFile(Path.Combine(_repoDirectories.Artifacts, "corehost", hostPolicyFileName))
+ .WithFileOnDiskPath(hostPolicyFileName))))
+ .Build(new TestApp(netCoreAppPath, "Microsoft.NETCore.App"));
+
return this;
}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using Microsoft.Extensions.DependencyModel;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+
+namespace Microsoft.DotNet.CoreSetup.Test.HostActivation
+{
+ public class NetCoreAppBuilder
+ {
+ public string Name { get; set; }
+ public string Framework { get; set; }
+ public string Runtime { get; set; }
+
+ private TestApp _sourceApp;
+
+ public Action<RuntimeConfig> RuntimeConfigCustomizer { get; set; }
+
+ public List<RuntimeLibraryBuilder> RuntimeLibraries { get; } = new List<RuntimeLibraryBuilder>();
+
+ public List<RuntimeFallbacksBuilder> RuntimeFallbacks { get; } = new List<RuntimeFallbacksBuilder>();
+
+ internal class BuildContext
+ {
+ public TestApp App { get; set; }
+ }
+
+ public class RuntimeFileBuilder
+ {
+ public string Path { get; set; }
+ public string AssemblyVersion { get; set; }
+ public string FileVersion { get; set; }
+
+ public string SourcePath { get; set; }
+ public string FileOnDiskPath { get; set; }
+
+ public RuntimeFileBuilder(string path)
+ {
+ Path = path;
+ }
+
+ public RuntimeFileBuilder CopyFromFile(string sourcePath)
+ {
+ SourcePath = sourcePath;
+ return this;
+ }
+
+ public RuntimeFileBuilder WithFileOnDiskPath(string relativePath)
+ {
+ FileOnDiskPath = relativePath;
+ return this;
+ }
+
+ internal RuntimeFile Build(BuildContext context)
+ {
+ string path = ToDiskPath(FileOnDiskPath ?? Path);
+ string absolutePath = System.IO.Path.Combine(context.App.Location, path);
+ if (SourcePath != null)
+ {
+ FileUtils.EnsureFileDirectoryExists(absolutePath);
+ File.Copy(SourcePath, absolutePath);
+ }
+ else
+ {
+ FileUtils.CreateEmptyFile(absolutePath);
+ }
+
+ return new RuntimeFile(Path, AssemblyVersion, FileVersion);
+ }
+
+ private static string ToDiskPath(string assetPath)
+ {
+ return assetPath.Replace('/', System.IO.Path.DirectorySeparatorChar);
+ }
+ }
+
+ public class RuntimeAssetGroupBuilder
+ {
+ public string Runtime { get; set; }
+
+ public bool IncludeMainAssembly { get; set; }
+
+ public List<RuntimeFileBuilder> Assets { get; } = new List<RuntimeFileBuilder>();
+
+ public RuntimeAssetGroupBuilder(string runtime)
+ {
+ Runtime = runtime ?? string.Empty;
+ }
+
+ public RuntimeAssetGroupBuilder WithMainAssembly()
+ {
+ IncludeMainAssembly = true;
+ return this;
+ }
+
+ public RuntimeAssetGroupBuilder WithAsset(RuntimeFileBuilder asset)
+ {
+ Assets.Add(asset);
+ return this;
+ }
+
+ public RuntimeAssetGroupBuilder WithAsset(string path)
+ {
+ return WithAsset(new RuntimeFileBuilder(path));
+ }
+
+ internal RuntimeAssetGroup Build(BuildContext context)
+ {
+ IEnumerable<RuntimeFileBuilder> assets = Assets;
+ if (IncludeMainAssembly)
+ {
+ assets = assets.Append(new RuntimeFileBuilder(Path.GetFileName(context.App.AppDll)));
+ }
+
+ return new RuntimeAssetGroup(
+ Runtime,
+ assets.Select(a => a.Build(context)));
+ }
+ }
+
+ public enum RuntimeLibraryType
+ {
+ project,
+ package
+ }
+
+ public class RuntimeLibraryBuilder
+ {
+ public string Type { get; set; }
+ public string Name { get; set; }
+ public string Version { get; set; }
+
+ public List<RuntimeAssetGroupBuilder> AssemblyGroups { get; } = new List<RuntimeAssetGroupBuilder>();
+ public List<RuntimeAssetGroupBuilder> NativeLibraryGroups { get; } = new List<RuntimeAssetGroupBuilder>();
+
+ public RuntimeLibraryBuilder(RuntimeLibraryType type, string name, string version)
+ {
+ Type = type.ToString();
+ Name = name;
+ Version = version;
+ }
+
+ public RuntimeLibraryBuilder WithAssemblyGroup(string runtime, Action<RuntimeAssetGroupBuilder> customizer = null)
+ {
+ return WithRuntimeAssetGroup(runtime, AssemblyGroups, customizer);
+ }
+
+ public RuntimeLibraryBuilder WithNativeLibraryGroup(string runtime, Action<RuntimeAssetGroupBuilder> customizer = null)
+ {
+ return WithRuntimeAssetGroup(runtime, NativeLibraryGroups, customizer);
+ }
+
+ private RuntimeLibraryBuilder WithRuntimeAssetGroup(
+ string runtime,
+ IList<RuntimeAssetGroupBuilder> list,
+ Action<RuntimeAssetGroupBuilder> customizer)
+ {
+ RuntimeAssetGroupBuilder runtimeAssetGroup = new RuntimeAssetGroupBuilder(runtime);
+ customizer?.Invoke(runtimeAssetGroup);
+
+ list.Add(runtimeAssetGroup);
+ return this;
+ }
+
+ internal RuntimeLibrary Build(BuildContext context)
+ {
+ return new RuntimeLibrary(
+ Type,
+ Name,
+ Version,
+ string.Empty,
+ AssemblyGroups.Select(g => g.Build(context)).ToList(),
+ NativeLibraryGroups.Select(g => g.Build(context)).ToList(),
+ Enumerable.Empty<ResourceAssembly>(),
+ Enumerable.Empty<Dependency>(),
+ false);
+ }
+ }
+
+ public class RuntimeFallbacksBuilder
+ {
+ public string Runtime { get; set; }
+ public List<string> Fallbacks { get; } = new List<string>();
+
+ public RuntimeFallbacksBuilder(string runtime, params string[] fallbacks)
+ {
+ Runtime = runtime;
+ Fallbacks.AddRange(fallbacks);
+ }
+
+ public RuntimeFallbacksBuilder WithFallback(params string[] fallback)
+ {
+ Fallbacks.AddRange(fallback);
+ return this;
+ }
+
+ internal RuntimeFallbacks Build()
+ {
+ return new RuntimeFallbacks(Runtime, Fallbacks);
+ }
+ }
+
+ public static NetCoreAppBuilder PortableForNETCoreApp(TestApp sourceApp)
+ {
+ return new NetCoreAppBuilder()
+ {
+ _sourceApp = sourceApp,
+ Name = sourceApp.Name,
+ Framework = ".NETCoreApp,Version=v3.0",
+ Runtime = null
+ };
+ }
+
+ public static NetCoreAppBuilder ForNETCoreApp(string name, string runtime)
+ {
+ return new NetCoreAppBuilder()
+ {
+ _sourceApp = null,
+ Name = name,
+ Framework = ".NETCoreApp,Version=v3.0",
+ Runtime = runtime
+ };
+ }
+
+ public NetCoreAppBuilder WithRuntimeConfig(Action<RuntimeConfig> runtimeConfigCustomizer)
+ {
+ RuntimeConfigCustomizer = runtimeConfigCustomizer;
+ return this;
+ }
+
+ public NetCoreAppBuilder WithRuntimeLibrary(
+ RuntimeLibraryType type,
+ string name,
+ string version,
+ Action<RuntimeLibraryBuilder> customizer = null)
+ {
+ RuntimeLibraryBuilder runtimeLibrary = new RuntimeLibraryBuilder(type, name, version);
+ customizer?.Invoke(runtimeLibrary);
+
+ RuntimeLibraries.Add(runtimeLibrary);
+ return this;
+ }
+
+ public NetCoreAppBuilder WithProject(string name, string version, Action<RuntimeLibraryBuilder> customizer = null)
+ {
+ return WithRuntimeLibrary(RuntimeLibraryType.project, name, version, customizer);
+ }
+
+ public NetCoreAppBuilder WithProject(Action<RuntimeLibraryBuilder> customizer = null)
+ {
+ return WithRuntimeLibrary(RuntimeLibraryType.project, Name, "1.0.0", customizer);
+ }
+
+ public NetCoreAppBuilder WithPackage(string name, string version, Action<RuntimeLibraryBuilder> customizer = null)
+ {
+ return WithRuntimeLibrary(RuntimeLibraryType.package, name, version, customizer);
+ }
+
+ public NetCoreAppBuilder WithRuntimeFallbacks(string runtime, params string[] fallbacks)
+ {
+ RuntimeFallbacks.Add(new RuntimeFallbacksBuilder(runtime, fallbacks));
+ return this;
+ }
+
+ public NetCoreAppBuilder WithStandardRuntimeFallbacks()
+ {
+ return
+ WithRuntimeFallbacks("win10-x64", "win10", "win-x64", "win", "any")
+ .WithRuntimeFallbacks("win10-x86", "win10", "win-x86", "win", "any")
+ .WithRuntimeFallbacks("win10", "win", "any")
+ .WithRuntimeFallbacks("win-x64", "win", "any")
+ .WithRuntimeFallbacks("win-x86", "win", "any")
+ .WithRuntimeFallbacks("win", "any")
+ .WithRuntimeFallbacks("linux", "any");
+ }
+
+ private DependencyContext BuildDependencyContext(BuildContext context)
+ {
+ return new DependencyContext(
+ new TargetInfo(Framework, Runtime, null, Runtime == null),
+ CompilationOptions.Default,
+ Enumerable.Empty<CompilationLibrary>(),
+ RuntimeLibraries.Select(rl => rl.Build(context)),
+ RuntimeFallbacks.Select(rf => rf.Build()));
+ }
+
+ public TestApp Build()
+ {
+ return Build(_sourceApp.Copy());
+ }
+
+ public TestApp Build(TestApp testApp)
+ {
+ RuntimeConfig runtimeConfig = null;
+ if (File.Exists(testApp.RuntimeConfigJson))
+ {
+ runtimeConfig = RuntimeConfig.FromFile(testApp.RuntimeConfigJson);
+ }
+ else if (RuntimeConfigCustomizer != null)
+ {
+ runtimeConfig = new RuntimeConfig(testApp.RuntimeConfigJson);
+ }
+
+ if (runtimeConfig != null)
+ {
+ RuntimeConfigCustomizer?.Invoke(runtimeConfig);
+ runtimeConfig.Save();
+ }
+
+ BuildContext buildContext = new BuildContext()
+ {
+ App = testApp
+ };
+ DependencyContext dependencyContext = BuildDependencyContext(buildContext);
+
+ DependencyContextWriter writer = new DependencyContextWriter();
+ using (FileStream stream = new FileStream(testApp.DepsJson, FileMode.Create))
+ {
+ writer.Write(dependencyContext, stream);
+ }
+
+ return testApp;
+ }
+ }
+}
\ No newline at end of file
{
public class CommandResultAssertions
{
- private CommandResult _commandResult;
+ public CommandResult Result { get; }
public CommandResultAssertions(CommandResult commandResult)
{
- _commandResult = commandResult;
+ Result = commandResult;
}
public AndConstraint<CommandResultAssertions> ExitWith(int expectedExitCode)
{
- Execute.Assertion.ForCondition(_commandResult.ExitCode == expectedExitCode)
+ Execute.Assertion.ForCondition(Result.ExitCode == expectedExitCode)
.FailWith("Expected command to exit with {0} but it did not.{1}", expectedExitCode, GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> Pass()
{
- Execute.Assertion.ForCondition(_commandResult.ExitCode == 0)
+ Execute.Assertion.ForCondition(Result.ExitCode == 0)
.FailWith("Expected command to pass but it did not.{0}", GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> Fail()
{
- Execute.Assertion.ForCondition(_commandResult.ExitCode != 0)
+ Execute.Assertion.ForCondition(Result.ExitCode != 0)
.FailWith("Expected command to fail but it did not.{0}", GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> HaveStdOut()
{
- Execute.Assertion.ForCondition(!string.IsNullOrEmpty(_commandResult.StdOut))
+ Execute.Assertion.ForCondition(!string.IsNullOrEmpty(Result.StdOut))
.FailWith("Command did not output anything to stdout{0}", GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> HaveStdOut(string expectedOutput)
{
- Execute.Assertion.ForCondition(_commandResult.StdOut.Equals(expectedOutput, StringComparison.Ordinal))
+ Execute.Assertion.ForCondition(Result.StdOut.Equals(expectedOutput, StringComparison.Ordinal))
.FailWith("Command did not output with Expected Output. Expected: {0}{1}", expectedOutput, GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> HaveStdOutContaining(string pattern)
{
- Execute.Assertion.ForCondition(_commandResult.StdOut.Contains(pattern))
+ Execute.Assertion.ForCondition(Result.StdOut.Contains(pattern))
.FailWith("The command output did not contain expected result: {0}{1}", pattern, GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> NotHaveStdOutContaining(string pattern)
{
- Execute.Assertion.ForCondition(!_commandResult.StdOut.Contains(pattern))
+ Execute.Assertion.ForCondition(!Result.StdOut.Contains(pattern))
.FailWith("The command output contained a result it should not have contained: {0}{1}", pattern, GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> HaveStdOutMatching(string pattern, RegexOptions options = RegexOptions.None)
{
- Execute.Assertion.ForCondition(Regex.Match(_commandResult.StdOut, pattern, options).Success)
+ Execute.Assertion.ForCondition(Regex.Match(Result.StdOut, pattern, options).Success)
.FailWith("Matching the command output failed. Pattern: {0}{1}", pattern, GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> HaveStdErr()
{
- Execute.Assertion.ForCondition(!string.IsNullOrEmpty(_commandResult.StdErr))
+ Execute.Assertion.ForCondition(!string.IsNullOrEmpty(Result.StdErr))
.FailWith("Command did not output anything to stderr.{0}", GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> HaveStdErrContaining(string pattern)
{
- Execute.Assertion.ForCondition(_commandResult.StdErr.Contains(pattern))
+ Execute.Assertion.ForCondition(Result.StdErr.Contains(pattern))
.FailWith("The command error output did not contain expected result: {0}{1}", pattern, GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> NotHaveStdErrContaining(string pattern)
{
- Execute.Assertion.ForCondition(!_commandResult.StdErr.Contains(pattern))
+ Execute.Assertion.ForCondition(!Result.StdErr.Contains(pattern))
.FailWith("The command error output contained a result it should not have contained: {0}{1}", pattern, GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> HaveStdErrMatching(string pattern, RegexOptions options = RegexOptions.None)
{
- Execute.Assertion.ForCondition(Regex.Match(_commandResult.StdErr, pattern, options).Success)
+ Execute.Assertion.ForCondition(Regex.Match(Result.StdErr, pattern, options).Success)
.FailWith("Matching the command error output failed. Pattern: {0}{1}", pattern, GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> NotHaveStdOut()
{
- Execute.Assertion.ForCondition(string.IsNullOrEmpty(_commandResult.StdOut))
+ Execute.Assertion.ForCondition(string.IsNullOrEmpty(Result.StdOut))
.FailWith("Expected command to not output to stdout but it was not:{0}", GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> NotHaveStdErr()
{
- Execute.Assertion.ForCondition(string.IsNullOrEmpty(_commandResult.StdErr))
+ Execute.Assertion.ForCondition(string.IsNullOrEmpty(Result.StdErr))
.FailWith("Expected command to not output to stderr but it was not:{0}", GetDiagnosticsInfo());
return new AndConstraint<CommandResultAssertions>(this);
}
return new AndConstraint<CommandResultAssertions>(this);
}
- private string GetDiagnosticsInfo()
+ public string GetDiagnosticsInfo()
{
return $"{Environment.NewLine}" +
- $"File Name: {_commandResult.StartInfo.FileName}{Environment.NewLine}" +
- $"Arguments: {_commandResult.StartInfo.Arguments}{Environment.NewLine}" +
- $"Exit Code: {_commandResult.ExitCode}{Environment.NewLine}" +
- $"StdOut:{Environment.NewLine}{_commandResult.StdOut}{Environment.NewLine}" +
- $"StdErr:{Environment.NewLine}{_commandResult.StdErr}{Environment.NewLine}"; ;
+ $"File Name: {Result.StartInfo.FileName}{Environment.NewLine}" +
+ $"Arguments: {Result.StartInfo.Arguments}{Environment.NewLine}" +
+ $"Exit Code: {Result.ExitCode}{Environment.NewLine}" +
+ $"StdOut:{Environment.NewLine}{Result.StdOut}{Environment.NewLine}" +
+ $"StdErr:{Environment.NewLine}{Result.StdErr}{Environment.NewLine}"; ;
}
public AndConstraint<CommandResultAssertions> HaveSkippedProjectCompilation(string skippedProject, string frameworkFullName)
{
- _commandResult.StdOut.Should().Contain("Project {0} ({1}) was previously compiled. Skipping compilation.", skippedProject, frameworkFullName);
+ Result.StdOut.Should().Contain("Project {0} ({1}) was previously compiled. Skipping compilation.", skippedProject, frameworkFullName);
return new AndConstraint<CommandResultAssertions>(this);
}
public AndConstraint<CommandResultAssertions> HaveCompiledProject(string compiledProject, string frameworkFullName)
{
- _commandResult.StdOut.Should().Contain($"Project {0} ({1}) will be compiled", compiledProject, frameworkFullName);
+ Result.StdOut.Should().Contain($"Project {0} ({1}) will be compiled", compiledProject, frameworkFullName);
return new AndConstraint<CommandResultAssertions>(this);
}
}
}
}
+
+ public static void EnsureFileDirectoryExists(string filePath)
+ {
+ string directory = Path.GetDirectoryName(filePath);
+ if (!Directory.Exists(directory))
+ {
+ Directory.CreateDirectory(directory);
+ }
+ }
+
+ public static void CreateEmptyFile(string filePath)
+ {
+ EnsureFileDirectoryExists(filePath);
+ File.WriteAllText(filePath, string.Empty);
+ }
}
}